计网课设:基于TCP协议的简历聊天室程序设计
1 题目要求
设计题目:基于TCP协议的简易聊天室程序设计
设计要求:使用Java编程语言,设计并实现一个基于TCP协议的简易聊天室程序。
程序包括服务器端和多个客户端,客户端能够连接到服务器并实现实时的聊天功能。
实现基本的用户登录、消息发送和接收功能。
2 整体架构设计
在线聊天室程序通常采用客户端-服务器(C/S)架构设计如图3.1所示,其中服务器端负责管理用户连接、消息传递和群聊管理等核心功能,而客户端则提供用户界面,允许用户登录、发送消息和接收其他用户消息。
当设计一个聊天室程序时,除了客户端-服务器(C/S)架构外,通常还涉及到服务器与数据库的交互部分。服务器需要与数据库交互来存储用户的用户名和账号信息。
2.1 服务器端设计
在日常生活中,服务器通常要同时接收来自客户端的多个请求,需要同时为这些客户端提供它们想要的服务,因此服务器端通常采用多线程或异步IO等技术,以支持多个客户端同时连接和消息处理。
在此次课程设计任务中,服务器实现的核心功能列举如下:
- 接受和管理连接:服务器通过绑定到特定端口的ServerSocket监听客户端连接请求,每当有新的连接请求时,创建一个新的线程用于处理服务器与该客户端的连接。
- 用户认证:每当有客户端发出登录请求时,服务器需要验证客户端提供的用户名和密码是否存在以及是否正确,以确保用户身份的安全性和合法性。
- 消息接收和转发:当用户登录成功之后,需要和其他用户发送消息,此时服务器需要接收来自客户端的消息,根据目标用户或聊天室的不同,将消息发送给特定的客户端或所有连接的客户端(群发)。
- 用户管理:维护当前所有在线用户的状态,管理用户的发言权,当发现用户出现在聊天中使用言语或行为对其他用户进行恶意攻击时等行为时,应当对其进行禁言处理或者强制下线处理,防止对其他用户造成影响,也可以对指定用户解除禁言。
- 消息日志:日志记录可以帮助开发人员追踪和诊断服务器或客户端的问题。同时掌握每个客户端的行为,了解用户行为模式和使用习惯,从而优化产品功能和用户体验。
2.2 客户端设计
客户端主要用于处理用户的请求,以及与服务器端进行信息的交互,并且客户端的用户界面设计应考虑到用户友好性和操作便捷性,客户端实现的核心功能如下:
- 登录功能:登录界面主要为用户提供输入用户名和密码进行登录,用户点击登录后将登录信息发送给服务器,以进行用户身份的核验。
- 聊天功能:聊天功能是这个设计过程中最重要的部分,用户在成功登录后,进入聊天界面,可以和当前其他的在线用户进行群聊或者进行私聊,以及确保用户可以即时地接收到其他用户发送的消息,并在界面上实时显示。
2.3 数据库设计
在本次课程设计任务中,使用MySQL数据库来存储用户的登录信息,包括用户名和对应的密码。具体实现是通过创建一个名为user的表来完成,该表包含两个主要列,分别用于存储用户名(username)和密码(password)。这样设计的主要目的是在用户登录时能够有效地验证其身份信息。
3 TCP协议
当一个用户给其他用户发送消息时,应保证消息的完整性,因此在传输层采用TCP协议实现可靠传输。TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层协议。它是互联网协议套件中最核心的协议之一,确保了数据在网络中的可靠传输。
3.1 面向连接
在通信之前,TCP需要先建立连接,这包括3次握手过程(SYN、SYN-ACK、ACK),确保通信双方能够彼此确认并准备好数据传输。在用户聊天结束后应该释放连接。TCP协议通过4次握手释放连接,确保双方安全地关闭连接,避免数据丢失或冗余传输。
3.2 TCP连接的端点是Socket
每一条TCP连接唯一地被通信两端的两个套接字(Socket)所确定。每一个Socket由主机的IP地址和端口号构成,其中IP地址用来在整个互联网中标识一个主机,端口号用于在一个主机的若干进程中标识指定的进程。通过Socket,同一主机、不同主机的应用进程之间可以通过不同的端口号进行通信。TCP协议确保了数据传输的可靠性和安全性。
4 通信消息格式设计
在设计服务器和客户端之间的通信消息格式时,重要的考虑因素包括消息的结构化、易解析性和扩展性。因此将通信的消息分为消息头和消息体部分,消息头用于标识消息的用途或操作类型,类型为字符串(String);消息体是实际传输的数据载荷,类型为字符串(String)。
4.1 消息头
消息头通常用于标识消息的用途或操作类型。类型为字符串(String),它可以包括诸如命令、指令、请求类型等信息。通过消息头,服务器和客户端可以快速识别消息的意图,从而决定下一步要执行的操作。如表3.1所示,在消息头的设计中包含8种类型以及对应的关键字。
关键字 | 作用 | 解释 |
---|---|---|
loginRequest | 登录请求 | 客户端向服务器发出登录请求 |
loginReply | 登录回复 | 服务器对客户端发送的登录请求进行回复 |
public | 群聊消息 | 一个用户发送一条群聊消息 |
private | 私聊消息 | 一个用户对指定的用户发送一条私聊消息 |
mute | 禁言 | 服务器将指定用户禁言 |
dismute | 解除禁言 | 服务器将指定用户解除禁言 |
delete | 通知有用户下线 | 从客户端的在线用户列表中删除下线用户 |
exit | 强制用户下线 | 服务器将指定用户强制下线 |
4.2 消息体
消息体则是实际传输的数据载荷,也以字符串(String)类型为主。消息体包含了具体的数据信息,例如文本内容、文件内容、数据结构等,这些数据是根据消息头指示的操作类型而传输的。对不同消息头的消息体分析如下:
- 消息头为loginRequest:消息体包含用户名和密码登录凭证信息。
- 消息头为loginReply:消息体分为“true”和“false”两种信息,“true”表示身份信息核验通过,允许用户登录。否则不允许登录。
- 消息头为public:消息体为用户发送消息的主体内容,将其消息体的内容显示在群聊窗口中。
- 消息头为private:此时消息体是一个结构化的内容,分别用户名和对应的消息内容主体。
- 消息头为delete:消息体中包含下线用户的用户名,需要将其从在线用户列表中进行删除。
- 消息头为mute、dismute和exit:此时消息体为空,分别执行用户禁言和解除禁言操作。
通过合理设计和使用消息头和消息体,可以实现服务器和客户端之间的有效通信和数据交换。消息头提供了关键的元数据信息,帮助接收方正确解析消息;消息体则承载了具体的业务数据或操作结果。这种设计不仅能够满足各种通信场景的需求,还能保证通信的安全性、可靠性和扩展性。
5 数据库交互功能设计
在Java语言中,通常使用JDBC(Java Database Connectivity)与数据库进行交互。JDBC作为Java语言中与关系型数据库交互的标准API,提供了开发和维护数据库应用程序的基础设施。通过合理地利用JDBC的各种功能和特性,开发人员能够实现高效、可靠和安全的数据库操作,从而满足复杂的业务需求和性能要求。
在JDBC的基础上,实现了一个用于操作数据库的Java类DatabaseConnect,主要用于连接到MySQL数据库,并提供了查询和插入操作的功能,其中包含的变量如表3.2所示。
变量名 | 变量类型 | 作用 |
---|---|---|
sql | String | 用于存储SQL语句 |
stmt | Statement | 用于执行SQL语句的Statement对象 |
conn | Connection | 数据库连接对象 |
表3.3列举了DatabaseConnect类中定义的方法。通过这些方法,可以实现基本的用户身份验证和数据记录功能。同时,通过异常处理,确保程序在面对异常情况时能够正确地处理并提供错误信息。
方法名 | 返回值类型 | 参数列表 | 作用 |
---|---|---|---|
DatabaseConnect | 无返回值 | 无 | 注册JDBC驱动,建立数据库连接,实例话Statement对象 |
query | boolean | String username String password | 查询数据库中指定用户名的密码,并验证密码是否匹配 |
insert | boolean | String username String password | 向数据库中插入新的用户名和密码记录 |
DatabaseConnect类的代码实现如下:
1 | public class DatabaseConnect { |
在使用JDBC之前,首先需要加载适当的数据库驱动程序。每个数据库厂商都提供了自己的JDBC驱动程序,它们通常都实现了java.sql.Driver接口。之后通过DriverManager.getConnection()方法建立与数据库的连接。需要提供数据库的URL、用户名和密码。连接建立后,可以创建Connection对象来执行SQL语句和管理事务。并创建Statement或PreparedStatement对象,用于执行SQL查询、更新或删除操作。
通过执行SQL查询语句后返回的ResultSet对象来处理查询结果。ResultSet提供了对查询结果集的遍历和访问方法,可以通过列名或索引获取具体的数据值。在完成数据库操作后,需要显式关闭Connection、Statement、PreparedStatement和ResultSet等对象,以释放数据库资源并避免内存泄漏。
6 界面绘制
在界面绘制部分,包括客户端登录界面、客户端聊天界面以及服务器管理界面的设计,使用Java Swing工具进行开发。Java Swing是Java提供的一个GUI工具包,用于创建跨平台的桌面应用程序。它提供了丰富的组件和布局管理器,使开发者能够灵活地设计和布局用户界面。
在Swing中,提供了很多封装好的组件(Component)和布局管理器(Layout Manager),其中组件包括按钮(JButton)、标签(JLabel)和文本框(JTextArea)等;布局管理器用来确定组件在容器中的位置和大小,确保界面在不同平台和窗口大小下的一致性和美观性。常见的布局管理器包括FlowLayout、BorderLayout、GridLayout和GridBagLayout。
此外,在界面设计中还使用了事件监听器(Listener)来处理用户操作,比如处理用户点击按钮、用户选择私聊对象等事件,通过使用上述基本组件、布局和事件设计来完成此次界面的开发。
7 Socket编程实现聊天功能
7.1 Server类实现
Server类是一个实现服务器端功能的Java类,主要用于管理和处理多个客户端的连接和通信。该类包含两个重要的内部类:ClientAgent和ServerUI,它们分别负责处理客户端连接和管理服务器的用户界面。
表3.4描述了Server类中的变量,通过这些变量来帮助服务器管理和处理来自多个客户端的请求和消息。
变量名 | 变量类型 | 作用 |
---|---|---|
ui | ServerUI | 控制界面相关信息显示 |
db | DatabaseConnect | 与数据库进行交互 |
serverSocket | ServerSocket | 监听是否有客户端发送请求 |
mp | Map<Socket, String> | 建立socket和用户姓名之间的映射 |
clients | List<ClientAgent> | 保存当前所有在线用户的socket |
表3.5描述了Server类中的方法,这些方法共同组成了Server类的功能,实现了服务器端的核心逻辑:监听客户端连接、管理多个客户端的通信、处理消息广播和动态客户端管理等。
方法名 | 返回值类型 | 参数列表 | 作用 |
---|---|---|---|
Server | 无返回值 | Int port | 在port端口创建一个Socket套接字,创建界面 |
listen | void | 无 | 监听客户端连接请求 |
broadcastMessage | void | String message ClientAgent me | 向出了发送方me外其他客户端广播消息message |
在listen方法中,服务器端开放一个端口号不断监听从客户端发送的请求,使用java语言中的Socket类。Socket类位于java.net包中,提供了客户端和服务器之间进行通信的能力,支持基于TCP协议的网络通信。
Server类服务器的设计逻辑如下:首先使用Socket类创建客户端或服务器端的套接字对象。客户端通过Socket发送请求到服务器的指定地址和端口,服务器接受客户端的连接请求并创建一个ClientAgent客户端代理对象用于处理之后该客户端的请求。
Server类中监听来自客户端请求的核心代码如下:
1 | // 服务器创建socket |
之后服务器不断监听是否有客户端向当前的Socket发送请求,如果检测到有请求,则创建一个新的线程类的实例化对象client处理这个客户端的请求,之后继续监听是否有其他客户端发送请求。
7.2 内部类ClientAgent的实现
ClientAgent是Server类中的一个重要的内部线程类,主要负责处理服务器与单个客户端之间的通信。表3.6展示了其中的私有变量,具体变量类型和作用如下所示。
变量名 | 变量类型 | 作用 |
---|---|---|
myName | String | 用于存储当前socket对应的用户名 |
socket | Socket | 负责处理的客户端socket |
send | PrintWriter | 用于向客户端发送消息 |
receive | BufferedReader | 用于从客户端接收消息 |
同时定义了表3.7中的方法,来有效地处理客户端的连接、登录、消息收发等操作,保证了服务器与客户端之间的稳定通信和用户管理功能。
方法名 | 返回值类型 | 参数列表 | 作用 |
---|---|---|---|
ClientAgent | 无返回值 | Socket socket | 实例化与客户端通信所需的变量socket、send和receive |
login | void | String username String password | 处理客户端的登录请求 |
exit | void | String username | 处理客户端的退出请求 |
privateChat | void | String username String message | 处理客户端的私聊消息 |
run | void | 无 | 根据客户端发送消息的消息头类型进行逻辑处理 |
在上述方法中,最重要的是run方法的实现。在run方法中,通过reverive.readLine()不断读取客户端发送的消息,直到客户端断开连接。如果收到客户端发送的消息,根据消息头的类型进行逻辑处理。
同时,应当捕获可能的异常并及时输出错误信息。最终,在客户端断开连接时,执行清理工作:退出用户、关闭流和socket,并从在线用户clients列表中移除当前ClientAgent实例,核心代码如下:
1 | public void run() { |
7.3 Client类实现
Client类是一个基于Java Swing的客户端应用程序,用于实现在线聊天系统的功能,其中包含内部类ServerAgent用于处理来自服务器的消息。
变量名 | 变量类型 | 作用 |
---|---|---|
socket | Socket | 用于与server进行通信的套接字 |
receive | BufferReader | 用于从服务器接收消息 |
send | PrintWriter | 用于向服务器发送消息 |
chatUserName | String | 当前要进行私聊的用户名 |
如表3.9所示,在Client类中,有以下关键方法用于实现客户端的核心功能。
方法名 | 返回值类型 | 参数列表 | 作用 |
---|---|---|---|
Client | 无返回值 | 无 | 实例化与服务器通信所需的变量socket、send和receive |
loginCheck | boolean | String username String password | 发送用户登录请求到服务器,并等待服务器返回登录结果 |
loginSuccess | void | String username | 显示聊天界面,并启动新线程用于接收服务器发送的消息 |
createUI | void | String username | 处理客户端的私聊消息 |
newChatArea | void | 无 | 创建用户界面 |
sendMessage | void | 无 | 发送消息给服务器 |
newMessage | void | String message | 处理接收到的新消息 |
7.4 内部类ServerAgent的实现
在Client类中,最重要的是ServerAgent类的实现。ServerAgent类通过继承Thread类,实现了多线程处理接收服务器消息的功能。
在ServerAgent类定义了一个run方法,通过循环持续接收消息,并根据消息内容动态调整客户端的行为和界面显示,实现了与服务器端的实时通信和状态同步。其中使用了try-catch块捕获IOException异常,在捕获到异常时,抛出RuntimeException并传递原始异常对象,以便进行异常处理或记录。
ServerAgent类的代码实现如下:
1 | public class ServerAgent extends Thread { |
8 程序演示
在程序演示部分创建1个服务器端和2个客户端进行测试,以演示多个客户端同时与服务器通信和聊天功能测试的情况。
8.1 客户端注册和登录功能演示
启动在线聊天室程序后,登录界面如图3.2所示。
当用户第一次登录在线聊天程序时,需要注册对应的用户名和密码,即点击“注册”按钮进行用户的注册,如图3.3所示。
输入用户名和密码,点击“注册”,之后系统会提示是否注册成功,注册成功后可以在登录界面输入刚才注册的用户名和密码进行登录。如图3.4所示,当用户名和密码正确时,会提示登录成功。
登录成功之后会进入到聊天界面,此时用户可以选择和其他用户进行群聊或私聊,如图3.5所示。
同时,从图3.5可以看到当前用户为202113115,并且此时只有一个用户。这里再注册一个用户进行测试,同样登录进入到聊天界面如图3.6所示。此时由于用户202113115在线,所以在用户1的其他在线用户中会显示用户202113115的存在。同样在用户202113115的其他用户列表中也会显示用户1在线。
查看数据库中是否有对应的用户名和密码,如图3.7所示,发现此时MySQL数据库中存在已经两个用户注册的用户名和密码,说明程序对数据库的操作正确。
8.2 客户端群聊功能演示
客户端群聊功能是一个典型的网络应用场景,通常涉及多个用户通过网络连接在同一个聊天室或频道中进行即时通讯。当用户1在群聊窗口中发送一个消息时,其他所有用户都能够收到这条消息,演示结果如图3.8所示。
8.3 客户端私聊功能演示
客户端私聊功能与群聊功能有所不同,因为它需要指定接收者,而不是简单地将消息广播给所有连接的客户端,所以私聊功能需要进行额外的设计,同时私聊时应当单独打开一个聊天窗口,而不应该在群聊窗口中进行显示,。
用户1可以在左侧的其他在线用户列表中选择要进行私聊的用户,这里选择用户202113115,之后点击左侧“选定用户私聊”的按钮,即可开启一个和用户202113115私聊的窗口。此时,用户1和用户202113115的聊天内容除了他们其他人室看不见的,演示结果如图3.9所示。
8.4 服务器消息日志功能演示
由图3.10可以看到,服务器的界面有查看用户消息日志、查看在线用户、对指定的用户强制下线、禁言和解除禁言的功能。通过这些功能可以了解系统负载和活跃度,同时在发现恶意行为、违反规定或其他紧急情况下,管理员可以立即将用户强制下线或进行禁言,有助于维护在线聊天室的秩序和安全,提升了管理员对系统运行状态和用户活动的可视化和控制能力。
经过前面演示操作后的消息日志如图3.10所示,可以看到在服务器端能够看到所有用户的行为,例如所有用户的登录和注册。
8.5 服务器禁言功能演示
在服务器端可以对右侧在线用户中指定的用户进行禁言功能,防止有些用户发表不正当言论等行为,具体操作是点击一个用户后,点击底部中间的“禁言”按钮,结果如图3.11所示。
之后会提示已将用户1禁言,用户1将无法在聊天室中发送任何消息。发送消息按钮变为灰色以及不可点击状态,以示禁言状态。同时,管理员禁言后,用户1也将无法发起或回复任何私聊会话。私聊按钮也会被禁用,以防止用户1绕过禁言限制。
用户1禁言后的效果如图3.12所示。
8.6 服务器解除禁言功能演示
将用户禁言一段时间后,可以对用户解除禁言。通过点击“解除禁言”按钮实现,解除禁言后用户可以正常发送消息以及和其他用户进行私聊。
8.7 服务器强制下线功能演示
在服务器端可以对指定的用户进行强制下线的操作,即选定一个用户后,点击底部左侧的“强制下线”按钮,即可将对应的用户强制下线。被强制下线的用户的所在的客户端会弹出图3.14所示的下线提示窗口。
经过上述操作后,查看服务器端的日志文件如图3.15所示。
9 结束语
本次计算机网络课程设计应该是本科阶段的最后一个课程设计,通过计算机科学与技术专业的这么多次课程设计,感觉自己的代码能力和工程能力有了很大的提升。在此次设计一个基于TCP协议的简易聊天室程序时,我从中收获了许多宝贵的计算机网络知识和实践经验,其中最主要的是深刻理解了书本上所学的TCP协议和C/S架构。
在日常生活中,可靠的消息通信是非常重要的,如果人们之间传送的消息如果出现了丢失和差错,将会导致不可挽回的后果。通过实现聊天室程序,我深入理解了TCP协议的可靠性、流量控制和拥塞控制机制。理解TCP连接的建立、数据传输和断开过程对于两个源点之间的可靠通信至关重要。并且我学会了如何使用Socket API来实现基于TCP的通信。这不仅仅是理论知识,还涉及到实际的编码和调试过程,帮助我熟悉了如何在实际项目中应用所学的网络概念。
此外,实现一个聊天室需要处理多个客户端同时连接的情况,我通过使用并发编程来有效地管理多个线程或进程来处理这些连接。在开发过程中,我遇到了各种各样的错误和异常情况,例如客户端与服务器连接不上、服务器连接数据库失败以及服务器对收到的信息解析错误等。通过解决这些问题,我提升了自己的错误处理能力和调试技能,学会了如何有效地排查和修复网络程序中的问题。
计算机专业的理论知识学习固然重要,但仅仅停留在理论层面是远远不够的。只有将理论知识应用到实际项目中,才能真正理解它们的意义和实际效果。只有实际实现一个聊天室,才能体会到TCP如何在实际通信中处理数据包的传输和重传,以及如何通过Socket进行通信。在今后的学习和职业生涯中,这种实践经验将为我提供宝贵的基础和信心,使我能够更好地应对复杂的技术挑战和项目需求。
10 参考资料
- 王罡, 林立志. 基于Windows的TCP/IP编程[M]. 北京, 清华大学出版社, 2002.
- 李向江, 赵怡涛, 马雪凝. 基于Socket接口的局域网聊天系统设计[J]. 长江信息通信, 2024,37(04):109-111.
- 张玉, 贾遂民, 郑桂萍. 基于Socket的网络聊天系统的设计与实现[J]. 计算机时代, 2022,(12): 93-95.
- 甄泰航. 基于Socket通信的社交应用软件[J]. 电子技术与软件工程, 2020, (16): 30-33.
- 谢希仁. 计算机网络(第8版)[M]. 北京, 电子工业出版社, 2021.