一、UDP的特点
UDP(用户数据报协议)是一种简单轻量级、不可靠、面向数据报,无连接的传输层协议。
二、UDP适合应用的几种情况
1、网络数据大多为短消息
2、拥有大量客户端
3、对数据安全性无特殊要求
4、网络负担非常重,但对响应速度要求高。
三、利用UDP进行通信
因为UDP是无连接,所以通信不需要建立连接,只要知道对方的IP地址和端口号就行了。
(1)首先需要绑定端口号,用到bind函数(如果同一台电脑之间测试可以不绑定端口号)
udpsocket->bind(8000);
(2)接收数据部分
接收到数据的时候,socket会自动触发readyRead这个信号,所以需要有一个函数来处理这个信号,也就是读取socket接收到的数据。提供了读取的函数:readDatagram
readDatagram(char *data, qint64 maxSize, QHostAddress *address = Q_NULLPTR, quint16 *port = Q_NULLPTR)
参数详情:
1、将读取的内容存放在data中
2、读取的长度
3、对方的ip地址
4、对方的端口号
(3)发送数据部分
发送数据的步骤和读取数据的步骤差不多的,用到了writeDatagram()这个函数来发送
writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port)
参数详情:
1、需要发送的消息
2、对方的IP地址
3、对方的端口号
贴个小例子:
//创建套接字
QUdpSocket *udpsocket= new QUdpSocket;
//绑定端口
bool result = udpsocket->bind(LocalPort,QUdpSocket::ShareAddress|QUdpSocket::ReuseAddressHint);
if(result)
{
udpsocket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption,1024*1024*8);//设置缓冲区
//连接接收信号槽
connect(udpsocket,SIGNAL(readyRead()),this,SLOT(dataReceived()));
//发送数据 目的地址:serverIP 目的IP:serverPort
QByteArray line;
line.resize(2);
line[0] = 0x02;
line[1] = 0x7d;
udpsocket->writeDatagram(line.data() , QHostAddress(serverIP),serverPort);
void dataReceived()
{
while (udpsocket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(udpsocket->pendingDatagramSize());
udpsocket->readDatagram(datagram.data(),datagram.size());
qDebug()<<"data ;"<
断开连接:
udpsocket->disconnected();
delete udpsocket;
udpsocket= nullptr;
下面介绍udp的组播(Multicast)
组播的原理大致就是服务器往某一组播地址和端口发数据,之后客户端从指定的组播地址和端口去取数据,好处就是减轻了服务器发送的压力,弊就是只要是加入到组播组的用户都可以收到数据,如果往同一组播地址和端口发送数据的话,可能会引起问题。
下面是服务器加入到组播,其实就是用了joinMulticastGroup()函数
QUdpSocket *udpsocket= new QUdpSocket;
//绑定本地端口
udpsocket->bind(QHostAddress::AnyIPv4, multicastPort, QUdpSocket::ShareAddress);
//加入组播组
bool result = udpsocket->joinMulticastGroup(QHostAddress(multicastIP));
if(result)
{
//设置缓冲区
udpsocket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption,1024*1024*8);
//连接接收信号槽
connect(udpsocket,SIGNAL(readyRead()),this,SLOT(dataReceived()));
}
下面就和普通udp连接类似,在槽函数里读取数据,做些想做的操作。
也可以开启多个服务器,用客户端发送数据,所有服务器端都会收到客户端发送的数据。
组播的注意点:
(1)发送端既可以加入组播,也可以不加入组播;
(2)服务端绑定的ip地址必须是ipv4地址,像QHostAddress::Any即是ipv4地址
(3)组播ip必须是D类ip。
贴一点项目的UDP实例代码
#include
class UdpServer:public QObject
{
Q_OBJECT
public:
UdpServer(int port);
virtual ~UdpServer();
//开始监听
bool startListen();
//广播message到port上
static int broadCast(const QString &message, int port);
protected:
virrtual bool doMessage(const QString &data) = 0;
private:
bool init(int port);
private slots:
void readpendingDatagrams();
private:
QUdpSocket * m_socket;
bool m_isInit;
int m_port; //广播端口
};
Udpserver::Udpserver(int port):
m_isInit(false)
{
m_socket = new QUdpSocket(this);
m_port = port;
}
Udpserver::~Udpserver
{
delete m_socket;
}
bool Udpserver::startListen()
{
}
int Udpserver::broadCast(const QString& message, int port)
{
static QUdpSocket udp;
QByteArray datagram = message.toUtf8();
int ret = udp.writeDatagram(datagram .data(), datagram.size(),
QHostAddress::BroadCast, port);
if(!ret)
{
Qstring str = QStringLiteral("发送失败");
}
return ret;
}
bool Udpserver::init(int pot)
{
if(m_socket->bind(QHostAddress::any,port))
{
m_isInit = connect(m_socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagram()));
return m_isInit;
}
return false;
}
void Udpserver::readPendingDatagram()
{
while(m_socket->hasPendingDatagram())
{
QByteArray datagram;
datagram.resize(m_socket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
m_socket->readDatagram(datagram.data(), datagram.size(),
&sender, &senderPort);
if(!domessage(datagram))
{
qDebug()<<"error";
}
}
}