当前位置:网站首页>Qt网络与通信(TCP聊天室)
Qt网络与通信(TCP聊天室)
2022-04-21 14:32:00 【啊渊】
目录
TCP理论知识
TCP协议是网络中常用的传输层协议,为满足TCP协议的这些特点,TCP协议做了如下的规定:
- 数据分片:在发送端对用户数据进行分片,在接收端进行重组,由TCP确定分片的大小并控制分片和重组;
- 到达确认:接收端接收到分片数据时,根据分片数据序号向发送端发送一个确认;
- 超时重发:发送方在发送分片时启动超时定时器,如果在定时器超时之后没有收到相应的确认,重发分片;
- 滑动窗口:TCP连接每一方的接收缓冲空间大小都固定,接收端只允许另一端发送接收端缓冲区所能接纳的数据,TCP在滑动窗口的基础上提供流量控制,防止较快主机致使较慢主机的缓冲区溢出;
- 失序处理:作为IP数据报来传输的TCP分片到达时可能会失序,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层;
- 重复处理:作为IP数据报来传输的TCP分片会发生重复,TCP的接收端必须丢弃重复的数据;
- 数据校验:TCP将保持它首部和数据的检验和,这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到分片的检验和有差错,TCP将丢弃这个分片,并不确认收到此报文段导致对端超时并重发。
聊天室
服务器提供服务,给予各个客户端链接到服务器中,然后客户端之间在聊天室里进行发送数据内容。

工程文件pro需要添加network库
QT += core gui network
TCP服务器
Tcp服务器聊天室的主要作用是接收来自不同客户端的链接,当有客户端链接到聊天室,向所有的客户读发送广播消息,当有客户端向服务器发送消息时,也同样广播消息给所有的客户端,通知其更新消息。
架构设计
设计如下:

TCPServer用户监听服务。
TCPClient每个客户端链接的消息通道。
TcpServer
TcpServer继承QTcpServer,在构造函数中使用listen函数启动监听。当有客户端链接到Tcp服务器时会自动调用incomingConnection函数。
incomingConnection函数内为每一个链接,创建一个客户端,并将将其保在m_listTcpClient列表中,当客户发送消息都会在每个客户端中接收消息。
void TCPServer::incomingConnection(qintptr handle)
{
TCPClient *tcpClient = new TCPClient(this);
connect(tcpClient, SIGNAL(sigUpdateClients(QString, qint64)), this,
SLOT(updateClients(QString, qint64)));
connect(tcpClient, SIGNAL(sigDisconnected(qintptr)), this,
SLOT(slotDisconnect(qintptr)));
tcpClient->setSocketDescriptor(handle);
m_listTcpClient.append(tcpClient);
}
TCPClient
TCPClient继承QTcpSocket 保存每一个客户端的链接,其绑定两个重要的消息信号。
readyRead信号:当客户端向服务发送信号,并且发送完毕后。触发该信号。然后可以通过read函数读取发送过来的数据。
disconnected信号:当客户端断链以后发送该信号。
TCPClient::TCPClient(QObject *parent):QTcpSocket(parent)
{
connect(this, SIGNAL(readyRead()), this, SLOT(slotDataReceived()));
connect(this, SIGNAL(disconnected()), this, SLOT(slotDisconnected()));
}
服务器读取客户端发送的消息,函数如下:
void TCPClient::slotDataReceived()
{
while (bytesAvailable() > 0) {
qint64 len = bytesAvailable();
char buf[1024] = {0};
read(buf, len);
QString msg = buf;
emit sigUpdateClients(msg, len);
}
}
关键流程
客户端向服务器发送消息流程
如下:

QTcpSocket接收到客户端发送数据完毕的信号,然后将信号通知给TcpClient。
TcpClient从缓冲区中拿到各个客户端发送的数据,然后将数据信息通过信号发送给TcpServer。
TcpServer,将获取的消息同步(遍历给每个客户端,并是write函数将消息发送个每个客户端)
TcpServer获取数据通过信号送给MainWindow。
MainWindow获数据,将内容展示在页面中。
客户端向服务器发出断链信号
note:在客户端链接的时候,通过setSocketDescriptor函数给予每个客户端唯一标识,为方便后期断链找到对应的客户端。
断链流程如下:

当客户端断链时,
QTcpServer接收到断链信号,并将其消息传递给TCPClient
TCPClient获取断链信号,将自己的setSocketDescriptor(唯一标识)通过信号方式传递给TCPServer
TCPServer获取信号后,查找对应的setSocketDescriptor找到客户端,把客户端从列表中删除。
void TCPServer::slotDisconnect(qintptr descrition)
{
foreach (auto item, m_listTcpClient) {
// 当断开时,找到对应的断开的句柄
if (descrition == item->socketDescriptor()) {
m_listTcpClient.removeOne(item);
return;
}
}
}
文件结构
├── main.cpp
├── mainwindow.cpp
├── mainwindow.h
├── README.html
├── README.md
├── tcp_client.cpp
├── tcp_client.h
├── tcp_server.cpp
├── tcp_server.h
├── TCPServer.pro
TCP客户端
架构

每个客户端只需一个QTcpSocket用于发送和接收数据。
绑定信号如下:
connect(m_ptrClientTcpSocket, SIGNAL(connected()), this,
SLOT(slotConnected()));
connect(m_ptrClientTcpSocket, SIGNAL(disconnected()), this,
SLOT(slotDisConnected()));
connect(m_ptrClientTcpSocket, SIGNAL(readyRead()), this,
SLOT(slotDataReveived()));
函数说明
connectToHost
用于链接服务器,链接成功后会触发connected()信号
virtual void connectToHost(const QHostAddress &address, quint16 port, OpenMode mode = ReadWrite);
address:需要链接的服务器i地址
port:服务器的端口号。
disconnectFromHost
disconnectFromHost与服务器断链,断链成功后会发送disconnected信号。
write
如果客户读已经链接完毕,可以通过write函数向服务器发送数据。
qint64 write(const char *data, qint64 len);
qint64 write(const char *data);
read
如果客户读已经链接完毕,服务器发送数据后可以通过该函数获取服务器发送的数据。
源码地址
Tcp服务器:QtNetWork/TCPServer · master · 啊渊 / QT博客案例 · GitCode
Tcp客户端: QtNetWork/TCPClient · master · 啊渊 / QT博客案例 · GitCode
版权声明
本文为[啊渊]所创,转载请带上原文链接,感谢
https://arv000.blog.csdn.net/article/details/124284771
边栏推荐
猜你喜欢

回归预测 | MATLAB实现Bayes-GRU(贝叶斯优化门控循环单元)多输入单输出

How to provide CPU branch prediction efficiency at the code level

Ali's monthly salary is 15K. The interview is so simple

or1k启动文件分析

From a comment in the source code, I trace it back to 12 years ago. It's a little interesting

IK word splitter

toString的使用与包装类的使用

How to apply for a free SSL certificate? Pagoda panel SSL certificate installation and deployment complete tutorial

I took out 38K from Tencent and showed me the basic ceiling

PCL测试程序出现LNK2001-无法解析的外部符号
随机推荐
Bug custom type
Insect sequence table
股价暴跌 Robinhood收购英国加密公司求扩张
.Net C# Newtonsoft. JSON serializersettings configuration
理性看待自动化测试优缺点
【Groovy】MOP 元对象协议与元编程 ( 使用 Groovy 元编程进行函数拦截 | 通过 MetaClass#invokeMethod 方法调用类其它方法 )
Golang Zap日志
Golang zap log
[groovy] mop meta object protocol and meta programming (use groovy meta programming for function interception | dynamic interception function | dynamically obtain methods in metaclass | evaluate metho
Why does MySQL index use B + tree instead of jump table?
.Net C# Newtonsoft.Json JsonSerializerSettings配置
如何申请免费SSL证书?宝塔面板SSL证书安装部署完整教程
源码级别的广播与监听实现
SQL server variable assignment and batch processing
代码重构之分解临时变量
Tencent side 2: what is the semi synchronization of MySQL?
Network security: introduce five common encryption algorithms
网络安全:为大家介绍5种常见的加密算法
蟲子 插入 希爾
Several implementation methods and optimization of quick sorting