1. 程式人生 > 其它 >01基於BIO的多人聊天室

01基於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 
12 public class
ChatServer { 13 14 private int DEFAULT_PORT = 8888; 15 private final String QUIT = "quit"; 16 17 private ServerSocket serverSocket; 18 private Map<Integer, Writer> connectedClients; 19 20 public ChatServer() { 21 connectedClients = new HashMap<>(); 22 }
23 24 public synchronized void addClient(Socket socket) throws IOException { 25 if (socket != null) { 26 int port = socket.getPort(); 27 BufferedWriter writer = new BufferedWriter( 28 new OutputStreamWriter(socket.getOutputStream()) 29 );
30 connectedClients.put(port, writer); 31 System.out.println("客戶端[" + port + "]已連線到伺服器"); 32 } 33 } 34 35 public synchronized void removeClient(Socket socket) throws IOException { 36 if (socket != null) { 37 int port = socket.getPort(); 38 if (connectedClients.containsKey(port)) { 39 connectedClients.get(port).close(); 40 } 41 connectedClients.remove(port); 42 System.out.println("客戶端[" + port + "]已斷開連線"); 43 } 44 } 45 46 public synchronized void forwardMessage(Socket socket, String fwdMsg) throws IOException { 47 for (Integer id : connectedClients.keySet()) { 48 if (!id.equals(socket.getPort())) { 49 Writer writer = connectedClients.get(id); 50 writer.write(fwdMsg); 51 writer.flush(); 52 } 53 } 54 } 55 56 public boolean readyToQuit(String msg) { 57 return QUIT.equals(msg); 58 } 59 60 public synchronized void close() { 61 if (serverSocket != null) { 62 try { 63 serverSocket.close(); 64 System.out.println("關閉serverSocket"); 65 } catch (IOException e) { 66 e.printStackTrace(); 67 } 68 } 69 } 70 71 public void start() { 72 73 try { 74 // 繫結監聽埠 75 serverSocket = new ServerSocket(DEFAULT_PORT); 76 System.out.println("啟動伺服器,監聽埠:" + DEFAULT_PORT + "..."); 77 78 while (true) { 79 // 等待客戶端連線 80 Socket socket = serverSocket.accept(); 81 // 建立ChatHandler執行緒 82 new Thread(new ChatHandler(this, socket)).start(); 83 } 84 85 } catch (IOException e) { 86 e.printStackTrace(); 87 } finally { 88 close(); 89 } 90 } 91 92 public static void main(String[] args) { 93 ChatServer server = new ChatServer(); 94 server.start(); 95 } 96 97 }

聊天任務

 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 + "\n";
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 + "\n");
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 }