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对象和服务器进行通信。

相关推荐
key_Go几秒前
07.容器监控
运维·网络·网络协议·docker·监控
東雪蓮☆20 分钟前
Ansible Playbook 编写与模块详解
linux·运维·网络·ansible
科技那些事儿1 小时前
海外代理IP软件哪家好?高性价比海外代理IP服务商平台
服务器·网络·tcp/ip
cpsvps1 小时前
容器主机名解析在香港服务器内部网络的调试方案
运维·服务器·网络
CAE虚拟与现实1 小时前
PyQt和Qt、PyQt和PySide的关系
开发语言·python·qt·pyqt·pyside
PyHaVolask2 小时前
渗透测试入门:从网络抓包到Web安全基础
网络·web安全·http协议·网络抓包
Reicher2 小时前
Wireshark的介绍和抓包
网络·测试工具·wireshark
gs801403 小时前
在 openEuler 上排查 Docker 同桥网络不通:从“全线超时”到定位容器没启动
网络·docker·容器
数据猿视觉3 小时前
海外代理IP平台推荐,跨境运营稳定不掉线代理IP软件
网络·网络协议·tcp/ip
jingfeng5143 小时前
浏览器发起http,到得到网页的整个过程
网络·网络协议·http