# ChattingRoom **Repository Path**: lxwzsh123/chatting-room ## Basic Information - **Project Name**: ChattingRoom - **Description**: 武汉大学大二下软构大作业,实现一个多功能聊天室,可实现两人实时聊天,听歌,并能统计两人近期聊天的高频词汇,聊天频率随时间的变化。 - **Primary Language**: C# - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2025-07-29 - **Last Updated**: 2025-07-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # C#大作业开发文档 ### 4/22 1. 新建gitee仓库 2. 挑选项目 3. 了解大概技术 更换项目! WPF需要花的时间太久 ### 5/7 ##### 项目流程 要编写一个C# WinForm网络多人聊天室,需要遵循以下步骤: 1.设计界面:首先需要设计一个用户友好的界面,其中包括发送消息的文本框、聊天记录的文本框和用户列表等。 2.建立服务器:创建一个服务器程序,并使其在网络上监听客户端的连接请求。在这个聊天室中,服务器将负责接收和转发客户端发送的消息。 3.建立客户端:创建客户端程序,并使其连接到服务器。每个客户端都可以发送和接收消息。 4.处理连接请求:当客户端连接到服务器时,服务器应该记录其连接信息并加入客户端列表。当客户端断开连接时,应该从列表中删除该客户端。 5.实现消息传递:当客户端发送消息时,服务器应该将该消息发送到所有已连接的客户端。 6.处理异常:由于网络连接是不可靠的,因此需要处理连接异常。例如,当客户端突然断开连接时,服务器应该清除该客户端的连接信息并从列表中删除该客户端。 7.优化聊天室性能:为了提高聊天室的性能,可以采用多线程和异步编程技术。例如,可以使用多线程来处理客户端的连接请求和消息传递,以避免阻塞主线程。 8.加入其他功能:可以根据需要加入其他功能,例如私聊、表情符号和文件传输等。 以上就是编写C# WinForm网络多人聊天室的一般思路,当然,具体实现细节还需要进一步研究和优化。 项目地址:https://github.com/seahore/chato.git,聊天室项目 ##### QQ的运作逻辑(模仿) QQ这种多人聊天的聊天室的运行逻辑大致如下: 1. 服务器端创建一个聊天室,并开放一个端口,等待客户端的连接。 2. 客户端连接到服务器,并向服务器发送加入聊天室的请求。 3. 服务器记录客户端的连接信息,并向其他已经连接到聊天室的客户端广播该新客户端的加入信息。 4. 新客户端接收到已连接客户端的加入信息,并将其显示在聊天室界面上。 5. 客户端之间可以通过服务器进行消息交流,当一位客户端发送消息时,服务器将该消息转发给其他已连接到聊天室的客户端。 6. 客户端接收到其他客户端的消息,并将其显示在聊天室界面上。 7. 当客户端离开聊天室时,客户端发送离开聊天室的请求给服务器,服务器将该客户端的连接信息从聊天室中移除,并向其他已连接到聊天室的客户端广播该客户端的离开信息。 8. 离开的客户端接收到已连接客户端的离开信息,并将其显示在聊天室界面上。 需要注意的是,在多人聊天室中,需要使用线程或异步编程来处理来自多个客户端的消息,以避免服务器阻塞或延迟响应。此外,还需要考虑消息的安全性和稳定性,例如消息的加密和校验等。 ##### 项目结构 1. Client > MainForm > > > 组件 > > > > > buttonConnect > > > > > > buttonSend > > > > 方法 > > > > > GetIPTex(t > > > > > > GetPoot() > > > > > > GetMsgText() > > > > > > ClearMsgText() > > > > > > Println(string s) > > > > > > SetConnectStatusLabel//设置连接状态标签 > > > > > > SetButtonSendEnabled//点击按钮发送 > > > > 委托 > > > > > VoidStirng(stirng s) > > > > > > VoidBoolString(bool b,stirng s) > > > > > > VoidBool(bool b) > > > > #### 一个简单的通过服务端实现客户端之间通信的代码 ```C# 使你的聊天程序能够监听UDP连接,而不仅仅是本地连接。使用UdpClient类来监听UDP连接,该类可用于创建一个UDP端口,从而允许多个客户端连接。例如: csharp Copy code UdpClient server = new UdpClient(port); 其中,port是你要使用的UDP端口。 当一个客户端连接到你的聊天程序时,你需要获取该客户端的IP地址和端口号。使用Receive方法来等待来自客户端的第一条消息,并从该消息中获取客户端的IP地址和端口号。例如: csharp Copy code IPEndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, 0); byte[] data = server.Receive(ref clientEndPoint); string clientIPAddress = clientEndPoint.Address.ToString(); int clientPort = clientEndPoint.Port; 其中,IPAddress.Any表示该服务器接受任何可用IP地址的连接,server.Receive等待来自客户端的第一条消息,并返回一个byte数组,该数组包含消息数据。clientEndPoint参数是传递给Receive方法的一个引用参数,该参数用于返回客户端的IP地址和端口号。 在你的聊天程序中,你需要使用客户端的IP地址和端口号来将消息发送到正确的客户端。例如,当一个客户端向你的聊天程序发送一条消息时,你可以使用以下代码将该消息转发到其他客户端: csharp Copy code foreach (IPEndPoint otherClientEndPoint in connectedClients) { if (otherClientEndPoint.ToString() != senderEndPoint.ToString()) { // 将消息发送到其他客户端 byte[] data = Encoding.UTF8.GetBytes(message); server.Send(data, data.Length, otherClientEndPoint); } } 其中,connectedClients是一个列表,包含所有当前连接到你的聊天程序的客户端的IPEndPoint。senderEndPoint是发送该消息的客户端的IPEndPoint ``` ### 5/8 正式开始,先做一个小型的基于Udp的简单聊天室,对界面暂时没有要求 后续可加功能: > 1. 表情包 > 2. 听音乐 > 3. 界面模式(比如整体色调的变化 > 4. 加密聊天 后续必加功能: > 1. 端口号合法性检查 1. 遇到的问题: > 1. C#中,实例成员只有在对象实例化后才能访问,只有静态成员才能在任何时候进行访问,也就是说不能再成员函数中访问非静态成员变量。要么把变量变成静态,要么把函数放到构造函数中 > > 2. 一个端口号只能使用一次 > > 3. 启动线程前要判断线程是否已经启动 > > 4. !!!!!UI线程和自定义的后台线程是独立的,当关闭界面前如果不手动关闭后台线程,后台线程会一直运行,以至于无法再次运行文件--FormClosing/ private void Form1_Load(object sender, EventArgs e)函数是一个预定义的,跟析构函数一样,也可以自己调用解决某些问题,比如关闭后台线程 > > 5. 端口使用后也要使用close进行释放 > > 6. Dispose和Close方法通常用于释放占用资源的对象。它们的区别在于: > > 1. Dispose方法是IDisposable接口定义的方法,用于手动释放对象所占用的资源,包括内存、文件句柄、数据库连接等非托管资源。一般情况下,如果一个类实现了IDisposable接口,就应该在使用完该对象后手动调用其Dispose方法,以确保及时释放资源。而Close方法通常是某些类(如FileStream、SqlConnection等)所定义的方法,用于关闭该对象所打开的资源,如关闭文件流、关闭数据库连接等。 > 2. Dispose方法可以在finally块中使用,以确保即使在出现异常的情况下也能够正确释放资源。而Close方法则通常不需要在finally块中使用,因为它只是关闭资源,不会抛出异常。 > 3. Dispose方法通常会将对象置为null,以便垃圾回收器可以更快地回收该对象占用的内存。而Close方法不会将对象置为null。 > > 需要注意的是,虽然Close方法并不是IDisposable接口的一部分,但是一些类实现了IDisposable接口,同时也定义了Close方法,这些类一般可以使用Close方法或者Dispose方法来释放资源。在这种情况下,两者的作用是相同的。 > > 7. 在C#代码中使用new Thread( )新建的进程默认是前台线程通常情况下,如果一个线程是前台线程,程序在退出时必须等待该线程结束,否则程序会一直等待直到该线程结束。而后台线程则不会影响程序的退出,它会随着程序的结束而自动结束。 1. UdpClient > ### 属性 > > - `Client`:获取或设置基础套接字。 > - `Ttl`:获取或设置发送多播数据包时使用的 TTL(生存时间)值。 > > ### 方法 > > - `Send(byte[] dgram, int bytes, IPEndPoint endPoint)`:向指定的终结点发送指定的字节数组。 > - `SendAsync(byte[] datagram, int bytes, IPEndPoint endPoint)`:以异步操作的方式向指定的终结点发送指定的字节数组。 > - `Receive(ref IPEndPoint remoteEP)`:接收数据报并返回一个字节数组,同时设置远程终结点。 > - `ReceiveAsync()`:以异步操作的方式接收数据报。 > > 在使用UdpClient类之前,需要先创建一个UdpClient对象并绑定到一个本地端口上,以便开始监听和处理来自其他节点的数据报。可以使用以下代码创建UdpClient对象: > > ``` > javaCopy code > UdpClient udpClient = new UdpClient(8080); > ``` > > 这将创建一个UdpClient对象,并将其绑定到本地端口8080上。现在,可以使用Send方法发送数据报,使用Receive方法接收数据报。 > > 需要注意的是,在使用完UdpClient类后,需要调用其Close方法释放资源,否则可能会导致资源泄漏。 2. QQ是怎么在不提前知道对方端口号的情况下给对方发消息的 *** 3. ## 服务端实现 ``` csharpCopy codeusing System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; class Server { static void Main(string[] args) { // 创建一个UdpClient对象并绑定到本地IP和端口 UdpClient server = new UdpClient(new IPEndPoint(IPAddress.Any, 8888)); Console.WriteLine("服务端已经启动..."); // 开启一个线程接收客户端发送的消息 Thread receiveThread = new Thread(() => { while (true) { // 接收客户端发送的消息 IPEndPoint clientEP = new IPEndPoint(IPAddress.Any, 0); //服务器这个线程进入阻塞,等待新的客户端连接,此时的clientEp里面没有任何实际的地址,直到接收到客户端连接后clientEP才有内容,并且是此客户端的地址。同时拿到此客户端发来的数据报 byte[] receiveBytes = server.Receive(ref clientEP); string receiveMsg = Encoding.UTF8.GetString(receiveBytes); // 将客户端发送的消息转发给其他客户端 Console.WriteLine($"收到来自 {clientEP} 的消息:{receiveMsg}"); //将客户端发送来的数据报再次打包(转化成字符数组),然后将此数据报发送给所有连接到此服务器的客户端 byte[] sendBytes = Encoding.UTF8.GetBytes(receiveMsg); foreach (IPEndPoint ep in clientList) { if (ep != clientEP) { server.Send(sendBytes, sendBytes.Length, ep); } } } }); receiveThread.Start(); // 开启一个线程定时清理客户端列表中已经关闭的连接 Thread cleanThread = new Thread(() => { while (true) { Thread.Sleep(10000); lock (clientList)//上锁 { for (int i = clientList.Count - 1; i >= 0; i--) { IPEndPoint ep = clientList[i]; try { // 发送一个空消息给客户端,如果客户端已经关闭连接,则会抛出异常 server.Send(new byte[0], 0, ep); } catch { Console.WriteLine($"客户端 {ep} 断开连接"); clientList.RemoveAt(i); //将客户离开聊天室的信息发送给所有客户端 byte[] sendBytes = Encoding.UTF8.GetBytes($"客户端 {ep} 离开聊天室"); foreach (IPEndPoint ep2 in clientList) { server.Send(sendBytes, sendBytes.Length, ep2); } } } } } }); cleanThread.Start(); Console.ReadLine(); } // 客户端列表 static List clientList = new List(); } ``` 4. ## 客户端实现 ``` csharpCopy codeusing System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; class Client { static void Main(string[] args) { Console.Write("请输入您的昵称:"); string name = Console.ReadLine(); // 创建一个UdpClient对象并绑定到本地IP和端口 UdpClient client = new UdpClient(new IPEndPoint(IPAddress.Any, 0)); // 向服务器发送加入聊天室的请求 byte[] sendBytes = Encoding.UTF8.GetBytes($"[{name}]加入聊天室"); client.Send(sendBytes, sendBytes.Length, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888)); scss Copy code // 开启一个线程接收服务器发送的消息 Thread receiveThread = new Thread(() => { while (true) { // 接收服务器发送的消息 IPEndPoint serverEP = new IPEndPoint(IPAddress.Any, 0); byte[] receiveBytes = client.Receive(ref serverEP); string receiveMsg = Encoding.UTF8.GetString(receiveBytes); // 显示服务器发送的消息 Console.WriteLine(receiveMsg); } }); receiveThread.Start(); // 开启一个线程发送消息 Thread sendThread = new Thread(() => { while (true) { // 读取用户输入的消息 string input = Console.ReadLine(); // 向服务器发送消息 byte[] sendBytes = Encoding.UTF8.GetBytes($"[{name}] {input}"); client.Send(sendBytes, sendBytes.Length, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888)); } }); sendThread.Start(); Console.ReadLine(); } 上面的代码示例中,服务端和客户端都使用了UDP协议来进行通信。服务端在启动后,首先创建一个`UdpClient`对象并绑定到本地IP和端口(8888)。然后开启一个线程接收客户端发送的消息,处理完消息后将消息转发给其他客户端。同时,服务端还开启了一个线程定时清理客户端列表中已经关闭的连接。服务端使用了一个静态的`clientList`变量来保存客户端列表。 客户端在启动后,首先要求用户输入昵称,然后创建一个`UdpClient`对象并绑定到本地IP和一个随机的端口。客户端向服务器发送加入聊天室的请求,并开启一个线程接收服务器发送的消息。同时,客户端还开启了一个线程读取用户输入的消息,并将消息发送给服务器。 当服务器收到客户端发送的消息后,会将消息转发给其他客户端。当客户端收到服务器发送的消息后,会将消息显示在控制台上。 需要注意的是,UDP协议是不可靠的,可能会出现消息丢失、重复等情况。在实际开发中,还需要考虑一些安全性和稳定性的问题,比如防止恶意攻击、断线重连、心跳包等。 ``` ### 5/10 1. 登录与注册页面 > 存在问题: > > > 页面切换 > > > > 数据库设计和存储账号 ### 5/15 使用MySQL,因为vs对前者有更好的兼容性。 1. C#数据库连接学习 > 1. 下载mysql(高版本具有caching_sha2_password身份验证插件,但是vs不支持。 > 2. 下载[mysql-for-visualstudio-1.2.9.msi](https://dev.mysql.com/downloads/windows/visualstudio/) > 3. 下载[mysql-connector-net-8.0.20.msi](https://dev.mysql.com/downloads/connector/net/8.0.html)使vs能获得MySQL数据源 > 4. 关闭mysql的SSL验证 > > - `data source`=服务器IP地址; > - `database`=数据库名称; > - `user id`=数据库用户名; > - `password`=数据库密码; > - `pooling`=是否放入连接池; > - `charset`=编码方式; 2. 数据库远程连接 > 如果你的程序需要在其他人的电脑上运行,并且要使用数据库进行身份验证,你需要考虑以下几点: > > 1. 远程数据库访问: 要使其他人能够通过数据库验证身份,你需要确保他们可以远程访问数据库。这要求数据库服务器允许远程连接,并且数据库的网络配置允许其他人连接。你需要配置数据库服务器以允许远程连接,并设置适当的网络安全策略。 > > 2. 配置连接字符串: 在你的程序中,你需要使用适当的数据库连接字符串,以便连接到远程数据库。连接字符串应包含数据库服务器的地址、端口、用户名、密码等信息。确保在连接字符串中使用安全的方式存储敏感信息,如使用加密或配置文件加密来保护连接字符串。 > > 3. 防止未经授权访问: 当其他人连接到远程数据库时,你需要确保只有经过身份验证的用户才能访问和执行数据库操作。你可以使用数据库的权限和访问控制机制,如用户角色、权限控制列表等,来限制用户的访问权限。 > > 4. 数据传输加密: 在远程连接和数据传输过程中,确保使用安全的传输协议,如 SSL/TLS,来加密数据的传输。这可以防止数据在传输过程中被窃听和篡改。 > > 5. 安全性和漏洞扫描: 考虑进行安全性评估和漏洞扫描,以确保你的程序和远程数据库的安全性。通过定期的安全性检查,及时修复和更新你的程序和数据库,以保护用户的数据和身份安全。 > > *** > > > > ​ 如果你是在本地建立了 SQL Server 实例,并且想让别人访问你的数据库,你需要确保以下几点: > > 1. 启用 SQL Server 的网络连接功能。默认情况下,SQL Server 仅允许本地连接,需要进行配置才能允许远程连接。 > 2. 打开 SQL Server 的防火墙端口。SQL Server 默认使用 TCP 协议的 1433 端口,需要在防火墙上开放这个端口才能让远程主机访问。 > 3. 允许 SQL Server 身份验证。默认情况下,SQL Server 仅允许使用 Windows 身份验证方式,需要配置才能启用 SQL Server 身份验证,以便用户使用用户名和密码访问数据库。 > > 如果以上三个步骤都已经完成,别人就可以通过远程连接方式访问你的数据库了。连接字符串应该包含 SQL Server 实例名称、用户名、密码以及数据库名称等信息。例如: > > ``` > sqlCopy code > Data Source=your_server_name;Initial Catalog=your_database_name;User ID=your_username;Password=your_password; > ``` > > 其中,your_server_name 是 SQL Server 实例的名称,如果是默认实例可以用 localhost 或者 . 表示;your_database_name 是要访问的数据库名称;your_username 和 your_password 是登录 SQL Server 的用户名和密码 3. 数据库连接数据获取 > > 在 C# 中,`MySqlCommand` 的 `ExecuteReader` 方法返回一个 `MySqlDataReader` 对象。`MySqlDataReader` 对象用于读取执行查询返回的结果集。 > > 要获取查询结果,你可以按照以下步骤进行操作: > > 1. 使用 `MySqlCommand` 对象执行查询,并调用 `ExecuteReader` 方法来获取 `MySqlDataReader` 对象。 > > ``` > csharpCopy codeMySqlCommand command = new MySqlCommand("SELECT * FROM YourTable", connection); > MySqlDataReader reader = command.ExecuteReader(); > ``` > > 2. 使用 `MySqlDataReader` 对象的方法来读取数据。可以使用 `Read` 方法来逐行读取结果集中的数据。 > > ``` > csharpCopy codewhile (reader.Read()) > { > // 读取每一行的数据 > // 可以使用索引或列名获取特定列的值 > int id = reader.GetInt32(0); > string name = reader.GetString(1); > // ... > } > ``` > > 注意:`GetXXX` 方法中的参数为列的索引或列名,从零开始计数。 > > !!!Reader只能同时打开一个 > > 3. 在读取完结果集后,记得关闭 `MySqlDataReader` 对象和数据库连接。 > > ``` > csharpCopy codereader.Close(); > connection.Close(); > ``` > > 这样就可以使用 `MySqlDataReader` 对象逐行读取查询结果,并获取相应的列值。 4. 实现一对一聊天思路 > > 要实现类似 QQ 的功能,显示与好友的对话页面并保持之前的聊天记录,可以考虑以下步骤: > > 1. 好友列表: 在客户端中创建一个好友列表,显示所有的好友头像或用户名。当用户点击某个好友头像时,将触发相应的事件或方法。 > 2. 对话页面: 创建一个对话页面或聊天窗口,在其中显示与好友的对话记录。对话页面可以是一个单独的窗体或用户界面元素。 > 3. 聊天记录存储: 在服务器端,可以使用数据库或其他持久化方式存储聊天记录。每次用户与好友进行聊天时,将聊天消息存储到数据库中,并关联好友标识符、发送者和接收者的标识符、消息内容、时间戳等信息。 > 4. 点击好友头像事件: 当用户点击好友头像时,客户端应该响应该事件,并获取与该好友的聊天记录。可以向服务器发送请求,获取该好友的历史聊天记录。 > 5. 显示聊天记录: 在对话页面中,根据获取到的聊天记录,显示用户和好友之间的对话记录。可以使用列表或聊天框等方式展示消息内容、发送者和接收者的信息。 > 6. 页面状态保存: 当用户切换到其他对话页面或关闭应用程序时,需要保存当前对话页面的状态,包括好友标识符、聊天记录等信息。可以将这些信息保存到本地数据库、文件或应用程序的内存中,以便在切换回对话页面时能够恢复之前的状态。 > > 需要注意的是,上述步骤提供了一般的实现思路,具体的实现方式和细节可能因应用程序架构和技术选择而有所不同。在实际开发中,你可以根据自己的需求和技术栈选择适合的方法和工具来实现该功能。 ### 5/18 1. 点击某一好友姓名跳转至相应聊天框 > 1. 聊天框实现 > > > !!!大坑:ListView在更换item的时候,即使只点击了一次,它的SelectedIndexChanged事件会执行两次,第一次先把selectedItems数组归零,第二次再执行时才会显示正确的值,因此必须先判断数组的长度是否大于零。 > > > > chatGPT对于这些经验性的知识掌握的很少。 > > 2. 发送信息的格式:对方UID+真实信息+自己UID,在服务端,会根据对方UID确定发送的对象,并将剩下的真实信息+自己UID发送给目标主机,目标主机得到自己UID后能显示在对应的聊天框 > > 3. 每个好友对应一个聊天框实例 > > 4. 加载一个聊天框时从数据库获取之前的聊天记录 ### 5/19 1. 实现聊天框界面的逻辑制作 2. 服务端接收信息并转发的识别逻辑 3. Bug:界面自动关闭 > C# WinForms 程序自动关闭的原因可能有多种,以下是一些常见的可能原因和解决方法: > > 1. 异常错误:程序中可能发生了未处理的异常错误,导致程序崩溃并关闭。你可以在程序中添加异常处理机制,使用 try-catch 块来捕获异常,并进行适当的处理和日志记录,以避免程序意外关闭。 > 2. 内存泄漏:程序中存在内存泄漏问题,导致内存占用过高,最终导致程序关闭。确保在不需要的时候及时释放对象和资源,尤其是对于大型对象或者订阅了事件的对象。 > 3. 无限循环:程序中可能存在无限循环的情况,导致程序无法正常退出。检查程序中的循环结构,并确保循环终止条件正确设置。 > 4. 系统资源不足:程序运行过程中,系统资源(如内存、文件句柄等)可能耗尽,导致程序关闭。检查程序是否正确释放资源,并优化程序的资源使用。 > 5. 线程问题:程序中使用了多线程,可能存在线程同步或死锁问题,导致程序关闭。确保在多线程操作中正确使用线程同步机制,避免死锁情况的发生。 > 6. 第三方库或组件冲突:程序中使用的某些第三方库或组件可能存在冲突或不稳定的情况,导致程序关闭。尝试更新或更换相关的库或组件,或者检查是否存在与其它组件或操作系统版本不兼容的情况。 > > 以上仅是一些常见的原因,具体问题需要根据你的程序代码和环境进行分析和调试。你可以尝试使用调试工具(如 Visual Studio)来附加到程序进程,以便捕获异常和调试问题。同时,记录程序关闭前的错误信息或日志,有助于更好地定位问题所在。 > > 如果你能提供更多关于程序关闭的详细信息和代码片段,我可以给出更具体的建议。 ### 5/22 1. 后台进程无法关闭原因: 在登录窗口中创建了聊天窗口并使登录窗口不可见( this.Visible = false;)在关闭聊天窗口时登录窗口还存在。 解决办法:在聊天窗口摧毁事件里加上Application.Exit(); Environment.Exit(0);强制关闭程序 2. 客户端无法收到服务端消息原因: ip不统一,且显示聊天框的组件不能再其他线程中创建,一个线程做一件事,使用全局变量接收这个线程做的结果。 ### 5/24 今日任务: > 1. 设计好注册界面 > > > 1. 使用随机生成六位UID(目前不存在的) > > 2. 设置密码(两次输入以保证一致) > > 3. 将用户信息导入数据库 > > 4. 新建一个用户的聊天信息表,根据时间顺序存信息 > > 5. 进入聊天页面 > > 6. 如果在登录界面就直接关闭窗口,则需要在窗口销毁事件里将整个程序关闭; > > 2. 重新设计身份识别,每个用户发的信息要以"对方UID"+"$"+"要发送的信息"+"$"+"自己UID"为标准 > > 3. 在登录界面为每个用户建立一个接收信息的数据库,方便后续导入 > > 4. 群聊功能 > > 5. 了解传输文件 > > 6. 了解服务器部署,将服务端代码部署在服务器 > > >部署服务器 > > > >记得开启两个防火墙 > > > >