QT UDP数据传输

(一)计算机网络

通过某种方式将多台计算机进行连接,实现多台计算机彼此之间的互联以及数据的交换。即在不同的计算机上编写一些实现了网络连接的程序,这些程序可以实现位于同一个网络中的计算机之间的数据的交换。

(二)网络通信协议

同一个网络中的计算机进行连接和通信时的规则,目前应用最广泛的是TCP/IP协议(包括,IP协议、TCP协议,UDP协议,ICMP协议等)。在进行数据传输时,要求发送的数据与接收到的数据完全一样,这时,就需要在原有的数据上添加很多信息,以保证数据在传输过程中数据格式完全一致。TCP/IP协议的层次分为4层。

应用层--如 HTTP、FTP、DNS           

主要负责应用程序的协议,如HTTP协议,FTP协议。

传输层--如 TCP、UDP            

主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。            

网络层-- 如 IP协议,ICMP、IGMP             

整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。

链路层-- 如 驱动程序,接口             

用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤,双绞线的驱动。

(三)UDP协议与TCP协议

传输层协议主要使网络程序进行通信。

UDP(用户数据协议):无连接通信协议数据传输时,数据的发送端和接收端不建立逻辑连接。即当一台计算机向另一台计算机发送数据时,数据的发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。所以利用UDP进行网络通信,只要知道对方的IP地址和端口号就可以了。

优点:UDP协议消耗资源小,通信效率高。(音频,视频的传送)

TCP(传输控制协议):面向连接的通信协议即在传输数据前先在发送端和接收端简单逻辑连接,然后再传输数据,它提供两台计算机之间可靠无差错的数据传输(下载文件)。在TCP连接中必须明确客户端与服务器端,由客户段向服务器端发出连接请求,每次连接,需要经过”三次握手“。

第一次:客户端向服务器发出连接请求,等待服务器确认。

第二次:服务器端向客户端回送一个响应,通知客户端收到了连接请求。

第三次:客户端再次向服务器端发送确认信息,确认连接。    

(四)IP地址和端口号

IP地址:它可以唯一标识一台计算机。

端口:在计算机中,不同的应用程序通过端口号来区分,通过IP地址连接到计算机后,如果想要访问计算机中的某个应用程序,还需要指定的端口号。

(五)UDP单播、广播和多播

单播用于两个主机之间的端对端通信。广播用于一个主机对整个局域网上所有主机上的数据通信。单播和广播是两个极端,要么对一个主机进行通信,要么对整个局域网上的主机进行通信。实际情况下,经常需要对一组特定的主机进行通信,而不是整个局域网上的所有主机,这就是多播的用途。

(六)Qt中实现

Qt中提供了QUdpSocket 类进行UDP数据报(datagrams)的发送和接收。首先需要了解一个名词Socket,即“套接字”。Socket简单地说,就是一个IP地址和一个port端口。因为我们要传输数据,就要知道往哪个机子上传送,而IP地址确定了一台主机。但是这台机子上可能运行着各种各样的网络程序,我们要往哪个程序中发送呢?这时就要使用一个端口来指定UDP程序。所以,Socket指明了数据报传输的路径。

QT中提供的SOCKET完全使用了类的封装机制,使用户不需要接触底层的各种结构体操作。而且它采用QT本身的signal-slot机制,使编写的程序更容易理解。

(七)代码实现

如果使用同一台主机进行测试,即该主机既是客户端又是服务端。程序运行时,先运行服务端程序,再运行客户端程序,发送数据,服务器端的窗口就可以显示接收到的数据。

本文只介绍单播,实现两台主机之间UDP数据传输。

服务器端建立一个UDP Socket并绑定在固定端口后,用信号与槽的方式进行监听是否有数据来临。

实例主要功能是:客户端既发送数据,服务器接收之后,将接收到的数据再发送给客户端。

需要在pro文件中添加:QT += network

客户端代码:

头文件:

#include <QUdpSocket>

QUdpSocket *socket;

 源文件:

socket = new QUdpSocket();
//采用信号与槽的方式进行监听是否有数据来临,readyRead()信号是每当有新的数据来临时就被触发
QObject::connect(socket, &QUdpSocket::readyRead, this, &MainWindow::socket_Read_Data);
//因为客户端也要接收服务器发送的数据,所以客户端也需要bind本机的IP地址和端口号
if(socket->bind(QHostAddress("192.168.0.10"),5000)>0);
    qDebug()<<"bind sucess";
//-------------“发送数据”按键,将数据发送到服务器端----------//
void MainWindow::on_pushButton_send_clicked()
{
    qDebug()<<"send:";
    QByteArray msg = "Hello world";
    //向特定IP发送, writeDatagram发送成功返回字节数,否则-1
    QHostAddress serverAddress = QHostAddress("192.168.0.11");
    if(socket->writeDatagram(msg.data(),msg.size(),serverAddress,5000)>0)
        qDebug()<<"write is ok";
    else
    {
	//可调用error()函数,查看bind不成功的原因
        qDebug()<<socket->error();
        qDebug()<<"write is failed";
    }
}
//------------读取服务器发送的数据-------------//
void MainWindow::socket_Read_Data()
{
    QByteArray array;	
   //pendingDatagramSize为返回第一个在等待读取报文的size,resize函数是把array的size归一化到参数size的大小一样	
   //将读取到的不大于array.size()大小数据输入到array.data()中,array.data()返回的是一个字节数组中存储数据位置的指针
    while(socket->hasPendingDatagrams())
    {
        array.resize(socket->pendingDatagramSize());
        socket->readDatagram(array.data(), array.size());
        qDebug()<<array.data();
    }
}

服务器端代码:

头文件:

#include <QUdpSocket>

QUdpSocket *uSocket;

 源文件:

uSocket = new QUdpSocket;
//服务器套接字绑定本地地址和端口
if(uSocket->bind(QHostAddress("192.168.0.11"), 5000)>0)
   qDebug()<<"bind sucess";
else
{
   qDebug()<<uSocket->error();
   qDebug()<<"bind failed";
}
//服务器采用信号与槽的方式进行监听是否有数据来临
connect(uSocket, SIGNAL(readyRead()), this, SLOT(receive()));

void MainWindow::receive()
{
    QByteArray array;
    QHostAddress address;
    quint16 port;
    array.resize(uSocket->bytesAvailable());//根据可读数据来设置空间大小
    //读取数据,获取客户端的IP地址和端口号
    int tmp = uSocket->readDatagram(array.data(),array.size(),&address,&port); 
    qDebug()<<array.data();
    //如果接收成功的话,将接收的数据发送给客户端
    if(tmp > 0)
        uSocket->writeDatagram(array.data(),QHostAddress(address),5000);
}

(八)是否bind

原因:因为服务器是时时在监听有没有客户端的连接,如果服务器不绑定IP和端口的话,客户端上线的时候怎么连到服务器呢,所以服务器要绑定IP和端口,而客户端就不需要了,客户端上线是主动向服务器发出请求的,因为服务器已经绑定了IP和端口,所以客户端上线的就向这个IP和端口发出请求,这时因为客户开始发数据了(发上线请求),系统就给客户端分配一个随机端口,这个端口和客户端的IP会随着上线请求一起发给服务器,服务收到上线请求后就可以从中获起发此请求的客户的IP和端口,接下来服务器就可以利用获起的IP和端口给客户端回应消息了。

1、采用TCP通信时,客户端不需要bind()本机的IP和端口号,而服务器必须要bind()机的IP和端口号;

2、若采用UDP通信时,无论服务器还是客户端,只要接收数据,就需要bind()本机的IP和端口号。

(九)QtQHostAddress 类的使

使用Qt获取本机IP地址的相关接口。

简述:

QHostAddress类提供一个IP地址。

这个类提供一种独立于平台和协议的方式来保存IPv4和IPv6地址。

QHostAddress通常与QTcpSocket、QTcpServer、QUdpSocket一起使用,来连接到主机或建立一个服务器。

可以通过setAddress()来设置一个主机地址,使用toIPv4Address()、toIPv6Address()或toString()来检索主机地址。你可以通过protocol()来检查协议类型。

注意: QHostAddress不做DNS查询,而QHostInfo是有必要的。

这个类还支持通用的预定义地址:Null、LocalHost、LocalHostIPv6、Broadcast和Any。

常用接口:

枚举 QHostAddress::SpecialAddress:

  //获取本地主机地址
  QHostAddress address = QHostAddress(QHostAddress::LocalHost);
  QString strIPAddress = address.toString();
  qDebug()<<"strIPAddress:"<<strIPAddress;

参考博文链接:

https://blog.csdn.net/weixin_42216430/article/details/80780297

https://blog.csdn.net/qq_36183935/article/details/74923736

https://blog.csdn.net/y____xiang/article/details/80529993

https://blog.csdn.net/suxinpingtao51/article/details/11809011

https://blog.csdn.net/iamplane/article/details/70738406

猜你喜欢

转载自blog.csdn.net/weixin_38621214/article/details/86539570