## 1.项目简介
在学完了UNIX网络编程的相关知识后,学以致用,就想着做一个简单的聊天室,实现本地虚拟机与Windows的通信,实现了本地的通信又想着与室友的电脑连通,与室友通过局域网连通了之后,想着完善聊天室的功能,增加了用户的注册与好友功能,包括好友的上线,下线的显示,就要用数据库管理注册的用户信息。这些都实现后,又想着与其他学校的同学连通,那就必须把服务器放在云端了,于是就去实现了。
在开发项目的过程中,会对以下知识和概念的理解更加深刻:
- 网络编程相关的API
- 套接字、端口
- 后台数据管理
- Mysql相关API
- Mysql与服务器建立连接
- 并发请求处理
对Linux下开发后台服务器的过程有所了解,熟悉了Linux中一些开发工具的使用。
而在开发客户端的过程中,对QT这款开发工具中与网络编程相关的API更加熟悉。
总体来看,实现了前台客户端到后台服务器过程的打通,对客户端与服务器的交互过程更加的熟悉。
## 2.整体结构
整体结构分为三个部分
- **客户端**:负责与用户交互,根据用户请求生成请求信息,发送给muduo服务器
- **muduo服务器**:负责从客户端接收用户请求信息,交由请求处理器处理,并从请求处理器接收请求响应,发送给客户端
- **请求处理器**:分为**信息处理器**和**MySQL**,信息处理器根据用户请求信息的不同,将信息处理后,交由MySQL存储或者从MySQL中获取数据,然后再生成响应信息,交给muduo服务器
![](https://www.writebug.com/myres/static/uploads/2021/10/24/8cc63f53b80d20f58cd9033128b70f2e.writebug)
## 3.基础知识
- Reactor反应模型
第一版的服务器用的只是一个简单的Reactor模型。主线程包含一个I/O多路转接器负责处理请求事件,对I/O的处理交给工作线程。
- TCP建立与关闭连接的过程,及优雅关闭连接
[TCP建立连接的三次握手和断开连接的四次挥手](https://www.cnblogs.com/LCCRNblog/p/5228648.html)
[TCP半关闭shutdown()函数](https://blog.csdn.net/skyuppour/article/details/44459579)
着重说一下关闭连接的问题
- 发送方不安全关闭连接方式:数据发送完后,直接调用close()
直接调用close()函数会关闭整个TCP连接,**如果TCP的发送缓冲区中还有数据,就会丢失**(**虽然也会发送出去,但是对方会返回一个RST或者SIGPIEP信号**),所以发送方发送数据完成后,直接用close(),可能会导致接收方接收的数据不完整。
- 发送方安全关闭连接的方式:数据发送完后,调用shutdown(sockfd, SHUT_WR)函数,关闭TCP的写端
发送方关闭TCP连接的**写端**(**这样任何对Socket写操作会触发SIGPIPE信号,同时发送FIN字段**),这样会使接收方的read返回0,如果接收方没有其他事做(有其他事:**若TCP发送缓冲区中还有数据没发完,会等到发送完毕再关闭连接**),接收方就会关闭连接(**发送FIN字段**),接收方关闭连接后,发送方的read也会返回0,发送方会进入**TIME_WAIT**状态,这样就是完整的通信,就不会出现数据丢失的情况了
- 接收方安全关闭连接的方式:read()->0后,再调用close()
- ![](https://www.writebug.com/myres/static/uploads/2021/10/24/8d532f7c5392f520d78f356db6cd88fb.writebug)
- TCP C/S编程三部曲
设置端口复用SO_REUSEADDR
忽略SIGPIPE信号
设置TCP_NODELAY
- 忽略SIGPIPE信号
在UNIX中,当发送方向一个已经关闭的管道写数据,发送方会收到SIGPIPE信号,默认情况会导致进程终止,这种情况有利于命令行管道,但是却不利于网络通信。在网络编程中,服务器向已关闭连接的客户端发送数据就会触发SIGPIPE信号,进而导致整个服务进程终止,影响所有的客户端。所以,在服务器启动之前需要忽略SIGPIPE信号。
> void handle_for_sigpipe()
> {
> struct sigaction sa;
> memset(&sa, '\0', sizeof(sa));
> sa.sa_handler = SIG_IGN;
> sa.sa_flags = 0;
> if(sigaction(SIGPIPE, &sa, NULL))
> return;
> }
- 设置TCP_NODELAY
默认情况下,TCP连接中,只要存在,已发送的数据包没有收到ACK的情况,调用write()不会发送数据,而是阻塞等待接收到所有已发数据包的ACK后再发送,所以对于write()->write()->read()方式,第二次的write()会有一个RTT(Round-Trip-time)的时延,虽说可以通过发送方的缓冲机制(将发送的消息整合到一起,只发送一次----write()->read()机制)解决,但并发请求下,缓冲机制的实现很难,所以,一般都会把TCP时延选项关掉。
> int optval=1;
>
> ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, &optval, static_cast<socklen_t>(sizeof optval)) ;
- 设置端口复用SO_REUSEADDR
方便服务器崩溃后可以马上重启,而不是要等待2分钟左右,等待端口重新启用。
在fork per connection模型中,子进程和父进程共享文件描述符(端口号),必须设置端口复用
> int optval=1;
>
> ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR,&optval, sizeof optval);
- TCP建立连接三次握手是从accept()函数之后开始的吗?
[TCP网络编程中connect()、listen()和accept()三者之间的关系](https://blog.csdn.net/tennysonsky/article/details/45621341?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task)
不是的。在客户端调用connect()后,三次握手建立连接开始。accept()只是从处于 established 状态的连接队列头部取出一个已经完成的连接,如果这个队列没有已经完成的连接,accept()函数就会阻塞,直到取出队列中已完成的用户连接为止。
![](https://www.writebug.com/myres/static/uploads/2021/10/24/43e8a3fd377751477f2048d85931d5ee.writebug)
## 4.测试及优化
### 4.1测试环境
- OS:Ubuntu 18.04
- 内存:2GB
- CPU:Intel(R) Xeon(R) Gold 6161 CPU @ 2.20GHz 单核
### 4.2测试工具
- 基于muduo的压力测试工具
### 4.3测试结果
- 1000并发量
1. 5线程
![](https://www.writebug.com/myres/static/uploads/2021/10/24/8dcfdbb92dfc500fb3d356711408a2ed.writebug)
处理完毕总耗时约16.44 s
2. 10线程
![](https://www.writebug.com/myres/static/uploads/2021/10/24/50ce298e599ad72f87c1b55f266d5c9b.writebug)
处理完毕总耗时约16.56 s
可以看到,在1000的并发量下,并未因线程的增多性能获得提升,因为处理器为单核的,所以多线程的优势发挥不出来。
## 5.演示
### 5.1**客户端**
win10下的客户端
![](https://www.writebug.com/myres/static/uploads/2021/10/24/d778ad76e8b389e2d89035b3316cdae1.writebug)
Ubuntu下客户端
![](https://www.writebug.com/myres/static/uploads/2021/10/24/65ef393a803c37b8b90dcae35e809119.writebug)
### 5.2聊天室
![](https://www.writebug.com/myres/static/uploads/2021/10/24/57d2b19a94983d0cb0bad0d2b616ff5a.writebug)
接收到好友请求
![](https://www.writebug.com/myres/static/uploads/2021/10/24/a9b4bf78d7f33f3aaeac91093328cf65.writebug)
是否同意?拒绝后,发送请求的一方会受到拒绝信息。
![](https://www.writebug.com/myres/static/uploads/2021/10/24/5c2880df33b4a55d799304e65d02be2a.writebug)
更换头像,实时更新,将头像信息回传到服务器。
![](https://www.writebug.com/myres/static/uploads/2021/10/24/a3f733f5dddb8212537153a5510d28c6.writebug)
实时更新好友头像,和状态信息
![](https://www.writebug.com/myres/static/uploads/2021/10/24/3c5ae7e000704b74735b947de214f705.writebug)
### 5.3服务器端
服务器后台记录在这里插入图片描述
![](https://www.writebug.com/myres/static/uploads
甜辣uu
- 粉丝: 9590
- 资源: 1102
最新资源
- 灰色关联分析与预测-MATLAB实现
- 三相PWM整流器,采用双闭环控制,用C语言实现PI控制,SVPWM等模块
- 电力系统潮流计算前推回代法MATLAB程序IEEE33节点系统 (1)该程序为电力系统潮流计算程序,硕士学位lunwen原程序,配有该lunwen (2)潮流求解方法为前推回代法,IEEE33节
- halcon 对线段上点的按线段方向顺序依一定距离依次取样排列
- 基于maxwell的6极36槽永磁同步电机(永磁直流无刷)模型,水冷,24.5kw, 绕组类型:分布式绕组,直流电压270Vdc,对6极 额定转速9000rpm,扭矩额定扭矩:输出扭矩不低于26Nm
- 毕设-c语言图书借阅系统源码3.zip
- 毕设-c语言通讯录管理系统源码1.zip
- 毕设-c语言学生成绩管理系统源码9.zip
- 毕设-c语言图书管理系统源码2.zip
- 毕设-c语言涂格子游戏源码4.zip
- 毕设-c语言五子棋源码7.zip
- 毕设-c语言万年历源码5.zip
- 毕设-c语言学生成绩管理系统8.zip
- 毕设-c语言学生信息系统10.zip
- 毕设-c语言文本编辑器系统源码6.zip
- 搭建属于自己的AI大语言模型网站(需要chatgpt的api即可搭建运行)
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈