Qt 基于TCP套接字编程

一、TCP和UDP区别:
1、TCP:

(1)、面向连接的,连接需要3次握手,断连需要4次挥手,即双向连接、双向断开。

(2)、流式传输协议,发送端和接收端处理数据量可以不均等,比如发送端一次发送10M数据,接收端每次接收1M数据,分10次接收。

(3)、数据可靠的,有数据校验机制,若数据包丢失则自动重传。
2、UDP:

(1)、面向无连接的,双方直接通信,无需连接。

(2)、报文式传输协议,发送端和接收端处理数据量均等,比如发送端一次发送1M报文,接收端要么一次接收1M报文,要么丢包,不存在接收一半报文的情况。

(3)、数据不可靠的,报文丢失就丢了。

二、简介
1、 在标准C++中,没有提供专门用于套接字通信的类,所以只能使用操作系统提供的基于C的API函数。
2、 基于C的API函数,我们可以封装自己的类。
3、 Qt是C++的一个框架,并且封装了用于套接字通信的类。
4、 在Qt中使用标准C的API进行套接字通信也是可以的。
**5、**网络通信和语言没有关系,只要搞清楚是TCP还是UDP。

三、TCP的C通信流程

cpp 复制代码
      TCP客户端                  TCP服务器端
	                             
								 socket()
								    |
                                  bind()
       socket()						|
		 |						 listen()
	   connect()				    |
		 |	\	   建立连接		  accept()
		 |		\	\	\	\	\   |
		 |						阻塞直到有客户端连接
		 |		   请求数据		    |
		send()------------------> recv()
		 |		   应答数据			|
		recv()<------------------ send()
		 |		   结束连接			|
		 |		  /	/ / / / / / / recv()
		 |		/				    |
		close()					  close()

四、UDP的C通信流程(没有严格意义上的客户端和服务器端)

cpp 复制代码
       SERVER                     CLIENT
	   
	   socket()                   socket()
	     |                           |
	    bind()                       |
         |          request // sendto()
       recvfrom() //		             |
		 |                           |
	   sendto() \\\\\\\\\\\          |
         |         response \\\\\\ recvfrom()
	     |                           |
	    close()					   close()

五、使用Qt提供的类进行基于TCP的套接字通信需要用到两个类:
1、QTcpServer:

服务器类,用于监听客户端连接以及和客户端建立连接。
2、QTcpSocket:

通信的套接字类,客户端、服务器端都需要使用。

注意: 这些通信类都属于网络模块network。

六、QTcpServer常用API函数:
1、QTcpServer(QObject * parent = nullptr)

(1)、构造函数
2、bool listen(const QHostAddress & address = QHostAddress::Any, quint16 port = 0)

(1)、告诉服务器监听地址address和端口port上的连接。

(2)、如果端口为0则会自动选择端口。

(3)、如果地址为QHostAddress::Any则服务器将监听所有网络接口。

(4)、成功返回true,失败返回false。
3、bool isListening() const

(1)、如果当前服务器正在监听则返回true,否则返回false。
4、virtual QTcpSocket * nextPendingConnection()

(1)、得到和客户端建立连接后用于通信的QTcpSocket对象。

(2)、注意,QTcpSocket对象是QTcpServer对象的子对象,当QTcpServer对象被销毁时,QTcpSocket对象会自动销毁。

(3)、但是,QTcpSocket通信完后,明确删除它是比较推荐的,以避免浪费内存,因为QTcpServer对象可能要继续监听很久。

(4)、注意,QTcpSocket对象不能在其它线程中使用,如果非要这样做,得重写incomingConnection()。
5、QHostAddress serverAddress() const

(1)、如果服务器正在监听连接,则返回服务器的地址,否则返回QHostAddress::Null。

(2)、这个地址就是C接口bind()的地址。
6、quint16 serverPort() const

(1)、如果服务器正在监听连接,则返回服务器的端口,否则返回0。

(2)、这个端口就是C接口bind()的端口。
7、bool waitForNewConnection(int msec = 0, bool *timedOut = nullptr)

(1)、阻塞等待客户端发起的连接请求。

(2)、不推荐在单线程程序中使用,建议使用非阻塞方式处理连接,即使用信号newConnection()。

(3)、最多等待msec毫秒,timedOut是出参,如果超时为true,没有超时为false。

(4)、如果有连接返回true,没有连接返回false。
8、void newConnection()

(1)、信号。

(2)、每次有新连接可用时都会发出此信号,无论它是否已添加到挂起的连接队列中。
9、void acceptError(QAbstractSocket::SocketError socketError)

(1)、信号。

(2)、当接受新连接导致错误时,将发射如下信号。

(3)、socketError参数描述了发生错误的信息。

七、QTcpSocket常用API函数:
1、 在服务器端,QTcpSocket对象是QTcpServer对象创建的,可以直接通信。

在客户端,需要程序员自己创建QTcpSocket对象,并且得先和服务器端建立连接,才能通信。
2、 继承关系:

QTcpSocket --> QAbstractSocket --> QIODevice。

QTcpSocket的读、写函数是继承QIODevice类中通用的。
3、QTcpSocket(QObject *parent = nullptr)

(1)、构造函数。
4、void connectToHost(const QHostAddress &address, quint16 port, QIODeviceBase::OpenMode openMode = ReadWrite)

(1)、连接服务器,需要指定服务器端绑定的IP和端口信息。

(2)、还有一个重载函数,其它参数一般默认。
5、QByteArray readAll()

(1)、从设备中读取所有剩余数据,并将其作为字节数组返回。

(2)、此函数无报错。

(3)、若返回的QByteArray对象为空,意味着当前没有可供读取的数据,或者发生了错误。
6、QByteArray read(qint64 maxSize)

(1)、从设备中读取最多maxSize字节数据,并将读取的数据作为QByteArray返回。

(2)、此函数无报错。

(3)、若返回的QByteArray对象为空,意味着当前没有可供读取的数据,或者发生了错误。
7、qint64 write(const char *data)

(1)、将数据内容写入设备,遇到'\0'结束。

(2)、返回实际写入的字节数。

(3)、如果发生错误,则返回-1。
8、qint64 write(const QByteArray &data)

(1)、将数据内容写入设备。

(2)、返回实际写入的字节数。

(3)、如果发生错误,则返回-1。
9、void connected()

(1)、信号。

(2)、此信号在调用connectToHost()并成功建立连接后发出。
10、void disconnected()

(1)、信号。

(2)、当连接断开时会发出此信号。

(3)、注意,若想在disconnected()信号对应的槽函数中删除QTcpSocket对象,只能使用deleteLater(),否则软件会崩溃。
11、void readyRead()

(1)、信号。

(2)、每当有新数据可从设备的当前读取通道读取时,就会发出一次此信号。

(3)、注意,只有新数据到达才会再次发出信号,而不是缓冲区中还有数据发出信号。

八、说明:
1、 在Qt中不管调用读函数接收数据,还是调用写函数发送数据,操作的对象都是本地由Qt框架维护的一块内存。
2、 调用了写函数数据不一定马上被发送到网络中,调用了接收函数也不是直接从网络中接收数据,因此才有QIODeviceBase::OpenMode这个参数。
**3、**关于底层的这些操作不需要开发者来维护。

九、基于TCP通信流程:
1、服务器端流程:

(1)、创建套接字服务器QTcpServer对象。

(2)、通过QTcpServer对象设置监听,即调用QTcpServer::listen()。

(3)、基于QTcpServer::newConnection()信号检测是否有新的客户端连接。

(4)、如果有新的客户端连接,在newConnection()信号对应的槽函数中调用QTcpServer::nextPendingConnection()得到通信的套接字对象。

(5)、使用通信的套接字对象QTcpSocket和客户端进行通信。
2、客户端通信流程:

(1)、创建通信的套接字类QTcpSocket对象。

(2)、使用服务器端绑定的IP和端口连接服务器QAbstractSocket::connectToHost()。

(3)、使用QTcpSocket对象和服务器进行通信。

相关推荐
老前端的功夫5 小时前
HTTP 协议演进深度解析:从 1.0 到 2.0 的性能革命
前端·网络·网络协议·http·前端框架
LaoZhangGong1235 小时前
以太网HTTP数据包格式分析
c语言·stm32·网络协议·http·tcp·arp
赖small强6 小时前
【Linux 网络基础】libwebsockets 技术文档
linux·网络·https·tls·lib·websockets
爱码小白6 小时前
PyQt5 QTimer总结
开发语言·qt
TT哇6 小时前
消息推送机制——WebSocket
java·网络·websocket·网络协议
Jay Chou why did7 小时前
13. Qt深入 样式表继承规则
qt
友友马7 小时前
『Qt』多元素控件
开发语言·qt
共享家95278 小时前
QT-界面优化(中)
开发语言·qt
wadesir9 小时前
当前位置:首页 > 服务器技术 > 正文Linux网络HSRP协议(实现路由器热备份与高可用性的实用指南)
linux·服务器·网络
带土19 小时前
4. 两台win11 笔记本局域网内文件传输
网络