前面一片学习了TCP/IP的基础网络编程,并给出了简单的服务端与客户端通信交互的例子。还介绍了UPC的通信例子。

这次学习TCP/IP的多线程编程。因为涉及到TCP/IP一般都是多线程,服务端会一直监听端口,多个客户端发来信息,收到某个客户端发来的数据后,如果所有处理都放在服务端,这样程序就会显得很臃肿。就需要单独启动一个线程去执行,来一个客户端就启动一个对应的程序。

下面给出具体例子:Java 多线程实现Socket通信

  1 package lesson1220Socket;
  2 
  3 import java.net.ServerSocket;
  4 import java.net.Socket;
  5 
  6 public class SeverTCPDemo {
  7     
  8     private static ServerSocket ss; //定义成static类型是有原因的,因为ss不能进行close.
  9 
 10     public static void main(String[] args) throws Exception {
 11         ss = new ServerSocket(9999);
 12         Socket socket = null;
 13         int num = 0;
 14         System.out.println("******服务器已启动,等待客户端连接*****");
 15         
 16         while(true){
 17             socket = ss.accept();
 18             num++;
 19             new SocketThread(socket,num).start();            
 20         }
 21     }
 22 }
 23 
 24 package lesson1220Socket;
 25 
 26 import java.io.BufferedReader;
 27 import java.io.IOException;
 28 import java.io.InputStream;
 29 import java.io.InputStreamReader;
 30 import java.io.OutputStream;
 31 import java.io.PrintWriter;
 32 import java.net.Socket;
 33 
 34 public class SocketThread extends Thread {
 35     
 36     Socket socket;
 37     private int num;    
 38 
 39     public SocketThread(Socket socket, int num) {
 40         super();
 41         this.socket = socket;
 42         this.num = num;
 43     }
 44 
 45     /* (non-Javadoc)
 46      * @see java.lang.Thread#run()
 47      */
 48     @Override
 49     public void run() {
 50         
 51         InputStream is = null;
 52         BufferedReader br = null;
 53         OutputStream os = null;
 54         PrintWriter pw = null;
 55         try {
 56             is = socket.getInputStream();
 57             br = new BufferedReader(new InputStreamReader(is));
 58             String info = null;
 59             while((info=br.readLine())!=null){
 60                 System.out.println("客户端发来消息:" + info);                
 61             }
 62             socket.shutdownInput();    
 63             
 64             os = socket.getOutputStream();
 65             pw= new PrintWriter(os);            
 66             pw.write("hello, I am Server! you are " + num + " Client!");
 67             pw.flush();
 68             socket.shutdownOutput();
 69             
 70         } catch (IOException e) {
 71             e.printStackTrace();
 72         }finally{
 73             try {
 74                 is.close();
 75             } catch (IOException e) {
 76                 e.printStackTrace();
 77             }
 78             try {
 79                 br.close();
 80             } catch (IOException e) {
 81                 e.printStackTrace();
 82             }
 83             try {
 84                 os.close();
 85             } catch (IOException e) {
 86                 e.printStackTrace();
 87             }
 88             pw.close();
 89         }
 90     }
 91 }
 92 
 93 package lesson1220Socket;
 94 
 95 import java.io.BufferedReader;
 96 import java.io.IOException;
 97 import java.io.InputStream;
 98 import java.io.InputStreamReader;
 99 import java.io.OutputStream;
100 import java.io.PrintWriter;
101 import java.net.Socket;
102 import java.net.UnknownHostException;
103 
104 public class ClientTCPDemo {
105 
106     public static void main(String[] args){
107 
108             Socket socket = null;
109             OutputStream os = null;
110             PrintWriter pw = null;
111             InputStream is = null;
112             BufferedReader br = null;
113             
114             try {
115                 socket = new Socket("127.0.0.1", 9999);
116                 os = socket.getOutputStream();
117                 pw = new PrintWriter(os);                
118                 pw.write("hello, server! I am client!");
119                 pw.flush();
120                 
121                 socket.shutdownOutput();
122                 
123                 is = socket.getInputStream();
124                 br = new BufferedReader(new InputStreamReader(is));
125                 String info = null;
126                 while((info=br.readLine())!=null){
127                     System.out.println("服务端返回信息:" + info);                
128                 }
129                 
130                 socket.shutdownInput();                
131             
132             } catch (UnknownHostException e) {
133                 e.printStackTrace();
134             } catch (IOException e) {
135                 e.printStackTrace();
136             }finally{
137                 try {
138                     os.close();
139                 } catch (IOException e1) {
140                     e1.printStackTrace();
141                 }
142                 pw.close();
143                 try {
144                     is.close();
145                 } catch (IOException e) {
146                     e.printStackTrace();
147                 }
148                 try {
149                     br.close();
150                 } catch (IOException e) {
151                     e.printStackTrace();
152                 }
153                 try {
154                     socket.close();
155                 } catch (IOException e) {
156                     e.printStackTrace();
157                 }                
158             }    
159     }
160 
161 }

运行结果:分别启动三个客户端:

******服务器已启动,等待客户端连接*****
客户端发来消息:hello, server! I am client!
客户端发来消息:hello, server! I am client!
客户端发来消息:hello, server! I am client!

客户端:

服务端返回信息:hello, I am Server! you are 1 Client!

服务端返回信息:hello, I am Server! you are 2 Client!

服务端返回信息:hello, I am Server! you are 3 Client!

Note:一定要等程序都运行完后,才可以关闭相关资源例如:os,is,pw等。

 

上面的例子通信一次就关闭了,下面再给出几个TCP/IP通信例子,两边可以交互通信:

例子1:两边通信,按顺序一发一收。客户端和服务器都有收发功能,并且收发有相应的顺序,都对应相应的阻塞:缓冲区br.readLine(), 键盘输入sc.nextLine()。

  1 package lesson1220Socket;
  2 
  3 import java.io.BufferedReader;
  4 import java.io.IOException;
  5 import java.io.InputStream;
  6 import java.io.InputStreamReader;
  7 import java.io.OutputStream;
  8 import java.io.OutputStreamWriter;
  9 import java.io.PrintWriter;
 10 import java.net.ServerSocket;
 11 import java.net.Socket;
 12 import java.util.Scanner;
 13 
 14 public class ChatServer {
 15     public static ServerSocket ss;
 16     
 17     public ChatServer() {
 18         try {
 19             ss = new ServerSocket(8888);
 20         } catch (IOException e) {
 21             e.printStackTrace();
 22         }
 23     }
 24     
 25     public void start(){
 26         Socket socket = null;
 27         InputStream is = null;
 28         InputStreamReader isr = null;
 29         BufferedReader br = null;
 30         OutputStream os = null;
 31         PrintWriter pw = null;
 32         
 33         try {
 34             System.out.println("服务端启动。。。。。。");            
 35             socket = ss.accept();
 36             
 37             is = socket.getInputStream();
 38             isr = new InputStreamReader(is);
 39             br = new BufferedReader(isr);
 40             
 41             os = socket.getOutputStream();
 42             //pw = new PrintWriter(os);    //很奇怪,这个地方要这么写,要不然数据发不出去?        
 43             OutputStreamWriter osw = new OutputStreamWriter(os);
 44             pw = new PrintWriter(osw, true);//解释上一行,要输入参数true,会自动刷新flush()
 45             
 46             Scanner sc = new Scanner(System.in);
 47             //也可以通过下面code来获取系统输入
 48             //BufferedReader br2 = new BufferedReader(new InputStreamReader(System.in));
 49             //br2.readLine();
 50             
 51             String info;
 52             
 53             while(true){                
 54                 
 55                 System.out.println("收到客户端消息: " + br.readLine());
 56                 pw.println(info = sc.nextLine());  
 57                 //pw.println(info = br2.readLine());
 58                 if("bye".equals(info)){
 59                     System.out.println("byebye!");
 60                     break;
 61                 }
 62             }        
 63             
 64         } catch (IOException e) {
 65             e.printStackTrace();
 66         }
 67     }
 68     
 69     public static void main(String[] args) {
 70         new ChatServer().start();        
 71     }
 72 }
 73 
 74 package lesson1220Socket;
 75 
 76 import java.io.BufferedReader;
 77 import java.io.IOException;
 78 import java.io.InputStream;
 79 import java.io.InputStreamReader;
 80 import java.io.OutputStream;
 81 import java.io.PrintWriter;
 82 import java.net.Socket;
 83 import java.util.Scanner;
 84 
 85 public class ChatClient {
 86     
 87     Socket socket ;
 88     
 89     public ChatClient() {
 90         try {
 91             this.socket = new Socket("127.0.0.1", 8888);
 92         } catch (IOException e) {
 93             e.printStackTrace();
 94         }        
 95     }
 96     
 97     public void start(){
 98         
 99         InputStream is = null;
100         InputStreamReader isr = null;
101         BufferedReader br = null;
102         OutputStream os = null;
103         PrintWriter pw = null;
104         try {
105             is = socket.getInputStream();
106             isr = new InputStreamReader(is);
107             br = new BufferedReader(isr);            
108             os = socket.getOutputStream();
109             pw = new PrintWriter(os,true);  //true代表 每写一行自动刷新
110 
111             Scanner sc = new Scanner(System.in);
112             //BufferedReader br2 = new BufferedReader(new InputStreamReader(System.in));
113             //br2.readLine();
114             
115             String info;
116             while(true){                
117                 pw.println(info = sc.nextLine());                
118                 //pw.write(info = sc.nextLine()+"\r\n");                
119                 //pw.flush();
120                 //详细讲解可以看帖子:https://www.cnblogs.com/wxgblogs/p/5347996.html
121                 System.out.println("收到服务端回应消息:" + br.readLine());
122                 
123                 if("bye".equals(info)){
124                     System.out.println("byebye!");
125                     break;
126                 }
127             }        
128             
129         } catch (IOException e) {
130             e.printStackTrace();
131         }
132         
133     }
134     
135     public static void main(String[] args) {
136         new ChatClient().start();        
137     }
138 
139 }

必须按顺序进行收发,不能同时进行。

要想收发同时进行,收发就不能再同一个线程内,就应该有两个线程,一个负责发,一个负责收。

 

例子2:通过将收发单独分开,用线程实现。两边可以任意发送。

  1 package lesson1220Socket;
  2 
  3 import java.io.IOException;
  4 import java.net.ServerSocket;
  5 import java.net.Socket;
  6 
  7 public class ChatServer2 {
  8     
  9 
 10     public static ServerSocket ss;
 11     private Socket socket;
 12     
 13     public ChatServer2() {
 14         try {
 15             ss = new ServerSocket(8888);
 16             socket = ss.accept();
 17         } catch (IOException e) {
 18             e.printStackTrace();
 19         }
 20     }
 21     
 22     public void start(){
 23         
 24         Thread st = new Thread(new SendThread(socket));
 25         st.start();
 26         Thread rv = new Thread(new ReceiveThread(socket));
 27         rv.start();    
 28         
 29     }
 30     
 31     public static void main(String[] args) {        
 32         new ChatServer2().start();        
 33     }
 34 
 35 }
 36 
 37 package lesson1220Socket;
 38 
 39 import java.io.IOException;
 40 import java.net.Socket;
 41 
 42 
 43 public class ChatClient2 {
 44     Socket socket ;
 45     
 46     public ChatClient2() {
 47         try {
 48             this.socket = new Socket("127.0.0.1", 8888);
 49         } catch (IOException e) {
 50             e.printStackTrace();
 51         }        
 52     }
 53     
 54     public void start(){
 55         
 56         Thread st = new Thread(new SendThread(socket));
 57         st.start();
 58         Thread rv = new Thread(new ReceiveThread(socket));
 59         rv.start();    
 60         
 61     }    
 62         
 63     public static void main(String[] args) {
 64         new ChatClient2().start();        
 65     }
 66 
 67 }
 68 
 69 package lesson1220Socket;
 70 
 71 import java.io.IOException;
 72 import java.io.OutputStream;
 73 import java.io.PrintWriter;
 74 import java.net.Socket;
 75 import java.util.Scanner;
 76 
 77 public class SendThread implements Runnable {
 78     
 79     private Socket socket;
 80     public SendThread(Socket socket) {
 81         this.socket = socket;
 82     }
 83 
 84     @Override
 85     public void run() {
 86         
 87         OutputStream os = null;
 88         PrintWriter pw = null;
 89         
 90         try {
 91             os = socket.getOutputStream();
 92             pw = new PrintWriter(os, true);            
 93             Scanner sc = new Scanner(System.in);
 94             
 95             while(true){    
 96                 pw.println(sc.nextLine()); 
 97             }        
 98         } catch (IOException e) {
 99             e.printStackTrace();
100         }        
101     }
102 }
103 
104 package lesson1220Socket;
105 
106 import java.io.BufferedReader;
107 import java.io.IOException;
108 import java.io.InputStream;
109 import java.io.InputStreamReader;
110 import java.net.Socket;
111 
112 public class ReceiveThread implements Runnable {
113     
114     Socket socket;
115     public ReceiveThread(Socket socket) {
116         this.socket = socket;
117     }
118 
119     @Override
120     public void run() {
121 
122         InputStream is = null;
123         InputStreamReader isr = null;
124         BufferedReader br = null;
125         
126         try {
127             is = socket.getInputStream();
128             isr = new InputStreamReader(is);
129             br = new BufferedReader(isr);
130             
131             while(true){    
132                 System.out.println("收到消息:" + br.readLine());
133             }        
134             
135         } catch (IOException e) {
136             e.printStackTrace();
137         }    
138     }
139 }

服务端和客户端共用收发线程,只要两边Socket连接建立完成,所有的工作都是在收发线程完成。

下面考虑多发通信问题。

 

例子3:一对多通信。 多个客户端同时给服务端发消息,然后服务端回消息,这个回的是群发消息。

  1 package lesson1220Socket;
  2 
  3 import java.io.IOException;
  4 import java.io.OutputStream;
  5 import java.io.PrintWriter;
  6 import java.net.ServerSocket;
  7 import java.net.Socket;
  8 import java.util.ArrayList;
  9 import java.util.Scanner;
 10 
 11 public class ChatServer3 {
 12     
 13     public static ServerSocket ss;
 14     Socket cs;
 15     ArrayList<Socket> list = new ArrayList<Socket>();
 16     private boolean isGroup = true;
 17     private Scanner input = new Scanner(System.in);
 18     
 19     public ChatServer3() {
 20         
 21         try {
 22             ss = new ServerSocket(7777);            
 23         } catch (IOException e) {
 24             e.printStackTrace();
 25         }
 26     }
 27     
 28     public void start(){
 29         System.out.println("服务端启动。。。");
 30         while(true){
 31             try {
 32                 cs = ss.accept();
 33                 list.add(cs);
 34                 System.out.println("新的连接" + cs.getPort());
 35                                 
 36                 Thread receiveThread = new Thread(new ReceiveThread(cs));
 37                 receiveThread.start();
 38                 
 39                 if(isGroup){
 40                     isGroup = false;
 41                     new SendFunc().start();                    
 42                 }                
 43                 
 44             } catch (IOException e) {
 45                 e.printStackTrace();
 46             }            
 47         }        
 48     }    
 49 
 50     public class SendFunc extends Thread {
 51         @Override
 52         public void run() {            
 53             OutputStream os = null;
 54             PrintWriter pw = null;
 55             while(true){
 56                 try {
 57                     String msg =input.nextLine();
 58                     for(Socket sc:list){
 59                         os = sc.getOutputStream();
 60                         pw = new PrintWriter(os, true);
 61                         pw.println(msg);                    
 62                     }
 63                 } catch (IOException e) {
 64                     e.printStackTrace();
 65                 }
 66             }
 67         }    
 68     }
 69     
 70     public static void main(String[] args) {
 71         new ChatServer3().start();
 72     }
 73 
 74 }
 75 
 76 package lesson1220Socket;
 77 
 78 import java.io.IOException;
 79 import java.net.Socket;
 80 
 81 public class ChatClient3 {
 82     Socket socket;
 83     
 84     public ChatClient3() {
 85         try {
 86             System.out.println("客户端启动。。。。。");
 87             socket = new Socket("127.0.0.1", 7777);
 88         } catch (IOException e) {
 89             e.printStackTrace();
 90         }
 91     }
 92     
 93     public void start(){        
 94             Thread sendThread = new Thread(new SendThread(socket));
 95             sendThread.start();
 96             
 97             Thread receiveThread = new Thread(new ReceiveThread(socket));
 98             receiveThread.start();
 99     }
100     
101     public static void main(String[] args) {
102         new ChatClient3().start();        
103     }
104 
105 }
106 
107 package lesson1220Socket;
108 
109 import java.io.IOException;
110 import java.io.OutputStream;
111 import java.io.PrintWriter;
112 import java.net.Socket;
113 import java.util.Scanner;
114 
115 public class SendThread implements Runnable {
116     
117     private Socket socket;
118     public SendThread(Socket socket) {
119         this.socket = socket;
120     }
121 
122     @Override
123     public void run() {
124         
125         OutputStream os = null;
126         PrintWriter pw = null;
127         
128         try {
129             os = socket.getOutputStream();
130             pw = new PrintWriter(os, true);            
131             Scanner sc = new Scanner(System.in);
132             
133             while(true){    
134                 pw.println(sc.nextLine()); 
135             }        
136         } catch (IOException e) {
137             e.printStackTrace();
138         }        
139     }
140 }
141 
142 package lesson1220Socket;
143 
144 import java.io.BufferedReader;
145 import java.io.IOException;
146 import java.io.InputStream;
147 import java.io.InputStreamReader;
148 import java.net.Socket;
149 
150 public class ReceiveThread implements Runnable {
151     
152     Socket socket;
153     public ReceiveThread(Socket socket) {
154         this.socket = socket;
155     }
156 
157     @Override
158     public void run() {
159 
160         InputStream is = null;
161         InputStreamReader isr = null;
162         BufferedReader br = null;
163         
164         try {
165             is = socket.getInputStream();
166             isr = new InputStreamReader(is);
167             br = new BufferedReader(isr);
168             
169             while(true){    
170                 System.out.println("收到消息:" + br.readLine());
171             }        
172             
173         } catch (IOException e) {
174             e.printStackTrace();
175         }    
176     }
177 }

上面code可以实现多个客户端向服务端发送消息,服务端可以群发消息。客户端没有做任何改变。

只需修改服务端,就是如何让消息群发出去,由一个线程来控制,循环遍历所有socket,然后将消息发出去。

网上很多帖子都是服务端自动回一个固定消息,实际上没有实现一对多通信。

但是上面的功能不能实现服务端向指定客户端回消息。若是收到一个客户端,服务端就启动一个收发线程,收的线程没有问题,可是发的线程有问题。 没法进行维护?也不知道该数据发向哪个Socket????

 

下面这两个也是很好的通过线程来调用Socket的例子:

https://www.cnblogs.com/sddychj/p/6102192.html

https://www.cnblogs.com/qqzy168/p/3772215.html

https://blog.csdn.net/sl_40/article/details/53232423------这个博客解决了我群发消息的问题。

https://blog.csdn.net/aiynmimi/article/details/47323165------这个例子也实现多个客户端向服务端发消息,服务端群发消息。这个里面有界面,通过ActionListener来实现群发!

 

posted on 2019-01-16 10:36  shiyuan310  阅读(5206)  评论(0编辑  收藏  举报