聊天室服务端实现
聊天主干逻辑
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 + "
";
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 }