• 02基于BIO的多线程客户端服务器通信案例


    在线聊天时序图

     

    服务端实现

     主程序入口

      1 package server;
      2 
      3 import java.io.BufferedWriter;
      4 import java.io.IOException;
      5 import java.io.OutputStreamWriter;
      6 import java.io.Writer;
      7 import java.net.ServerSocket;
      8 import java.net.Socket;
      9 import java.util.HashMap;
     10 import java.util.Map;
     11 import java.util.concurrent.ExecutorService;
     12 import java.util.concurrent.Executors;
     13 
     14 public class ChatServer {
     15 
     16     private int DEFAULT_PORT = 8888;
     17     private final String QUIT = "quit";
     18 
     19     private ExecutorService executorService;
     20     private ServerSocket serverSocket;
     21     private Map<Integer, Writer> connectedClients;
     22 
     23     public ChatServer() {
     24         executorService = Executors.newFixedThreadPool(10);
     25         connectedClients = new HashMap<>();
     26     }
     27 
     28     public synchronized void addClient(Socket socket) throws IOException {
     29         if (socket != null) {
     30             int port = socket.getPort();
     31             BufferedWriter writer = new BufferedWriter(
     32                     new OutputStreamWriter(socket.getOutputStream())
     33             );
     34             connectedClients.put(port, writer);
     35             System.out.println("客户端[" + port + "]已连接到服务器");
     36         }
     37     }
     38 
     39     public synchronized void removeClient(Socket socket) throws IOException {
     40         if (socket != null) {
     41             int port = socket.getPort();
     42             if (connectedClients.containsKey(port)) {
     43                 connectedClients.get(port).close();
     44             }
     45             connectedClients.remove(port);
     46             System.out.println("客户端[" + port + "]已断开连接");
     47         }
     48     }
     49 
     50     public synchronized void forwardMessage(Socket socket, String fwdMsg) throws IOException {
     51         for (Integer id : connectedClients.keySet()) {
     52             if (!id.equals(socket.getPort())) {
     53                 Writer writer = connectedClients.get(id);
     54                 writer.write(fwdMsg);
     55                 writer.flush();
     56             }
     57         }
     58     }
     59 
     60     public boolean readyToQuit(String msg) {
     61         return QUIT.equals(msg);
     62     }
     63 
     64     public synchronized void close() {
     65         if (serverSocket != null) {
     66             try {
     67                 serverSocket.close();
     68                 System.out.println("关闭serverSocket");
     69             } catch (IOException e) {
     70                 e.printStackTrace();
     71             }
     72         }
     73     }
     74 
     75     public void start() {
     76 
     77         try {
     78             // 绑定监听端口
     79             serverSocket = new ServerSocket(DEFAULT_PORT);
     80             System.out.println("启动服务器,监听端口:" + DEFAULT_PORT + "...");
     81 
     82             while (true) {
     83                 // 等待客户端连接
     84                 Socket socket = serverSocket.accept();
     85                 // 创建ChatHandler线程
     86                 executorService.execute(new ChatHandler(this, socket));
     87             }
     88 
     89         } catch (IOException e) {
     90             e.printStackTrace();
     91         } finally {
     92             close();
     93         }
     94     }
     95 
     96     public static void main(String[] args) {
     97         ChatServer server = new ChatServer();
     98         server.start();
     99     }
    100 
    101 }

    处理客户端请求

     1 package server;
     2 
     3 import java.io.*;
     4 import java.net.Socket;
     5 
     6 public class ChatHandler implements Runnable {
     7 
     8     private ChatServer server;
     9     private Socket socket;
    10 
    11     public ChatHandler(ChatServer server, Socket socket) {
    12         this.server = server;
    13         this.socket = socket;
    14     }
    15 
    16     @Override
    17     public void run() {
    18         try {
    19             // 存储新上线用户
    20             server.addClient(socket);
    21 
    22             // 读取用户发送的消息
    23             BufferedReader reader = new BufferedReader(
    24                     new InputStreamReader(socket.getInputStream())
    25             );
    26 
    27             String msg = null;
    28             while ((msg = reader.readLine()) != null) {
    29                 String fwdMsg = "客户端[" + socket.getPort() + "]: " + msg + "
    ";
    30                 System.out.print(fwdMsg);
    31 
    32                 // 将消息转发给聊天室里在线的其他用户
    33                 server.forwardMessage(socket, fwdMsg);
    34 
    35                 // 检查用户是否准备退出
    36                 if (server.readyToQuit(msg)) {
    37                     break;
    38                 }
    39             }
    40         } catch (IOException e) {
    41             e.printStackTrace();
    42         } finally {
    43             try {
    44                 server.removeClient(socket);
    45             } catch (IOException e) {
    46                 e.printStackTrace();
    47             }
    48         }
    49     }
    50 }

    客户端实现

    主程序入口

     1 package client;
     2 
     3 import java.io.*;
     4 import java.net.Socket;
     5 
     6 public class ChatClient {
     7 
     8     private final String DEFAULT_SERVER_HOST = "127.0.0.1";
     9     private final int DEFAULT_SERVER_PORT = 8888;
    10     private final String QUIT = "quit";
    11 
    12     private Socket socket;
    13     private BufferedReader reader;
    14     private BufferedWriter writer;
    15 
    16     // 发送消息给服务器
    17     public void send(String msg) throws IOException {
    18         if (!socket.isOutputShutdown()) {
    19             writer.write(msg + "
    ");
    20             writer.flush();
    21         }
    22     }
    23 
    24     // 从服务器接收消息
    25     public String receive() throws IOException {
    26         String msg = null;
    27         if (!socket.isInputShutdown()) {
    28             msg = reader.readLine();
    29         }
    30         return msg;
    31     }
    32 
    33     // 检查用户是否准备退出
    34     public boolean readyToQuit(String msg) {
    35         return QUIT.equals(msg);
    36     }
    37 
    38     public void close() {
    39         if (writer != null) {
    40             try {
    41                 System.out.println("关闭socket");
    42                 writer.close();
    43             } catch (IOException e) {
    44                 e.printStackTrace();
    45             }
    46         }
    47     }
    48 
    49     public void start() {
    50 
    51         try {
    52             // 创建socket
    53             socket = new Socket(DEFAULT_SERVER_HOST, DEFAULT_SERVER_PORT);
    54 
    55             // 创建IO流
    56             reader = new BufferedReader(
    57                     new InputStreamReader(socket.getInputStream())
    58             );
    59             writer = new BufferedWriter(
    60                     new OutputStreamWriter(socket.getOutputStream())
    61             );
    62 
    63             // 处理用户的输入
    64             new Thread(new UserInputHandler(this)).start();
    65 
    66             // 读取服务器转发的消息
    67             String msg = null;
    68             while ((msg = receive()) != null) {
    69                 System.out.println(msg);
    70             }
    71         } catch (IOException e) {
    72             e.printStackTrace();
    73         } finally {
    74             close();
    75         }
    76     }
    77 
    78     public static void main(String[] args) {
    79         ChatClient chatClient = new ChatClient();
    80         chatClient.start();
    81     }
    82 }

    用户输入任务线程

     1 package client;
     2 
     3 import client.ChatClient;
     4 import java.io.*;
     5 
     6 public class UserInputHandler implements Runnable {
     7 
     8     private ChatClient chatClient;
     9 
    10     public UserInputHandler(ChatClient chatClient) {
    11         this.chatClient = chatClient;
    12     }
    13 
    14     @Override
    15     public void run() {
    16         try {
    17             // 等待用户输入消息
    18             BufferedReader consoleReader =
    19                     new BufferedReader(new InputStreamReader(System.in));
    20             while (true) {
    21                 String input = consoleReader.readLine();
    22 
    23                 // 向服务器发送消息
    24                 chatClient.send(input);
    25 
    26                 // 检查用户是否准备退出
    27                 if (chatClient.readyToQuit(input)) {
    28                     break;
    29                 }
    30             }
    31         } catch (IOException e) {
    32             e.printStackTrace();
    33         }
    34     }
    35 }
  • 相关阅读:
    转:ORA-12541:TNS:无监听程序问题
    实战jmeter入门压测接口性能
    数据库的4种常用设计模式
    三范式,数据库设计的基本准则
    html5学习2
    html5学习1
    php初写成
    Typora编辑区域空白过大问题
    CURL 常用命令
    阿里云镜像创建Spring Boot工厂
  • 原文地址:https://www.cnblogs.com/lpzh/p/14953974.html
Copyright © 2020-2023  润新知