使用BIO实现群聊

222 阅读2分钟

「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

业务逻辑分析

(1):多个客户端连接到服务端

(2):一个客户端发送消息,其它客户端都能接收到这条消息

(3):用户退出群聊

上代码:服务端

Server.class

public class Server{

    private int DEFAULT_PORT = 80;
    //当用户发送 quit 的时候代表该客户端要退出群聊
    private String QUIT = "quit";
     
    private ServerSocket serverSocket;
    
    //用来存储每一个客户端
    private Map<Integer,Writer> connectedClients;
    
    public Server() {
       connectedClients = new HashMap<Integer,Writer>();
    }
    
    //有新客户端连接
    public void addClient(Socket socket) throws IOException {
        if(socket != null) {
               int port = socket.getPort();
               BufferWriter writer = new BufferWriter(new OutputStreamWriter(scoket.getOutputStream()));
               connectedClients.put(port,writer);
               System.out.println("客户端[" + port +"] 已经连接到服务器");
        }
    }
    
    //客户端下线
    public void removeClient(Socket socket) throws IOException {
        if(socket != null && connectedClients.containsKey(socket.getPort())) {
                int port = socket.getPort();
                Writer writer = connectedClients.get(port);
                writer.close();
                connectedClients.remove(port);
                System.out.println("客户端[" + port +"] 已经连接下线");
        }
    }

    //判断客户端是否准备下线
    public boolean readyToQuit(String msg) {
        return QUIT.equals(msg);
    }
    
    //群发消息
    public void sendMsg(String msg, Socket socket) {
        int port = socket.getPort();
        for(Integer id : connectedClients.keySet()) {
              if(!port.equals(id)) {
                  Writer writer = connectedClients.get(id);
                  writer.writer(msg + "\n");
                  writer.flush();
              }
        }
    }
    
    //启动入口
    public void start() {
      try{
          serverSocket = new ServerSocket(DEFAULT_PORT);
          System.out.println("服务器已经启动..........");
          while(true) {
             Socket socket = serverSocket.accept();
             //创建一个新的线程来处理客户端请求
             new Thread(new ServerHandler(this,socket)).start();
          }
      }catch(Exception e) {
      
      }finally {
         if(serverSocket != null) {
            try{
                serverSocket.close();
              }catch(Exception e){
            
              }
         }
      }
    }
    
        public static void main(String[] args) {
            Server server = new Server();
            server.start();
        }
}

ServerHandler.class

 public class ServerHandler implements Runnable{


     private Server server;
     private Socket socket;
     
     public ServerHandler(Server server, Socket socket) {
             this.server = server;
             this.socket = socket;
     }


    public void run() {
        try{
            //添加当前客户端到集合中去
            server.addClient(socket);
            //读取用户发送过来的消息,转发给其它用户
            BufferReader reader = new BufferReader(new InputStreamReader(socket.getInputStream()));
            String msg = null;
            while((msg = reader.readLine()) != null) {
                System.out.println("客户端【"+socket.getPort()+"】:" + msg);
                //将消息转发给其它客户端
                server.sendMsg(msg);
                //检查用户是否下线
                if(server.readyToQuit(msg)){
                   break;
                }
        }
        }catch(Exception e) {
        
        }finally{
              System.out.println("客户端【"+socket.getPort()+"】已经下线");
              try{
                 server.removeClient(socket);
              }catch(Exception e) {}
        }
       
    }
 }

客户端代码

CLient.class

   public class Client {
       
       private String DEFAULT_ADDRESS = "127.0.0.1";
       private int DEFAULT_PORT = 80;
       private Socket socket;
       private BufferReader reader;
       private BufferWriter writer;
       
      private final String QUIT = "quit";
      
      //发送消息给服务器
      public void sendMsg(String msg,Socket socket) throws IOException{
          if(!socket.isOutputShutdown()) {
                 writer.writer(msg + "\n");
                 writer.flush();
          }
      }
      
      //从服务端接收消息
      public String receiveMsg() throws IOException{
          String msg = null;
          if(!socket.isInputShutDown()) {
                 msg = reader.readLine();
          }
          return msg;
      }
      
      //检查用户是否退出
      public boolean readyToQuit(String msg) {
           return QUIT.equals(msg);
      }
      
      //关闭资源
      public void close() {
         if(writer != null) {
             try{
                 writer.close();
             }catch(Exception e) {
               
             }
         }
      }
      
      //启动入口
      public void start() {
           try{
               socket = new Socket(DEFAULT_ADDRESS,DEFAULT_PORT);
               //创建IO流
               reader = new BufferReader(new InputStreamReader(socket.getInputStream()));
               writer = new BufferWriter(new OutputStreamWriter(socket.getOutputStream()));
               //处理用户的输入
               new Thread(new ClientHandle(this)).start();
               //读取服务端转发的消息
               String msg = null;
               if((msg = receiveMsg()) != null) {
                   System.out.println(msg);
               }               
           }catch(Exception e) {
           
           }finally{
                close();
           }    
      }  
      
        public static void main(String[] args) {
            Client client = new Client();
            client.start();
        }
   }
   

ClientHandle.class

   public class ClientHandle implements Runnable {
      
         private Client client;
         
         public ClientHandle(Client client) {
            this.client = client;
         }
         
         public void run() {
             try{
                 BufferReader input = new BufferReader(new InputStreamReader(System.in));
                 while(true) {
                     String input = input.readLine();
                     //向服务器发送消息
                     client.sendMsg(input);
                     //检查用户是否退出
                     if(client.readyToQuit(input)) {
                           break;
                     }   
                 }
             }catch(Exception e) {
             
             }
         }
   }

测试

1:启动服务端

2:启动二个客户端

3:在客户端的控制台输入消息,然后回车查看效果