最近老师叫我们做一个基于Socket的多人聊天室,网上很多教程都只讲了如何通过Socket来建立连接以及通过控制台一遍打印证明连接已经完成但还没有具体实现多人聊天。这次我整理了一下自己的实现代码,希望能帮助到和我一样学习时感到困惑的兄弟姐妹。
这是基于TCP协议实现的Socket多人聊天室,分别用到ServerSocket(服务器)和Socket(客户端),说到TCP当然也离不开建立我们常常听到的三次握手、四次挥手,这里附上几位大佬的总结。
https://blog.csdn.net/jia281460530/article/details/41901069
https://blog.csdn.net/u013782203/article/details/51767763
聊天室有一个简单的图形界面,每一次客户端请求并完成连接时,服务器端会显示当前在线人数,同时在侧边栏添加了一个更新在线客户端信息的功能界面,显示在线的客户端(具体是显示每个客户端的名字,当然有一个局限就是客户端的名字不能相同)。如果想要在多台计算机之间实现通信,可以以管理员身份运行cmd命令行输入ipconfig查看相应的ip地址。
服务器主要功能:
服务器端的任务是不断地接收来自于多个客户端的连接请求,并且为每一个请求连接的客户端分配一个线程管理,每一个线程只管理与它相连接的客户端Socket。这里我用了Client内部类来封装每一个已经连接的客户端,这样子的好处是Socket的信息及输入输出流都能够一起保存;并将它们添加到List中,用于记录在线的客户端信息。同时,服务器起到的一个最重要的作用是转发,将A客户端发出的消息转发给B、C、D等多个在线客户端,这个时候保存了各个Client类的List就派上了关键用场,服务器每次收到一个客户端的消息就在List中查找每个在线客户端并向他们转发这个客户端所发出的消息(当然,跳过它自己本身)。总的来说服务器有以下几个功能:
- 循环监听并响应各个客户端的连接并为他们分配线程 **
- 接受各个客户端的消息并处理(代码中主要是在消息前面加上这个客户端的名字 如:Client_Name: + aLine(消息))
- 通过已保存好各个客户端信息的List来转发通过处理后的消息 **
- 如果有某个客户端A下线,则告诉其他在线客户端这个客户端A下线(代码中通过客户端发送Good Bye来说明离线)
- 更新【在线客户端信息界面】并将更新通知发往每一个在线客户端
客户端功能:
- 发送消息
- 接收消息并处理显示
- 更新在线客户端
其中,接收到的消息为:【Client_Name:+消息 】的时候显示在主文本框中;接收到的消息为:【update:+内容】的时候代表这是一个更新在线客户端的通知,显示在侧边的在线Client文本框中,内容中就是在线客户端的全部信息,并且每个客户端是以一个空格分隔的(这样子处理是因为我用BufferedReader读取消息时每次只读一行,(因为本人对输入输出流也并非太了解。。。))这个地方感觉做的不太好,另外,如果大家有什么建议或想法欢迎大家能跟我说说讨论讨论。
用到的技术:
- 图形界面GUI及响应事件
- 基于TCP的ServerSocket、Socket套接字
- 输入输出流
- Thread类
- 其中,服务器Thread主要是为每一个【封装了Socket的Client类】分配一个线程,客户端Thread主要是为了能实现不断地发送消息和同时不断地接受消息的功能。
以下是具体实现的代码
服务器:
package Server;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.LineBorder;
public class Server extends JFrame {
// server 对象
private ServerSocket server;
// Client's socket对象
private Socket socket;
// 存放客户端Client
List<Client> list;
// 窗口标签
private JLabel label;
// 面板用于容纳文本区和按钮
private JPanel labelPanel, clientPanel;
// 显示区
private JTextArea centerTextArea, clientTextArea;
public Server(int port) throws IOException {
server = new ServerSocket(port);
//控制台输出服务器端口号和ip地址
System.out.println(server.getLocalPort());
System.out.println(InetAddress.getLocalHost().getHostAddress());
//初始化存放Client的链表
list = new ArrayList<Client>();
setTitle("服务器");
//图形界面GUI
create();
//添加客户端
addClient();
}
private void create() {
setSize(500, 500);
// 窗口label,显示服务器名字
label = new JLabel("10086 服务器");
label.setFont(new Font("宋体", 5, 15));
labelPanel = new JPanel();
labelPanel.setSize(150, 20);
labelPanel.add(label, BorderLayout.CENTER);
// 窗口center部分,显示接收到的Client的消息
centerTextArea = new JTextArea(" ---聊天室已连接--- " + "\r\n");
centerTextArea.setFont(new Font("微软雅黑", 5, 13));
centerTextArea.setEditable(false); // 不可编辑
centerTextArea.setBackground(Color.LIGHT_GRAY);
// 窗口client部分,显示当前在线的Client
clientTextArea = new JTextArea("--在线Client--" + "\r\n");
clientTextArea.setEditable(false); // 不可编辑
//装载clientTextArea的容器
clientPanel = new JPanel(new FlowLayout());
clientPanel.setBorder(new LineBorder