概述
TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输协议。它是互联网协议套件中的一部分,用于在网络上可靠地传输数据。
TCP通过建立连接、数据传输和连接终止三个阶段来进行通信。在建立连接阶段,客户端和服务器之间会进行握手,确认彼此的身份并建立一个可靠的连接。在数据传输阶段,数据会被分成小的数据包,每个数据包都包含序列号,接收方会根据序列号对数据包进行排序和重组,以确保数据的正确顺序和完整性。在连接终止阶段,连接会被关闭,释放资源。
TCP提供了可靠的数据传输服务,通过使用确认和重传机制来确保数据的准确性和完整性。它还支持流量控制和拥塞控制机制,以避免网络拥塞和数据丢失。TCP的连接是全双工的,意味着数据可以在两个方向上同时传输。
同时,TCP是一种面向连接的协议,这意味着在进行通信之前,客户端和服务器必须先进行握手建立连接。这种连接的特点是可靠性和顺序性,数据包会按照发送的顺序被接收方接收和处理。
QTcpSocket
QTcpSocket类提供一个TCP套接字。该类继承于QAbstractSocket。
QTcpSocket是异步进行工作的,通过发送信号来报告状态改变和错误信息,依靠事件循环来检测接收的数据。
可以使用QTcpSocket::write()方法写入数据,使用QTCPSocket::read()方法读取数据。
当从一个QTcpSocket中读取数据前,必须先调用QTcpSocket::bytesAvailable()函数来确保已有足够的数据可用。
如果要处理到来的TCP连接,需要使用到QTcpServer类。
QTcpServer
QTcpServer类提供了一个基于tcp的服务器。
这个类使得接受传入的TCP连接成为可能。可以指定端口,也可以让QTcpServer自动选择一个。可以监听一个特定的地址,也可以监听所有机器的地址。
调用listen()让服务器侦听传入的连接。然后,每次客户端连接到服务器时都会发出newConnection()信号。
调用nextPendingConnection()将挂起的连接作为已连接的QTcpSocket接受。该函数返回QAbstractSocket::ConnectedState中指向QTcpSocket的指针,可以使用该指针与客户端进行通信。
如果发生错误,serverError()返回错误的类型,并且可以调用errorString()来获得关于发生的错误描述。
当监听连接时,服务器正在监听的地址和端口可以作为serverAddress()和serverPort()使用。
调用close()使QTcpServer停止侦听传入的连接。
虽然QTcpServer主要是为与事件循环一起使用而设计的,但是不使用事件循环也可以使用它。在这种情况下,必须使用waitForNewConnection(),它会阻塞,直到连接可用或超时过期。
bool QTcpServer::waitForNewConnection(int msec = 0, bool *timedOut = Q_NULLPTR)
最多等待几毫秒,或者直到进入的连接可用为止。如果连接可用,则返回true;否则返回false。如果操作超时且timemedout不为0,则* timemedout将被设置为true。
这是一个阻塞函数调用。不建议在单线程GUI应用程序中使用它,因为整个应用程序将停止响应,直到函数返回。waitForNewConnection()在没有事件循环可用时非常有用。
非阻塞的替代方法是连接到newConnection()信号。
如果msec为-1,则该函数不会超时。
TCP 客户端和服务端连接流程
示例
先上UI
服务端监听,客户端连接,如果成功,服务端发送helloworld
,客户端显示
server
部分源码
cpp
m_pServer = new QTcpServer(this);
if(!m_pServer->listen(QHostAddress::LocalHost, 4567))
{
QMessageBox::information(this, "prompt", m_pServer->errorString());
return;
}
connect(m_pServer, &QTcpServer::newConnection, this, &MainWindow::slot_sendMsg);
}
void MainWindow::slot_sendMsg()
{
QByteArray ba("helloworld");
QTcpSocket* m_pSocket = m_pServer->nextPendingConnection();
connect(m_pSocket, &QTcpSocket::disconnected, m_pSocket, &QTcpSocket::deleteLater);
m_pSocket->write(ba, ba.size());
m_pSocket->disconnectFromHost();
ui->plainTextEdit->appendPlainText(QString("发送数据 :%1").arg(QString(ba)));
}
- 解释:
首先创建一个Server对象,然后监听本地主机的4567端口,如果成功,就发射newConnection()信号
client
部分源码
cpp
m_pSocket = new QTcpSocket(this);
connect(m_pSocket, &QTcpSocket::readyRead, this, [=](){
QString strInfo;
strInfo = m_pSocket->readAll();
ui->plainTextEdit->appendPlainText(strInfo);
});
}
void MainWindow::on_toolButton_con_clicked()
{
m_pSocket->abort();
m_pSocket->connectToHost(ui->lineEdit->text(), ui->lineEdit_2->text().toShort());
}
- 解释
连接本地主机的4567端口,当有可读数据时,发送readyRead()
信号。
使用场景
-
网页浏览:当用户在浏览器中请求网页时,使用HTTP协议进行通信,而HTTP通常基于TCP协议。TCP确保网页的可靠传输,确保网页内容的准确性和完整性。
-
文件传输:当用户需要通过网络传输文件时,常用的协议如FTP(文件传输协议)和SCP(Secure Copy)使用TCP协议。TCP可以确保文件的完整性和准确性。
-
电子邮件:SMTP(简单邮件传输协议)和POP3(邮局协议版本3)都使用TCP协议。TCP保证了邮件的可靠传输,以及邮件的正确接收和发送。
-
远程登录:如Telnet和SSH(安全外壳)协议使用TCP协议进行远程登录。TCP提供了稳定的连接,确保远程用户的输入和输出可以正确传输。
-
数据库访问:在数据库服务器和客户端之间进行数据的传输和交互时,使用TCP协议进行连接和通信。TCP保证了数据的完整性和可靠性。
结论
心有多大,舞台就有多大
。