本节主要介绍关于计算机网络通信以及QT实现TCP/UDP通信的内容
计算机网络体系结构模型
除了标准的OSI七层模型以外,常见的网络层次划分还有TCP/IP四层协议它们之间的对应关系为:
应用层:为操作系统或网络应用程序提供访问网络服务的接口,主要协议有FTP、HTTP、SMTP、SSH等
传输层:为两台主机上的应用程序提供端到端的通信,有TCP/UDP传输协议
- TCP可靠传输协议:TCP需要三步握手建立连接,TCP每次通信都会进行数据的校验
- UDP不可靠传输协议:UDP不需要建立连接、UDP不会进行数据校验
网络层:负责提供基本的数据封包传送功能,让每个数据包都能够到达目的主机,有IPV4/IPV6,3G/4G/5G等网络协议
物理层:光纤、路由器、基站、网线、网卡……
具体的理解可以见该视频20min开始的解释,还挺形象:24网络的基本概念_哔哩哔哩_bilibili
QT TCP网络编程
1.QTcpSocket Class客户端类
要想使用QTcpSocket必须先添加网络模块
一些函数接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14//1.连接服务器
connectToHost(const QString &, quint16, QIODeviceBase::OpenMode, QAbstractSocket::NetworkLayerProtocol);
connectToHost(const QHostAddress &, quint16, QIODeviceBase::OpenMode);
//第一个参数为IP地址;第二个参数为端口号(在0~65535范围内);第三个参数OpenMode默认readwrite模式,不用管
//2.数据发送
write(const char *, qint64); //发送qint64大小(byte为基本单位)的数据到char *地址上
write(const QByteArray &); //发送QByteArray类型的数据
write(const char *); //直接发送字符数据
//3.数接接收
read(char *, qint64); //读取qint64大的数据到char*地址上
read(qint64); //读取qin64大的数据并返回QByteArray类型
readAll(); //读取所有数据并返回QByteArray类型示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13//1.创建一个客户端的通信对象
QTcpSocket *socket = new QTcpSocket(this);
//2.连接服务器
socket -> connectToHost("192.168.25.2", 1000);
//3.数据发送
socket -> write("hello");
//4.数据接收
QByteArray rev_data = socket -> readAll();
//其中数据的接收需要关联可读信号:readyReady()[每次有新数据可从设备的当前读取通道读取时,都会发出此信号。]
connect(socket, SIGNAL(readyReady()), this, SLOT(read_data())); ///自己再编写一个read_data槽函数
2.QTcpServer Class服务器类
一些函数接口:
1
2
3
4
5
6
7
8//1.绑定并监听
listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
//2.接收连接请求
[signal] void QTcpServer::newConnection(); //每次有新连接可用时都会发出此信号,无论该连接是否已添加到待处理连接队列中
//3.服务器产生新的对象
nextPendingConnection(); //返回一个新的QTcpSocket对象示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24//1.创建一个服务器对象
server = new QTcpServer(this);
//2.开始监听
if(server -> listen(QHostAddress::Any,6666)){
qDebug() << “监听成功”;
}
else {
qDebug() << “监听失败”;
}
//3.关联新的连接信号
connect(server, SIGNAL(newConnection()), this, SLOT(accept_connect())); //自己编写连接后的处理函数accept_connect
void accept_connect{
//产生新的通信对象
QTcpSocket *new_socket = server -> nextPendingConnection();
//新的对象发送数据
new_socket -> write("hello");
//新的对象接收数据
connect(new_socket, SIGNAL(readyRead()), this, SLOT(read_data()))
};服务器处理客户端连接逻辑:下图很形象。注意:客户端和服务器是不会直接通信的!!!
QT UDP网络编程
UDP的通信流程:
UDP部分客户端与服务器端
一些函数接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22//1.发送数据的接口
writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port);
//data:需要发送的数据
//size:数据的大小
//address:接收端的IP
//port:接收端的端口
writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port);
//2.绑定UDP socket
bind(const QHostAddress &address, quint16 port = 0, QAbstractSocket::BindMode mode = DefaultForPlatform); //其返回值为bool
//3.读取数据
qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr);
//data:读取后数据的存放地址
//maxSize:读取的数据最大值
//address:发送者的IP地址
//port:发送者的端口地址
QNetworkDatagram QUdpSocket::receiveDatagram(qint64 maxSize = -1);
//QNetworkDatagram 网络数据管理类
//QHostAddress senderAddress() const; //发送者的IP
//int senderPort() const; //发送者的端口
//QByteArray data(); //接收的数据示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38//1.创建一个UDP对象
udp = new QUdpSocket(this);
//2.发送UDP数据
udp -> writeDatagram(ui -> lineEdit -> text().toUtf8(), QHostAddress("192.168.25.2"), 6666);
//3.接收数据
//3.1绑定UDP socket
if(socket -> bind(QHostAddress::Any, 6666)){
qDebug() << "绑定成功";
}
else{
qDebug() <<"绑定失败";
}
//3.2关联可读信号
connect(udp, SIGNAL(readyRead), this, SLOT(readPendingDatagrams));
//3.3接收发送端的数据
void readPendingDatagrams()
{
qDebug() << "有数据可读";
//方法一
char buf[1024] = {0};
QHostAddress ip;
unsigned short port = 0;
socket -> readDatagram(buf, 1024, &ip, &port);
qDebug() << buf;
//方法二
while (udpSocket->hasPendingDatagrams()) { //判断是否有网络数据
//把所有数据读到datagram
QNetworkDatagram datagram = udpSocket->receiveDatagram();
//输出数据
qDebug() << datagram.senderAddress().toString();
qDebug() << datagram.senderPort();
qDebug() << datagram.data();
}
}
Reference
- 29QT_UDP通信_哔哩哔哩_bilibili【这个视频讲得特别好,是真的想教会你如何思考和学习】
- 基于网络通信的上位机-7.1 qcustomplot绘制折线图_哔哩哔哩_bilibili【这个视频讲得特别适合入门用代码布局界面,讲得很好】