Qt之TCP多线程收发(附源码)
本文介绍了传输控制协议/网际协议(TCP/IP)的基本概念及其在网络中的应用。该协议定义了设备如何连入互联网以及数据传输的标准,并支持应用程序之间的通信机制。TCP作为可靠通信协议的特点包括基于流的方式、面向连接以及超时重传机制等。此外,文章详细解释了三次握手(SYN发送、SYN+ACK接收及ACK确认)和四次挥手(FIN分节发送与接收)的过程,并展示了如何通过Qt框架实现TCP功能及相关代码示例。运行结果展示了一个完整的网络连接过程,并提供了获取源码的两种方式及关注作者的信息以促进进一步学习与交流。
TCP简介
● TCP/IP 是供已连接因特网的计算机进行通信的通信协议。
TCP/IP 代表传输控制协议/网际协议 (Transmission Control Protocol / Internet Protocol)
TCP/IP 通过规范电子设备(包括各种电子设备)如何接入互联网以及数据传输的流程来制定统一的通信标准。
● TCP 用于应用程序之间的通信。
当一个系统希望利用TCP协议向另一个系统进行通信时,它会向对方发送一个通信请求。这个请求必须被正确地发送到指定地址。在完成互换信息过程后,TCP协议将在两个系统之间实现全双工通信。
该双向通信将占据两个计算机之间的线路直至该线路被一方或双方切断之前
● UDP 和 TCP 很相似,但是更简单,同时可靠性低于 Tcp。
特点:
● 基于数据流传输机制;
● 以通信连接为基础;
● 确保通信过程的可靠性;
● 在网络状态欠佳时尽力减少因数据重传而产生的带宽消耗;
● 通信连接维护聚焦于两端设备而不涉及网络中间部分。
功能:
当应用层向TCP层发送用于网间传输的、用8位字节表示的数据流时,TCP协议会将其划分为适当长度的分段,最大传输分段大小(MSS)通常受限于当前连接所支持的最大数据链路单元(MTU)大小。随后将这些数据包转交给IP层,由后者负责将其传递至接收端实体对应的TCP层设备。
为了确保传输过程的可靠,TCP会对每个数据包赋一个序列号标识,同时这种序列化方式也保证了接收端实体能够按顺序接收已成功传输的数据块。对于已成功接收的数据块,接收端实体会返回相应的确认标记(ACK);如果发送端实体在合理传输时延(RTT)内未收到应有确认反馈,则认为相应的数据块丢失并将被重新发送。
在保证数据正确性和合法性的方面,TCP采用了计算校验和函数的方法来检测数据是否有误,在发送与接收过程中都需要执行这一操作;此外还可以采用MD5算法对数据进行加密认证。
为了提高传输可靠性,TCP采用了超时重传机制与带确认的重传策略。
在实现流量控制方面,TCP采用了滑动窗口协议,该协议规定:对于尚未得到确认的数据分组应当执行重传操作。
三步handshake流程:
(1)、客户端向服务器发送SYN报文(SEQ=x),进入SYN_SEND状态。
(2)、服务器接收到SYN报文后返回SYNAck包:SYN(SEQ=y)、ACK(x+1),进入SYN_RECV状态。
(3)、客户端接收到 server 返回的 SYN 指令后发送 ACK(y+1),完成握手过程进入Established状态
在三次握手完成后,TCP客户端与服务器端顺利完成连接建立过程;随后即可实现数据传输。

四次挥手:
(1) 某个应用进程首先发起close操作并称其端口为"主动关闭"(active close),随后该端口所在的TCP会发送一个FIN分段作为数据发送完毕的通知。
(2) 对方接收到此FIN分段后会进行"被动关闭"(passive close),并且此过程由TCP来确认完成。需要注意的是:
- FIN分段会被被发送方的应用进程用来标识文件结束符(end-of-file),并会被发送到等待接受相应连接的数据队列中去;
- 这是因为一旦接收到 FIN 分段就意味着相关连接上的数据接收已告一段落;
- 在此之后等待的数据不再会被处理;
(3) 一段时间过后,在接收到上述文件结束符的应用进程将发起一次close操作以关 closuresec),从而导致其所在 TCP 发送另一个 FIN 分段;
(4) 最终接受到这一 FIN 分段的应用层会响应这一事件并确认其完整性。
既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节。
注意:
(1)、“通常”是指,某些情况下,步骤1的FIN随数据一起发送,另外,步骤2和步骤3发送的分节都出自执行被动关闭那一端,有可能被合并成一个分节。
(2)、在步骤2与步骤3之间,从执行被动关闭一端到执行主动关闭一端流动数据是可能的,这称为“半关闭”(half-close)。
(3)、当一个Unix进程无论自愿地(调用exit或从main函数返回)还是非自愿地(收到一个终止本进程的信号)终止时,所有打开的描述符都被关闭,这也导致仍然打开的任何TCP连接上也发出一个FIN。
无论是在客户端还是在服务器端,任何一端都有能力发起主动关闭请求。一般情况下,客户端会发起主动关闭请求;然而,在少数特定协议中(例如HTTP/1.0这样的协议), server会进行主动关闭。

Qt - TCP
基于Qt的类:
服务代码:
/*
另外一说,moveToThread大家自行理解,在创建Server类时候可以写:
QThread *Thread = new QThread;
Server *sv = new Server;
sv->moveToThread(Thread);
Thread->start();
将收发数据函数定义为共有槽函数即可。
*/
Server::Server(QObject *parent) : QTcpServer(parent)
{
listen(QHostAddress("127.0.0.1"),5566);
connect(this,&QTcpServer::newConnection,this,&Server::NewConnection);
}
void Server::NewConnection()
{
if(hasPendingConnections())
{
socket = nextPendingConnection();
if(socket)
{
connect(socket,&QIODevice::readyRead,this,&Server::ReadyRead);
}
}
}
void Server::ReadyRead()
{
emit msg(socket->readAll().toStdString().c_str());
}
void Server::send(const QString &str)
{
socket->write(str.toStdString().c_str());
}
客户代码:
Socket::Socket(QObject *parent) : QTcpSocket(parent)
{
connectToHost("127.0.0.1",5566);
waitForConnected();
connect(this,&QIODevice::readyRead,this,&Socket::ReadyRead);
}
void Socket::send(const QString &str)
{
write(str.toStdString().c_str());
}
void Socket::ReadyRead()
{
emit msg(readAll().toStdString().c_str());
}
运行结果:

源码
获取方式一:积分下载
获取方式二:扫描下方微信公众号 ,回复 “102623648 ” ,立即获取源码链接。
关注
笔者 - jxd
通过微信公众号平台搜索“码农总动员”,或者通过扫描下方二维码访问该公众号账号,
了解更多你感兴趣的相关信息,
O(∩_∩)O~

