基于TCP的Qt网络通信
项目源码:https://github.com/say-Hai/TcpSocketLearn/tree/QTcpSocket
在标准C++没有提供专门用于套接字通信的类,所以只能使用操作系统提供的基于C的API函数,但是Qt就不一样了,它是C++的一个框架并且里边提供了用于套接字通信的类(TCP、UDP)这样就使得我们的操作变得更加简单。
使用Qt提供的类进行基于TCP的套接字通信需要用到两个类:(都属于网络模块network
)
QTcpServer
:服务器类,用于监听客户端连接以及和客户端建立连接。QTcpSocket
:通信的套接字类(IO操作),客户端、服务器端都需要使用。(与文件操作类QFile
同属于同一个祖先QIODevice
)
一、QTcpServer类
QTcpServer
类用于监听客户端连接以及和客户端建立连接
1.1 公共成员函数
-
1⭐构造函数
-
QTcpServer::QTcpServer(QObject *parent = Q_NULLPTR);
-
-
2⭐给监听的套接字设置监听
-
//★类似于Socket中的 bind + listen bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0); //使用QHostAddress类对IPv4/6进行了封装,可以直接通过点分十进制赋值// 判断当前对象是否在监听, 是返回true,没有监听返回false bool QTcpServer::isListening() const;//返回监听的服务器地址 QHostAddress QTcpServer::serverAddress() const; // 返回服务器的端口 quint16 QTcpServer::serverPort() const
-
-
4⭐得到和客户端建立连接之后用于通信的QTcpSocket套接字对象
-
QTcpSocket
套接字对象QTcpServer
的一个子对象,当QTcpServer对象析构的时候会自动析构这个子对象,建议用完之后自己手动析构这个通信的QTcpSocket对象。 -
QTcpSocket *QTcpServer::nextPendingConnection(); //返回值:返回用于通信的套接字对象,建议自己手动释放内存
-
-
阻塞等待客户端发起的连接请求
-
不推荐在单线程程序中使用,建议使用非阻塞方式处理新连接,即使用信号
newConnection()
-
bool QTcpServer::waitForNewConnection(int msec = 0, bool *timedOut = Q_NULLPTR);
-
1.2 信号
-
当接受新连接导致错误时,将发射如下信号
-
void QTcpServer::acceptError(QAbstractSocket::SocketError socketError); //socketError:描述发生错误的相关信息
-
-
3⭐每次有新连接可用时都会发出 newConnection() 信号。
-
void QTcpServer::newConnection();
-
-
有数据可读取时,发送
readyRead
1.3 服务器连接的API调用顺序
-
创建
QTcpServer
实例-
QTcpServer *server = new QTcpServer(this);
-
-
监听端口
QTcpServer::listen()
-
server->listen(QHostAddress::Any, 12345)
-
-
连接
newConnection()
信号-
connect(server, &QTcpServer::newConnection, this, &MyServer::onNewConnection);
-
-
处理新连接
-
在槽函数
onNewConnection()
中获取新的QTcpSocket
,它代表与客户端的连接。 -
void MyServer::onNewConnection() {QTcpSocket *clientSocket = server->nextPendingConnection();// 连接信号与槽connect(clientSocket, &QTcpSocket::readyRead, this, &MyServer::onReadyRead);connect(clientSocket, &QTcpSocket::disconnected, this, &MyServer::onDisconnected); }
-
二、QTcpSocket
QTcpSocket
是一个套接字通信类,不管是客户端还是服务器端都需要使用。在Qt中发送和接收数据也属于IO操作(网络IO)
继承关系:
2.1 公共成员函数
-
构造函数
-
QTcpSocket::QTcpSocket(QObject *parent = Q_NULLPTR);
-
-
连接服务器:需要指定服务器端绑定的IP和端口信息
-
[virtual] void QAbstractSocket::connectToHost(const QString &hostName, quint16 port, OpenMode openMode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);void QAbstractSocket::connectToHost(const QHostAddress &address, quint16 port,OpenMode openMode = ReadWrite);
-
-
读写数据
-
在Qt中不管调用读函数,还是调用写函数,操作的对象都是由Qt框架维护的一块内存。因此,调用了发送函数数据不一定会马上被发送到网络中,调用了接收函数也不是直接从网络中接收数据,关于底层的相关操作是不需要使用者来维护的。
-
// 指定可接收的最大字节数 maxSize 的数据到指针 data 指向的内存中 qint64 QIODevice::read(char *data, qint64 maxSize); // 指定可接收的最大字节数 maxSize,返回接收的字符串 QByteArray QIODevice::read(qint64 maxSize); // 将当前可用操作数据全部读出,通过返回值返回读出的字符串 QByteArray QIODevice::readAll();// 发送指针 data 指向的内存中的 maxSize 个字节的数据 qint64 QIODevice::write(const char *data, qint64 maxSize); // 发送指针 data 指向的内存中的数据,字符串以 \0 作为结束标记 qint64 QIODevice::write(const char *data); // 发送参数指定的字符串 qint64 QIODevice::write(const QByteArray &byteArray);
-
2.2 信号
- 在
QTcpSocket
进行套接字通信的过程中,如果该类对象发射出readyRead()
信号,说明对端发送的数据已到达,之后可以调用read
函数接收数据。
void QIODevice::readyRead();
- 调用
connectToHost()
函数并成功建立连接之后发出connected()
信号。
void QAbstractSocket::connected();
- 在套接字断开连接时发出
disconnected()
信号。
void QAbstractSocket::disconnected();
2.3 客户端连接的API调用顺序
-
创建客户端套接字用于与服务器通信
-
QTcpSocket *socket = new QTcpSocket(this);
-
-
将客户端的信号与槽函数绑定,以便监听事件,例如连接成功、数据接收等。
-
connect(socket, &QTcpSocket::connected, this, &YourClass::onConnected); connect(socket, &QTcpSocket::readyRead, this, &YourClass::onReadyRead); connect(socket, &QTcpSocket::errorOccurred, this, &YourClass::onError);
-
-
使用
connectToHost
函数连接到目标服务器。-
socket->connectToHost("127.0.0.1", 12345);
-
三、通信流程
3.1 服务器端
通信流程:
- 创建套接字服务器
QTcpServer
对象 - 通过
QTcpServer
对象设置监听,即:QTcpServer::listen()
- 基于
QTcpServer::newConnection()
信号检测是否有新的客户端连接 - 如果有新的客户端连接调用
QTcpSocket *QTcpServer::nextPendingConnection()
得到通信的套接字对象 - 使用通信的套接字对象
QTcpSocket
和客户端进行通信
3.2 客户端
通信流程:
- 创建通信的套接字类
QTcpSocket
对象 - 使用服务器端绑定的IP和端口连接服务器
QAbstractSocket::connectToHost()
- 使用
QTcpSocket
对象和服务器进行通信