我们来了解一下什么是TCP的通讯小知识点,方便后续的理解
1. TCP的简单了解
由网上搜索的资料可知,tcp传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。
tcp通讯一定要经过三次握手才可以连接成功进行通讯;且,tcp通讯只能一对一进行连接;现在大多数通讯都是使用tcp协议,例如用于发送文件等。
QTcpSocket继承自QAbstractSocket,与QUdpSocket传输的数据报不同的是,QTcpSocket传输的是连续的数据流,尤其适合连续的数据传输,TCP一般分为客户端和服务端,即C/S (Client/Server模型)。
QTcpSocket代表了两个独立的数据流,一个用来读取数据,一个用来写入数据,分别采用QTcpSocket::read()及QTcpSocket::write()操作,读取数据前先调用QTcpSocket::bytesAvailable来确定已有足够的数据可用。
QTcpServer处理客户端的连接,可通过QTcpServer::listen()监听客户端发来的连接请求,每当有客户端连接时会发射newConnection()信号,QTcpSocket可用于读取客户端发来的数据报,亦可发送数据报。
注意:QTcpSocket被称为通信套接字;
QTcpServer被称为监听套接字。
1.1QTcpServer服务端建立
首先要在pro文件增加网络库,即QT += network
然后才是QTcpServer服务端的建立
QTcpServer server = new QTcpServer();
connect(server,&QTcpServer::newConnection,this,&MainWindow::server_New_Connect);//监听
if(!server->listen(QHostAddress::Any, 8000)) {
qDebug()<<server->errorString();
}```
创建server对象后先要监听客户端的连接,通过listen函数可以开启监听,但是需要指定的监听ip和端口号,其中ip可以使用QHostAddress::Any
QTcpServer当有新客户端连接时会发出QTcpServer::newConnection的信号,只需要关联到自定义的槽即可。
void MainWindow::server_New_Connect() {
//获取客户端连接
auto socket_temp = server->nextPendingConnection();//根据当前新连接创建一个QTepSocket
m_socket=socket_temp;//记录此连接用于后续数据读写
//连接QTcpSocket的信号槽,以读取新数据
QObject::connect(socket_temp, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data);
//当断开连接时发出的信号
QObject::connect(socket_temp, &QTcpSocket::disconnected, this,&MainWindow::socket_Disconnected);
}
上述为一个新的接到的槽函数例子,利用nextPendingConnection获取到新的连接的socket,存储到此socket,并关联对应的信号。
主要有两个:接收到新的数据的信号以及连接断开的信号。
当连接断开可以响应信号槽机实现开后的操作。
1.2客户端的建立
客户端为主动连接方,不需要监听,直接建立QTcpServer就可以了。
m_socket = new QTcpSocket;
m_socket->connectToHost("127.0.0.1",80100,QTcpSocket::ReadWrite);
connect(m_socket,SIGNAL(connected()),this,SLOT(connected()));
上述例子使用的是信号槽方式等待连接成功,也可以使用阻塞方式:waitForConnected,等到接连成功才会执行后续代码,不需要建立新的槽函数。
通过connectToHost连接指定ip和端口,同时将socket的连接成功的信号与对应槽连接,当连接成功可以将自定义的标记位置为true,可进行相应的收发。
void MainWindow::connected() {
m_is_connected = true;
connect(this->socket,SIGNAL(readyRead()),this,SLOT(readyread())); //连接接收消息槽
QObject::connect(socket_temp,?&QTcpSocket::disconnected,?this,?&MainWindow::socket_Disconnected);//断开连接
}
当成功建立将接受和断开的信号进行connect
1.3信息收发
1.3.1阻塞收发
QT有提供阻塞收发以及连接、断开连接的函数:
virtual bool waitForConnected(int msecs = 30000)
virtual bool waitForDisconnected(int msecs = 30000)
virtual bool waitForBytesWritten(int msecs = 30000)
virtual bool waitForReadyRead(int msecs = 30000)
通过上述函数可以实现阻塞连接、断开连接、发送、接收数据内容
1.3.2不阻塞收发
无论客户端还是服务端只有在建立连接时有差异,后续的信息手法都相同
首先通过QTcpSocket::close()可以主动断开连接,无论客户端还是服务端都可以执行主动断开,通过readyRead()信号可以在接到信号时进行信息操作,在槽中执行QTcpSocket::readAll()可以读取缓冲区所有数据。
QTcpSocket::send()可发送信息,调用flush可立即发送缓冲区的数据,不需等待。
总结:1.服务端调用listen函数进行监听,是否有客户端与其进行连接;
2.客户端需要进行主动与客户端连接,调用connectToHost进行连接;
3.服务端:如果与客户端连接成功,服务器会触发newConnection信号;
4.客户端:如果与服务器连接成功,客户端会触发connected信号;
5.当断开连接,客户端的通信套接字会触发disconnected信号,服务器的通信套接字也会触发 disconnected信号;
6.服务器:触发newConnection信号后,必须在槽函数中实例化QTcpSocket对象;
7.服务端与客户端都是通过自己的通信套接字使用wirte函数进行发送信息;
8.服务端与客户端接收到对方发过来的消息时,都会触发readyRead信号,然后就可以在对应槽函数做接受处理;
9.服务端与客户端的断开都是使用通信套接字调用disconnectFromHost函数进行断开处理。