zoukankan      html  css  js  c++  java
  • Socket 多线程编程

    前面一片学习了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()+"
    ");                
    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来实现群发!

  • 相关阅读:
    Vue--this.$refs 获取dom元素和组件(获取子组件的dom和方法)
    Vue评论案例--数据存放本地---联系子组件调用父组件方法(子组件点击发表-调用父组件更新评论列表)
    Spring系列教材 (五)- 注解方式 AOP
    Spring系列教材 (四)- aop 面向切面编程
    Spring系列教材 (三)- 注解方式 IOC/DI
    Spring系列教材 (二)- 注入对象
    Spring系列教材 (一)- 教程
    购物车系列教材 (五)- 订单模块
    购物车系列教材 (四)- 模块
    购物车系列教材 (三)- 用户模块
  • 原文地址:https://www.cnblogs.com/beilou310/p/10263097.html
Copyright © 2011-2022 走看看