zoukankan      html  css  js  c++  java
  • 这有点爽的

      简单应用了一下多线程,搞定了多客户端的问题。

      之前只能有一个客户端接入,因为服务器只会accept()一次,然后就进入接收输入流的死循环了。

      然后我趴在地上想了一下,主进程里死循环来accept(),然后每个客户端new一个新进程是不是就搞定了,越想越觉得有道理,于是就试了试。

      另外每个进程里重新各new一个Socket和输入流,这样就不会跟主进程产生冲突,同时主进程里的这两个也就可以直接删掉了。

      于是现在是各个进程各自处理自己的接收信息动作,互不干涉。

      启动进程是start()不是run()哪。

      现在的问题是服务器已经把该接收的都接收了,怎么把客户端发上来的消息再发给其他客户端呢。

      不可能在服务器里放一个StringBuffer,虽然这样很稳妥,也能解决问题,但是这样消耗带宽越来越大……

      另一种方法是客户端发上来消息之后先不更新自己的文本框内容,由服务器向所有客户端来发送,也就是说我发一条消息要发上去再下下来,是不是有点蛋疼,虽然这样也可以解决问题。

      

      诸君,我从小学开始就最擅长找笨办法了……

      智商低好痛苦 _(:з」∠)_

      1 import java.io.*;
      2 import java.net.*;
      3 
      4 /**
      5  * 服务器端,目前还是单纯的解包并在命令行打印,再下个版本改。
      6  * 1. 处理了端口已占用的异常。
      7  * 2. 客户端退出后不关闭进程。
      8  * 3. *重要内容* 改用多进程的方式,支持了多客户端接入。
      9  * 不过目前只能接收信息命令行打印。
     10  * 之后加上向其他客户端发送消息的功能。
     11  * 
     12  * @author mlxy
     13  * @version 0.6
     14  * */
     15 public class SimChatServer {
     16     ServerSocket ss = null;
     17     int users;
     18     
     19     /** 服务器构造方法,只用来初始化已连接客户端数。*/
     20     public SimChatServer() {users = 0;}
     21     
     22     public static void main(String[] args) {
     23         SimChatServer server = new SimChatServer();
     24         
     25         // 尝试启动服务器,端口被占用则提示并退出。
     26         try {
     27             server.ss = new ServerSocket(2333);
     28         } catch (BindException e) {
     29             System.out.println("Port occupied.");
     30             System.exit(0);
     31         } catch (IOException ex) {
     32             ex.printStackTrace();
     33         }
     34 
     35         // 死循环,等待客户端连接,连接成功则启动一个新线程。
     36         try {
     37             do {
     38                 server.new ClientThread(server, server.ss.accept()).start();
     39                 server.users++;
     40                 System.out.println("Current clients: " + server.users);
     41             } while (server.users > 0);
     42             
     43         } catch (IOException e) {
     44             e.printStackTrace();
     45         }
     46         
     47         
     48     }
     49     
     50     /** 管理客户端退出的方法。*/
     51     private void clientOut() {
     52         users--;
     53         System.out.println("Current clients: " + users);
     54         
     55         // 所有客户端都断开之后关闭服务器。
     56         if (users == 0) {
     57             System.out.println("All clients are out, server abort.");
     58             try {
     59                 ss.close();
     60             } catch (IOException e) {
     61                 e.printStackTrace();
     62             }
     63         }
     64     }
     65     
     66     /**
     67      * 内部类。
     68      * 单个客户端线程,包含了处理客户端发来信息的方法。
     69      * 目前只能接收信息,之后再加上向客户端发包的功能。
     70      * 
     71      * @author mlxy
     72      * @version 0.5
     73      */
     74     class ClientThread extends Thread {
     75         SimChatServer server;
     76         Socket singleSocket;
     77         ObjectInputStream singleInput;
     78         
     79         /** 一个客户端线程的构造方法。*/
     80         public ClientThread(SimChatServer server, Socket singleSocket) {
     81             this.server = server;
     82             this.singleSocket = singleSocket;
     83             System.out.println("Client connected.");
     84             try {
     85                 singleInput = new ObjectInputStream(singleSocket.getInputStream());
     86             } catch (IOException e) {
     87                 e.printStackTrace();
     88             }
     89         }
     90 
     91         @Override
     92         public void run() {
     93             // 主运行部分,抓到客户端退出的异常就打印提示并退出。
     94             try {
     95                 // 死循环,读包拆包打印。
     96                 while (true) {
     97                     String[] packReceived = (String[]) singleInput.readObject();
     98                     System.out.println(packReceived[0] + ": " + packReceived[1]);
     99                 }
    100                     
    101             } catch (ClassNotFoundException e) {
    102                 e.printStackTrace();
    103             } catch (EOFException ex) {
    104                 System.out.println("Client disconnected.");
    105             } catch (IOException exc) {
    106                 exc.printStackTrace();
    107             } finally {
    108                 // 关闭所有引用,释放资源。
    109                 try {
    110                     if (singleSocket != null)
    111                         singleSocket.close();
    112                     if (singleInput != null)
    113                         singleInput.close();
    114                     
    115                     // 报告一个客户端退出。
    116                     server.clientOut();
    117                 } catch (IOException e) {
    118                     e.printStackTrace();
    119                 }
    120             }
    121         }
    122         
    123     }
    124 }
    Server端
  • 相关阅读:
    Azure 虚拟机安全加固整理
    AzureARM 使用 powershell 扩容系统磁盘大小
    Azure Linux 云主机使用Root超级用户登录
    Open edX 配置 O365 SMTP
    powershell 根据错误GUID查寻错误详情
    azure 创建redhat镜像帮助
    Azure Powershell blob中指定的vhd创建虚拟机
    Azure Powershell 获取可用镜像 PublisherName,Offer,Skus,Version
    Power BI 连接到 Azure 账单,自动生成报表,可刷新
    Azure powershell 获取 vmSize 可用列表的命令
  • 原文地址:https://www.cnblogs.com/chihane/p/3524975.html
Copyright © 2011-2022 走看看