说明
今年由于疫情原因只能在家里学习,今年学校有一门很重要的课程《面向对象》,学习了java中的编程思想、多线程、JML、UML等等东西,为了检验自己学习得好不好,再加上听说 java 很适合 socket 编程,并且阿里云的服务器一年才九十多块钱,我就决定(其实以上都不是主要原因,主要原因就是考完试在家闲的发慌)决定搭建一个多人在线聊天室,并且从中也可以学习 Swing、socket 等等。
后面代码中所有GUI界面布局的内容,参见我之前的一篇博客 Swing的简要学习记录 。
本次实现的聊天室功能比较简单,主要实现的功能如下:
带有优美的 GUI界面(才怪);
在服务器允许的压力下支持多人实时聊天;
支持账户登录功能(不支持注册功能,也就是服务器端预先设好了账号)
以下是或许下一次要改进的内容:
实现注册功能;
实现单人聊天;
实现好友功能
Socket及java编程方法
socket(套接字)是计算机之间进行通信的一种约定。如果学过操作系统应该会知道,进程之间的通信(IPC)包括管道、FIFO、共享内存、信号量机制等等,这里socket就是一种可用于不同计算机的进程之间的通信机制,用来解决网络通信问题。
socket的通信基于TCP/IP协议,用(ip地址,协议,端口号)唯一标识某一个主机中的某一个进程,socket通信的数据传输方式包括两种:SOCK_STREAM(流套接字,基于TCP协议,特点是不易出错)和SOCK_DGRAM(数据报套接字,基于UDP协议,特点是速度快)。java中的socket编程应该主要是基于TCP协议的。TCP连接时有什么三次握手建立连接(connect)、四次握手断开连接(close),这些说实话具体过程我都不了解。
我只知道 java 中应该怎么写(注意里面的Macro是我自己定义的一个类,可以忽略):
服务器端:
// 建立socket服务
ServerSocket serverSocket = new ServerSocket(Macro.port);
// 这句话的意思是,一直等待客户端连接,一旦连接成功就返回一个socket
Socket socket = serverSocket.accept();
1
2
3
4
主要的socket连接建立其实就这两个,一般实现时会每当有客户端连接时,新建一个线程去处理。
客户端:
// 建立一个与serverIP服务器,port端口的socket连接
try {
socket = new Socket(Macro.serverIp, Macro.port);
} catch (Exception e) {
e.printStackTrace();
}
1
2
3
4
5
6
就这样服务器和客户端的socket连接就如此方便地建立好了!
常用文件流:
BufferedReader bufferedReader = null; // 这个是socket中的输入流
PrintWriter printWriter = null; // 这个是socket中的输出流
try {
bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
} catch (Exception e) {
e.printStackTrace();
}
1
2
3
4
5
6
7
8
这些文件流跟本地的标准输入输出以及文件操作其实差不多,就是写入读出这些操作。
然后就可以服务器和客户端就可以通过这两个流进行通信了。
功能结构
共享类
这是服务器和客户端共享的类,这些类不管在打包服务器的jar或者客户端的jar时都应该包括在内,这些类包括Macro和Message,前者定义了一些通信中encode和decode的规则,以及服务器ip、端口号等等,后者用于双方发送消息的载体。
Macro类:定义通信规则(包括对LOGIN请求的加密和解密、LOGOUT请求的加密和解密、MESSAGE的加密和解密、登录是否成功信号的定义)、服务器相关信息、一些信号的宏定义等等;
Message类:定义了用户发送的一个message需要包含的信息,有:发送者、发送时间、发送内容。
服务器端
服务器端处理用户登录登出请求、维护当前登录状态、维护用户账号密码信息、处理message发送请求,并且要支持多用户服务,主要包含的类如下:
server类:一直运行,初始加载Info类和MessageSend类,并且一直调用serverSocket.accept()进行socket连接监听,一但有socket连接成功,新建一个serverThread线程进行socket通信。
serverThread类:这个类与Info类和MessageSend类有关联关系,用于与socket通信。这个类需要一直读入用户请求,并且支持三种请求:
LOGIN请求:通过Info类判断该用户是否合法,密码是否正确,如果正确就在MessageSend中设定该用户在线,并且通过socket返回登录成功信号;
LOGOUT请求:直接在MessageSend中设定该用户注销(不在线);
MESSAGE请求:MessageSend中调用函数,给所有在线用户发送该message。
Info类:记录用户账号密码信息,提供账号密码是否正确的服务。
MessageSend类:记录在线用户(username)以及与他们socket通信中的PrintWriter,实现发送Message的功能。
客户端
客户端用于用户登录以及聊天,主要实现了两个GUI界面(登录界面和聊天界面),包括的类如下:
Client类:调用登录界面。
Login类:实现登录界面的JFrame,与服务器建立连接,每当进行登录操作时向服务器发送登录请求,然后读取登录是否成功的信息,如果成功调用Dialog类运行并且向之传送socket信息,然后销毁自己。
Dialog类:实现聊天界面的JFrame,通过socket与服务器通信,每当进行发送操作时,打包输入框中的文字为Message,然后发送给服务器。并且一直读入服务器传来的数据,进行decode然后显示在聊天框中。还要对窗体的关闭键进行监听,关闭窗体时向服务器发送LOGOUT请求,并且关闭当前的socket,然后销毁自己。
效果展示
代码
详细的代码和运行方法,参见 这里 。
原文链接:https://blog.csdn.net/dragonylee/article/details/107063946