目录
第1章 概述
1.1 概述
1.2 QT socket通信的本质
1.3 QUdpSocket相关的信号
1.4 QTcpSocket相关的信号
第2章 UDP通信示例
服务端代码:
客户端代码:
第3章 TCP通信代码示例
服务器端代码:
客户端代码:
第1章 概述
1.1 概述
在Qt中,通过套接字(socket)实现网络通信主要使用的是QTcpSocket和QUdpSocket类。QTcpSocket用于基于TCP协议的通信,而QUdpSocket用于基于UDP协议的通信。
在Qt中,使用TCP/IP协议进行网络通信可以使用QTcpSocket和QTcpServer类。QTcpServer用于创建服务器,监听连接请求并接受客户端连接,而QTcpSocket用于创建客户端,并与服务器建立连接。
1.2 QT socket通信的本质
QUdpSocket和QTcpSocket这两个类,是QT库提供的,应用程序,无论是服务器还是客户端,socket通信本质上就是创建应用程序的类和类对象,并且在socket库提供的QUdpSocket和QTcpSocket类和类对象之间进行对象间通信,当socket对象中有数据时,自动通过信号+槽机制,自动回调应用程序注册到socket对象中的槽函数。这就是QT socket通信的本质。
1.3 QUdpSocket相关的信号
QUdpSocket类在Qt中用于进行UDP网络通信。下面是QUdpSocket中一些常用的信号:
-
readyRead():当有新的数据可读取时触发该信号。可以通过调用readDatagram()方法读取数据。
-
stateChanged(QAbstractSocket::SocketState state):当QUdpSocket的状态发生变化时触发该信号。状态可以是QAbstractSocket::UnconnectedState(未连接状态)、QAbstractSocket::HostLookupState(主机查找状态)、QAbstractSocket::ConnectingState(连接中状态)、QAbstractSocket::ConnectedState(已连接状态)等。
-
errorOccurred(QAbstractSocket::SocketError socketError):当QUdpSocket发生错误时触发该信号。通过socketError参数可以获取到具体的错误类型,例如QAbstractSocket::ConnectionRefusedError(连接被拒绝错误)、QAbstractSocket::RemoteHostClosedError(远程主机关闭连接错误)等。
这些信号可以通过连接到相关的槽函数来实现相应的逻辑处理。使用示例如下:
// 声明QUdpSocket对象 QUdpSocket *udpSocket; // 连接信号和槽函数 connect(udpSocket, &QUdpSocket::readyRead, this, &MyClass::readReady); connect(udpSocket, &QUdpSocket::stateChanged, this, &MyClass::socketStateChanged); connect(udpSocket, &QUdpSocket::errorOccurred, this, &MyClass::socketErrorOccurred); // 槽函数实现 void MyClass::readReady() { QByteArray datagram; datagram.resize(udpSocket->pendingDatagramSize()); QHostAddress senderAddress; quint16 senderPort; udpSocket->readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort); // 处理读取到的数据 } void MyClass::socketStateChanged(QAbstractSocket::SocketState state) { // 处理状态变化 } void MyClass::socketErrorOccurred(QAbstractSocket::SocketError socketError) { // 处理错误 }
通过连接这些信号和相应的槽函数,可以实现对QUdpSocket对象的事件响应和处理。
1.4 QTcpSocket相关的信号
在Qt中,使用QTcpSocket类进行TCP网络通信。下面是QTcpSocket类的一些常见信号:
-
connected():当TCP套接字成功连接到远程主机时发出的信号。
-
disconnected():当TCP套接字与远程主机断开连接时发出的信号。
-
readyRead():当有新的数据可供读取时发出的信号。可以通过调用read()方法读取数据。
-
bytesWritten(qint64 bytes):当已成功写入一定字节数的数据后发出的信号。可以通过bytes参数获取已写入的字节数。
-
hostFound():当QTcpSocket已成功查找到远程主机时发出的信号。
-
stateChanged(QAbstractSocket::SocketState state):当QTcpSocket的状态发生变化时发出的信号。状态可以是QAbstractSocket::UnconnectedState(未连接状态)、QAbstractSocket::HostLookupState(主机查找状态)、QAbstractSocket::ConnectingState(连接中状态)、QAbstractSocket::ConnectedState(已连接状态)等。
-
errorOccurred(QAbstractSocket::SocketError socketError):当QTcpSocket发生错误时发出的信号。通过socketError参数可以获取到具体的错误类型,例如QAbstractSocket::ConnectionRefusedError(连接被拒绝错误)、QAbstractSocket::RemoteHostClosedError(远程主机关闭连接错误)等。
这些信号可以通过连接到相关的槽函数来实现相应的逻辑处理。使用示例如下:
// 声明QTcpSocket对象 QTcpSocket *tcpSocket; // 连接信号和槽函数 connect(tcpSocket, &QTcpSocket::connected, this, &MyClass::socketConnected); connect(tcpSocket, &QTcpSocket::disconnected, this, &MyClass::socketDisconnected); connect(tcpSocket, &QTcpSocket::readyRead, this, &MyClass::socketReadyRead); connect(tcpSocket, &QTcpSocket::bytesWritten, this, &MyClass::bytesWritten); connect(tcpSocket, &QTcpSocket::hostFound, this, &MyClass::hostFound); connect(tcpSocket, &QTcpSocket::stateChanged, this, &MyClass::socketStateChanged); connect(tcpSocket, &QTcpSocket::errorOccurred, this, &MyClass::socketErrorOccurred); // 槽函数实现 void MyClass::socketConnected() { // 处理连接成功事件 } void MyClass::socketDisconnected() { // 处理断开连接事件 } void MyClass::socketReadyRead() { // 处理有数据可读事件 } void MyClass::bytesWritten(qint64 bytes) { // 处理数据写入事件 } void MyClass::hostFound() { // 处理主机查找事件 } void MyClass::socketStateChanged(QAbstractSocket::SocketState state) { // 处理状态变化 } void MyClass::socketErrorOccurred(QAbstractSocket::SocketError socketError) { // 处理错误 }
通过连接这些信号和相应的槽函数,可以实现对QTcpSocket对象的事件响应和处理。
第2章 UDP通信示例
下面是一个简单的示例代码,展示了如何使用Qt进行UDP通信:
服务端代码:
// Server.h #ifndef SERVER_H #define SERVER_H #include#include class Server : public QObject { Q_OBJECT public: explicit Server(QObject *parent = nullptr); public slots: void readyRead(); private: QUdpSocket *udpSocket; }; // Server.cpp #include "Server.h" Server::Server(QObject *parent) : QObject(parent) { //创建udp socket对象 udpSocket = new QUdpSocket(this); //由于是服务器,需要绑定socket的IP地址和端口号 udpSocket->bind(QHostAddress::Any, 12345); //在socket对象和Server应用程序之间建立信号与回调函数机制 //当Server中有数据时,socket自动发送信号给Server应用程序,自动调用Server注册到Socket中的回调函数 connect(udpSocket, &QUdpSocket::readyRead, this, &Server::readyRead); } // Server的应用程序 void Server::readyRead() { while (udpSocket->hasPendingDatagrams()) { //为读取/接收数据准备缓冲区 QByteArray datagram; datagram.resize(udpSocket->pendingDatagramSize()); //为获取发送方信息准备对象 QHostAddress senderAddress; quint16 senderPort; //应用程序从socket中读取数据 udpSocket->readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort); qDebug() << "Received data:" << datagram << "from" << senderAddress.toString() << ":" << senderPort; // 在这里可以对接收到的数据进行处理 // 回复客户端: 即向socket写数据 udpSocket->writeDatagram("Server response", senderAddress, senderPort); } }
客户端代码:
// Client.h #ifndef CLIENT_H #define CLIENT_H #include#include class Client : public QObject { Q_OBJECT public: explicit Client(QObject *parent = nullptr); public slots: void readyRead(); private: QUdpSocket *udpSocket; }; // Client.cpp #include "Client.h" Client::Client(QObject *parent) : QObject(parent) { //创建udp socket对象 udpSocket = new QUdpSocket(this); //当udpSocket中有数据时,TCP/IP协议栈自动会给该socket发送事件 //该socket对象自动会发送readyRead的信号,请求应用程序读取数据 //应用程序只需要把自己对象的槽函数挂接到新创建的socket对象的readyRead事件上即可 //有socket中有数据时,创建的socket对象自动会发送readyRead事件,这是QT的网络通信协作栈保证的 connect(udpSocket, &QUdpSocket::readyRead, this, &Client::readyRead); } //readyRead是应用程序挂接到socket上,读取socket数据的函数 //本质上是一个回调函数而已 void Client::readyRead() { //client检查socket中是否有数据 //如果有数据,则一直读数据,然后数据读完 //如果没有数据,则直接退出 while (udpSocket->hasPendingDatagrams()) { //准备好数据接收buffer QByteArray datagram; datagram.resize(udpSocket->pendingDatagramSize()); //获取数据发送端的IP地址和端口号 QHostAddress senderAddress; quint16 senderPort; //从upd socket读取数据,并获得数据发送端的信息 udpSocket->readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort); qDebug() << "Received data:" << datagram << "from" << senderAddress.toString() << ":" << senderPort; // 在这里可以对接收到的数据进行处理 // ............................. // ............................. } }
第3章 TCP通信代码示例
特别说明:
TCP的socket与UDP通信相似,都是应用程序类对象向socket类对象注册回调函数,当socket对象发生某种事件,socket对象通过先前注册的回调函数(信号与槽),自动调用相应的应用程序处理socket相关信号!!!
下面是一个简单的示例代码,展示了如何使用Qt进行TCP/IP通信:
服务器端代码:
// Server.h #ifndef SERVER_H #define SERVER_H #include#include #include class Server : public QObject { Q_OBJECT public: explicit Server(QObject *parent = nullptr); public slots: void newConnection(); void readyRead(); void disconnected(); private: QTcpServer *tcpServer; QTcpSocket *clientSocket; }; // Server.cpp #include "Server.h" Server::Server(QObject *parent) : QObject(parent) { tcpServer = new QTcpServer(this); if (!tcpServer->listen(QHostAddress::Any, 12345)) { qDebug() << "Server could not start!"; } else { qDebug() << "Server started!"; } connect(tcpServer, &QTcpServer::newConnection, this, &Server::newConnection); } void Server::newConnection() { clientSocket = tcpServer->nextPendingConnection(); connect(clientSocket, &QTcpSocket::readyRead, this, &Server::readyRead); connect(clientSocket, &QTcpSocket::disconnected, this, &Server::disconnected); qDebug() << "Client connected!"; } void Server::readyRead() { QByteArray data = clientSocket->readAll(); qDebug() << "Received data:" << data; // 在这里可以对接收到的数据进行处理 // 回复客户端 clientSocket->write("Server response"); clientSocket->flush(); } void Server::disconnected() { qDebug() << "Client disconnected!"; clientSocket->deleteLater(); }
客户端代码:
// Client.h #ifndef CLIENT_H #define CLIENT_H #include#include class Client : public QObject { Q_OBJECT public: explicit Client(QObject *parent = nullptr); public slots: void connected(); void disconnected(); void readyRead(); private: QTcpSocket *tcpSocket; }; // Client.cpp #include "Client.h" Client::Client(QObject *parent) : QObject(parent) { tcpSocket = new QTcpSocket(this); connect(tcpSocket, &QTcpSocket::connected, this, &Client::connected); connect(tcpSocket, &QTcpSocket::disconnected, this, &Client::disconnected); connect(tcpSocket, &QTcpSocket::readyRead, this, &Client::readyRead); tcpSocket->connectToHost("127.0.0.1", 12345); } void Client::connected() { qDebug() << "Connected to Server!"; tcpSocket->write("Hello from Client!"); tcpSocket->flush(); } void Client::disconnected() { qDebug() << "Disconnected from Server!"; } void Client::readyRead() { QByteArray data = tcpSocket->readAll(); qDebug() << "Received data:" << data; // 在这里可以对接收到的数据进行处理 }
在上面的示例中,服务器监听在IP地址为"Any"(0.0.0.0)的所有网络接口上,端口号为12345的地址上。客户端连接到"127.0.0.1"(本地回环地址)上的12345端口。
当客户端连接到服务器后,服务器会打印"Client connected!"。当服务器接收到客户端发来的数据后,会在控制台打印该数据,然后回复客户端。客户端在接收到服务器的回复后,会在控制台打印该数据。
请确保在客户端连接之前启动服务器,以便能够接收到客户机的连接请求。
这只是一个简单的示例,你可以根据需要进行修改和扩展。请注意,在实际使用中,应该对错误和异
还没有评论,来说两句吧...