java编程_socket_套接字_网络编程

来源:互联网 发布:java奇数偶数的和 编辑:程序博客网 时间:2024/06/07 19:55

============================================================ 

                                          1.实现server和client模型程序

============================================================ 

实现原理:

============================================================ 

服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,

在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),

等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。  

============================================================ 
客户端,使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,

关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。

============================================================ 

服务器端代码:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.basic.socket.server;  
  2.   
  3. import java.io.DataOutputStream;  
  4. import java.io.IOException;  
  5. import java.io.OutputStream;  
  6. import java.net.ServerSocket;  
  7. import java.net.Socket;  
  8. /**  
  9.  * 服务器断的工作就是在指定的端口上监听  
  10.  * 1、建立连接  
  11.  * 2、打开输出流  
  12.  * 3、封装输出流  
  13.  * 4、向客户端发送数据  
  14.  * 5、关闭打开的输出流  
  15.  * 6、关闭打开的socket对象  
  16.  *   
  17.  * @author HP  
  18.  *   
  19.  * @time 2013-12-07  
  20.  *   
  21.  * @version 1.0  
  22.  */  
  23. public class Chat_Server {  
  24.     public static void main(String[] args) {  
  25.         try {  
  26.             // 指定服务器端的端口号为8888  
  27.             ServerSocket s=new ServerSocket(8888);  
  28.             while(true){  
  29.                 //建立连接  
  30.                 Socket socket=s.accept();  
  31.                 //打开输出流  
  32.                 OutputStream os=socket.getOutputStream();  
  33.                 //封装输出流  
  34.                 DataOutputStream dos=new DataOutputStream(os);  
  35.                 //s.getInetAddress()获取远程ip地址,s.getPort()远程客户端的断后好  
  36.                 //向客户端发送数据  
  37.                 dos.writeUTF("你好,客服端地址信息:"+socket.getInetAddress()+"\t客服端通讯端口号:"+socket.getPort());  
  38.                 dos.writeUTF("i'm a server ,my name is Mercury!");  
  39.                 //关闭打开的输出流  
  40.                 dos.close();  
  41.                 //关闭打开的socket对象  
  42.                 socket.close();  
  43.             } //开始下一次循环  
  44.         } catch (IOException e) {  
  45.             e.printStackTrace();  
  46.         }  
  47.     }  
  48. }  
客户端代码:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.basic.socket.client;  
  2.   
  3. import java.io.DataInputStream;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.net.Socket;  
  7. /**  
  8.  * 1、创建socket对象,指定服务器的ip地址,和服务器监听的端口号  
  9.  * 2、打开输入流  
  10.  * 3、封装输入流  
  11.  * 4、打印服务器端发送过来的信息  
  12.  * 5、关闭输入流  
  13.  * 6、关闭打开的socket对象  
  14.  *   
  15.  * 客服端  
  16.  *   
  17.  * @author HP  
  18.  *  
  19.  * @time 2013-12-07  
  20.  *   
  21.  * @version 1.0  
  22.  */  
  23. public class Chat_Client {  
  24.     public static void main(String[] args) {  
  25.         try {  
  26.             // 创建socket对象,指定服务器的ip地址,和服务器监听的端口号  
  27.             // 客户端在new的时候,就发出了连接请求,服务器端就会进行处理,如果服务器端没有开启服务,那么  
  28.             // 这时候就会找不到服务器,并同时抛出异常==》java.net.ConnectException: Connection  
  29.             // refused: connect  
  30.             Socket socket=new Socket("127.0.0.1",8888);  
  31.             // 打开输入流  
  32.             InputStream is=socket.getInputStream();  
  33.              // 封装输入流  
  34.             DataInputStream dis=new DataInputStream(is);  
  35.             // 打印服务器端发送过来的信息  
  36.             System.out.println(dis.readUTF());  
  37.             System.out.println(dis.readUTF());  
  38.             // 关闭输入流  
  39.             dis.close();  
  40.             // 关闭打开的socket对象  
  41.             socket.close();  
  42.         } catch (IOException e) {  
  43.             e.printStackTrace();  
  44.         }  
  45.     }  
  46. }  

如果服务器端没有打开,这时候运行客户端,出现的结果:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. java.net.ConnectException: Connection refused: connect  
  2.     at java.net.PlainSocketImpl.socketConnect(Native Method)  
  3.     at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)  
  4.     at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)  
  5.     at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)  
  6.     at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)  
  7.     at java.net.Socket.connect(Socket.java:518)  
  8.     at java.net.Socket.connect(Socket.java:468)  
  9.     at java.net.Socket.<init>(Socket.java:365)  
  10.     at java.net.Socket.<init>(Socket.java:179)  
  11.     at com.b510.socket1703.TestClient.main(TestClient.java:19)  
如果服务器端先打开服务,这时候客户端连接服务器端,出现的效果:
1 你好,客户端地址信息: /127.0.0.1    客户端通信端口号: 197122 i'm a server ,my name is Mercury!

============================================================ 

                                              2.实现单线程的聊天室

============================================================ 

服务器端代码:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.basic.socket.server;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.DataInputStream;  
  5. import java.io.DataOutputStream;  
  6. import java.io.IOException;  
  7. import java.io.InputStream;  
  8. import java.io.InputStreamReader;  
  9. import java.io.OutputStream;  
  10. import java.net.ServerSocket;  
  11. import java.net.Socket;  
  12. import java.net.SocketException;  
  13. /**  
  14.  * 服务器断的工作就是在指定的端口上监听  
  15.  * 1、建立连接  
  16.  * 2、打开输出流  
  17.  * 3、封装输出流  
  18.  * 4、向客户端发送数据  
  19.  * 5、关闭打开的输出流  
  20.  * 6、关闭打开的socket对象  
  21.  *   
  22.  * @author HP  
  23.  *   
  24.  * @time 2013-12-07  
  25.  *   
  26.  * @version 1.0  
  27.  */  
  28. public class Chat_Server_Simple {  
  29.     public static void main(String[] args) {  
  30.         try {  
  31.             // 指定服务器端的端口号为8888  
  32.             ServerSocket s=new ServerSocket(8888);  
  33.             //建立连接  
  34.             Socket socket=s.accept();  
  35.             //打开输出流  
  36.             OutputStream os=socket.getOutputStream();  
  37.             //封装输出流  
  38.             DataOutputStream dos=new DataOutputStream(os);  
  39.             //打开输入流  
  40.             InputStream is=socket.getInputStream();  
  41.             //封装输入流  
  42.             DataInputStream dis=new DataInputStream(is);  
  43.             //读取键盘输入流  
  44.             InputStreamReader isr=new InputStreamReader(System.in);  
  45.             //封装键盘输入流  
  46.             BufferedReader br=new BufferedReader(isr);  
  47.               
  48.             String info;  
  49.             while(true){  
  50.                 //接受客户端发送过来的信息  
  51.                 info=dis.readUTF();  
  52.                 //打印接受的信息  
  53.                 System.out.println("对方说: " + info);  
  54.                 //如果发现接受的信息为:bye,那么就结束对话  
  55.                 if(info.equals("bye"))  
  56.                     break;  
  57.                     //读取键盘的输入流  
  58.                     info=br.readLine();  
  59.                     //写入到网络连接的另一边,即客户端  
  60.                     dos.writeUTF(info);  
  61.                     //如果服务器自己说:bye,也是结束对话  
  62.                     if(info.equals("bye"))  
  63.                         break;  
  64.             } //开始下一次循环  
  65.               
  66.             //关闭打开的输入流  
  67.             dis.close();  
  68.             //关闭打开的输出流  
  69.             dos.close();  
  70.             //关闭打开的socket对象  
  71.             socket.close();  
  72.             s.close();  
  73.               
  74.         } catch (SocketException e) {  
  75.             System.out.println("网络连接异常,程序退出!");  
  76.         }catch (IOException e) {  
  77.             e.printStackTrace();  
  78.         }  
  79.     }  
  80. }  

客户端代码:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.basic.socket.client;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.DataInputStream;  
  5. import java.io.DataOutputStream;  
  6. import java.io.IOException;  
  7. import java.io.InputStream;  
  8. import java.io.InputStreamReader;  
  9. import java.io.OutputStream;  
  10. import java.net.Socket;  
  11. /**  
  12.  * 1、创建socket对象,指定服务器的ip地址,和服务器监听的端口号  
  13.  * 2、打开输入流  
  14.  * 3、封装输入流  
  15.  * 4、打印服务器端发送过来的信息  
  16.  * 5、关闭输入流  
  17.  * 6、关闭打开的socket对象  
  18.  *   
  19.  * 客服端  
  20.  *   
  21.  * @author HP  
  22.  *  
  23.  * @time 2013-12-07  
  24.  *   
  25.  * @version 1.0  
  26.  */  
  27. public class Chat_Client_Simple {  
  28.     public static void main(String[] args) {  
  29.         try {  
  30.             // 创建socket对象,指定服务器的ip地址,和服务器监听的端口号  
  31.             // 客户端在new的时候,就发出了连接请求,服务器端就会进行处理,如果服务器端没有开启服务,那么  
  32.             // 这时候就会找不到服务器,并同时抛出异常==》java.net.ConnectException: Connection  
  33.             // refused: connect  
  34.             Socket socket=new Socket("localhost",8888);  
  35.             //打开输出流  
  36.             OutputStream os=socket.getOutputStream();  
  37.             //封装输出流  
  38.             DataOutputStream dos=new DataOutputStream(os);  
  39.             // 打开输入流  
  40.             InputStream is=socket.getInputStream();  
  41.             // 封装输入流  
  42.             DataInputStream dis=new DataInputStream(is);  
  43.             //读取键盘输入流  
  44.             InputStreamReader isr=new InputStreamReader(System.in);  
  45.             //封装键盘输入流  
  46.             BufferedReader br=new BufferedReader(isr);  
  47.   
  48.             String info;  
  49.             while(true){  
  50.                 //客户端先读取键盘输入信息  
  51.                 info = br.readLine();  
  52.                 //把他写入到服务器方  
  53.                 dos.writeUTF(info);  
  54.                 //如果客户端自己说:bye,即结束对话  
  55.                 if(info.equals("bye"))  
  56.                     break;  
  57.                     //接受服务器端信息  
  58.                     info = dis.readUTF();  
  59.                     //打印  
  60.                     System.out.println("对方说: " + info);  
  61.                     //如果服务器自己说:bye,也是结束对话  
  62.                     if(info.equals("bye"))  
  63.                         break;  
  64.             }  
  65.             //关闭相应的输入流,输出流,socket对象  
  66.             dis.close();  
  67.             dos.close();  
  68.             // 关闭打开的socket对象  
  69.             socket.close();  
  70.         } catch (IOException e) {  
  71.             e.printStackTrace();  
  72.         }  
  73.     }  
  74. }  

运行效果:

服务器端效果>>>

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 对方说: hell  
  2. 你好  
  3. 对方说: 嘿嘿  
  4. 你今天  
  5. 对方说: 13  
  6. 代售点  
客户端端效果>>>
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. hell  
  2. 对方说: 你好  
  3. 嘿嘿  
  4. 对方说: 你今天?  
  5. 13  
  6. 对方说: 代售点?  

当前的程序不管是服务器端,还是客户端,都是单线程的。如: 服务器端说:"你好"

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 1 //读取键盘的输入流  
  2. info = br.readLine();  
  3. 3 //写入到网络连接的另一边,即客户端  
  4. 4 dos.writeUTF(info);  
  5. 5 //如果服务器自己说:bye,也是结束对话  

通过上面的代码,把"你好"发送出去了,这时候,程序又开始循环,运行到:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 1 //接受客户端发送过来的信息  
  2. info = dis.readUTF();  

这段代码,其实在这里就阻塞在这里了。要等到客户端那边说了话,"嘿嘿",这时候这里的
阻塞才会变为非阻塞状态,然后又继续说,说完后又继续阻塞......

而对于客户端来说,其实是一样的道理,客户端说完"hello"后,进入:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 1 //接受服务器端信息  
  2. info = dis.readUTF();  

到收听服务器端的信息,在这里也产生了阻塞,只有服务器端说了"你好",这个阻塞才变为非阻塞
状态。然后又继续接下来的动作....

============================================================ 

                                              3.实现多线程的聊天室

============================================================ 

服务器端代码:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.basic.socket.server;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.DataInputStream;  
  5. import java.io.DataOutputStream;  
  6. import java.io.IOException;  
  7. import java.io.InputStream;  
  8. import java.io.InputStreamReader;  
  9. import java.io.OutputStream;  
  10. import java.net.ServerSocket;  
  11. import java.net.Socket;  
  12.   
  13. public class Test_Chat_Server {  
  14.     public static void main(String args[]) {  
  15.         try {  
  16.             // 创建一个socket对象  
  17.             ServerSocket s = new ServerSocket(8888);  
  18.             // socket对象调用accept方法,等待连接请求  
  19.             Socket s1 = s.accept();  
  20.   
  21.             // =========服务器端,在这里应该先打开输出流,在打开输入流,  
  22.             // =========因为服务器端执行的操作是先听,再说,听,说,听,说.....  
  23.   
  24.             // 打开输出流  
  25.             OutputStream os = s1.getOutputStream();  
  26.             // 封装输出流  
  27.             DataOutputStream dos = new DataOutputStream(os);  
  28.             // 打开输入流  
  29.             InputStream is = s1.getInputStream();  
  30.             // 封装输入流  
  31.             DataInputStream dis = new DataInputStream(is);  
  32.             // 创建并启用两个线程  
  33.             new MyServerReader(dis).start();  
  34.             new MyServerWriter(dos).start();  
  35.         } catch (IOException e) {  
  36.             e.printStackTrace();  
  37.         }  
  38.     }  
  39. }  
  40.   
  41. // 接受并打印客户端传过来的信息  
  42. class MyServerReader extends Thread {  
  43.     private DataInputStream dis;  
  44.   
  45.     public MyServerReader(DataInputStream dis) {  
  46.         this.dis = dis;  
  47.     }  
  48.   
  49.     public void run() {  
  50.         String info;  
  51.         try {  
  52.             while (true) {  
  53.                 // 如果对方,即客户端没有说话,那么就会阻塞到这里,  
  54.                 // 这里的阻塞并不会影响到其他线程  
  55.                 info = dis.readUTF();  
  56.                 // 如果状态有阻塞变为非阻塞,那么就打印接受到的信息  
  57.                 System.out.println("对方说: " + info);  
  58.                 if (info.equals("bye")) {  
  59.                     System.out.println("对方下线,程序退出!");  
  60.                     System.exit(0);  
  61.                 }  
  62.             }  
  63.         } catch (IOException e) {  
  64.             e.printStackTrace();  
  65.         }  
  66.     }  
  67. }  
  68.   
  69. // 从键盘获得输入流并写入信息到客户端  
  70. class MyServerWriter extends Thread {  
  71.     private DataOutputStream dos;  
  72.   
  73.     public MyServerWriter(DataOutputStream dos) {  
  74.         this.dos = dos;  
  75.     }  
  76.   
  77.     public void run() {  
  78.         // 读取键盘输入流  
  79.         InputStreamReader isr = new InputStreamReader(System.in);  
  80.         // 封装键盘输入流  
  81.         BufferedReader br = new BufferedReader(isr);  
  82.         String info;  
  83.         try {  
  84.             while (true) {  
  85.                 info = br.readLine();  
  86.                 dos.writeUTF(info);  
  87.                 if (info.equals("bye")) {  
  88.                     System.out.println("自己下线,程序退出!");  
  89.                     System.exit(0);  
  90.                 }  
  91.             }  
  92.         } catch (IOException e) {  
  93.             e.printStackTrace();  
  94.         }  
  95.     }  
  96. }  

客户端代码:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.basic.socket.client;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.DataInputStream;  
  5. import java.io.DataOutputStream;  
  6. import java.io.IOException;  
  7. import java.io.InputStream;  
  8. import java.io.InputStreamReader;  
  9. import java.io.OutputStream;  
  10. import java.net.Socket;  
  11.   
  12. public class Test_Chat_Client {  
  13.     public static void main(String args[]) {  
  14.         try {  
  15.             // 创建socket对象,指定服务器的ip地址,和服务器监听的端口号  
  16.             // 客户端在new的时候,就发出了连接请求,服务器端就会进行处理,如果服务器端没有开启服务,那么  
  17.             // 这时候就会找不到服务器,并同时抛出异常==》java.net.ConnectException: Connection  
  18.             // refused: connect  
  19.             Socket s1 = new Socket("127.0.0.1", 8888);  
  20.   
  21.             // =========客户端,在这里应该先打开输入流,在打开输出流,  
  22.             // =========因为客户端执行的操作是先说,再听,说,听,说,听.....  
  23.   
  24.             // 打开输入流  
  25.             InputStream is = s1.getInputStream();  
  26.             // 封装输入流  
  27.             DataInputStream dis = new DataInputStream(is);  
  28.             // 打开输出流  
  29.             OutputStream os = s1.getOutputStream();  
  30.             // 封装输出流  
  31.             DataOutputStream dos = new DataOutputStream(os);  
  32.   
  33.             // 创建并启用两个线程  
  34.             new MyClientReader(dis).start();  
  35.             new MyClientWriter(dos).start();  
  36.         } catch (IOException e) {  
  37.             e.printStackTrace();  
  38.         }  
  39.     }  
  40. }  
  41.   
  42. // 接受并打印服务器端传过来的信息  
  43. class MyClientReader extends Thread {  
  44.     private DataInputStream dis;  
  45.   
  46.     public MyClientReader(DataInputStream dis) {  
  47.         this.dis = dis;  
  48.     }  
  49.   
  50.     public void run() {  
  51.         String info;  
  52.         try {  
  53.             while (true) {  
  54.                 info = dis.readUTF();  
  55.                 System.out.println("对方说: " + info);  
  56.                 if (info.equals("bye")) {  
  57.                     System.out.println("对方下线,程序退出!");  
  58.                     System.exit(0);  
  59.                 }  
  60.             }  
  61.         } catch (IOException e) {  
  62.             e.printStackTrace();  
  63.         }  
  64.     }  
  65. }  
  66.   
  67. // 从键盘获得输入流并写入信息到服务器端  
  68. class MyClientWriter extends Thread {  
  69.     private DataOutputStream dos;  
  70.   
  71.     public MyClientWriter(DataOutputStream dos) {  
  72.         this.dos = dos;  
  73.     }  
  74.   
  75.     public void run() {  
  76.         InputStreamReader isr = new InputStreamReader(System.in);  
  77.         BufferedReader br = new BufferedReader(isr);  
  78.         String info;  
  79.         try {  
  80.             while (true) {  
  81.                 info = br.readLine();  
  82.                 dos.writeUTF(info);  
  83.                 if (info.equals("bye")) {  
  84.                     System.out.println("自己下线,程序退出!");  
  85.                     System.exit(0);  
  86.                 }  
  87.             }  
  88.         } catch (IOException e) {  
  89.             e.printStackTrace();  
  90.         }  
  91.     }  
  92. }  

客户端运行效果:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 1 这是客户端  
  2. 2 我是hongten  
  3. 3 这是我说的第三句话,haha  
  4. 4 对方说: 我是服务器端,这说我说的第一句话,hehe  

服务器端运行效果:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 1 对方说: 这是客户端?  
  2. 2 对方说: 我是hongten  
  3. 3 对方说: 这是我说的第三句话,haha  
  4. 4 我是服务器端,这说我说的第一句话,hehe  
0 0