UDP通信不需要建立链接,直接通过ip地址和端口的绑定即可实现通信
所以首先我们需要绑定一个端口号,这里我们绑定本地的端口号:
这个是端口号udpsocket->localPort()
port = udpsocket->localPort()
udpsocket->bind(port)
当我们不需要绑定时我们可以使用:
udpsocket->abort();//解除绑定
OK现在我们已经将端口绑定好了,接下来只需要读取数据并且显示出来就行。和TCP协议一样,当有消息传输时会发射readyread()函数,我们在这里需要使用信号槽来联系其readyread()和我们自己的onSocketReadyRead()。用来显示接受的信息
hasPendingDatagrams():表示是否有待读取的传入数据报
QByteArray datagram;
readDatagram(char *data(),qint64 maxsize,QHostAddress *address = Q_NULLPTR,quint16 *port = Q_NULLPTR);
data 和 maxsize是必须的,表示最多读取maxSize字节的数据到变量data里。address和port变量是可选的额,用于获取数据报来源的地址和端口
,最后我们使用一个字符串str来获取datagram.data
udpsocket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);
QString str = datagram.data();
获取了数据信息后如何显示出来就可以自己发挥了。
,这个是接受信息,那么我们如何发送信息呢?和TCP一样,我们发送信息需要address和端口,所以我们这边先获取端口和地址:
QString targetip = ui->lineEdit_target_ip->text();
QHostAddress targetaddr(targetip);
quint16 targetport = ui->lineEdit_target_port->text().toInt();
然后我们将获取的字符串转换成字节流:
QString msg = ui->lineEdit_msg->text();
QByteArray str = msg.toUtf8();
最后我们使用writeDatagram()函数来实现数据的发送:udpsocket->writeDatagram(str,targetaddr,targetport);//发出数据报
这个是端对端的发送,如果我们要广播的话只需要修改writeDatagram()函数即可
udpsocket->writeDatagram(str,QHostAddress::Broadcast,targetport);
至此,UDP发送消息的思路和逻辑完成了。
以下是完整的代码:
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include<QUdpSocket>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
QUdpSocket *udpsocket;
QString getlocalip();
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_act_bind_triggered();
void onSocketStateChange(QAbstractSocket::SocketState socketstate);
void onSocketReadyRead();//读取socket传入的数据
void on_act_Unbind_triggered();
void on_btn_send_msg_clicked();
void on_btn_radio_msg_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QHostInfo>
#include<QHostAddress>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QString ip = getlocalip();
this->setWindowTitle("发送端/接受端B");
ui->lineEdit_target_ip->setText(ip);
udpsocket = new QUdpSocket(this);
connect(udpsocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
connect(udpsocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
}
MainWindow::~MainWindow()
{
delete ui;
}
QString MainWindow::getlocalip()
{
QString ip="";
QString hostname = QHostInfo::localHostName();
QHostInfo hostinfo = QHostInfo::fromName(hostname);
QList<QHostAddress> addlist = hostinfo.addresses();
if(!addlist.isEmpty())
for(int i=0;i<addlist.size();i++)
{
QHostAddress add = addlist.at(i);
if(QAbstractSocket::IPv4Protocol == add.protocol())
{
ip = add.toString();break;
}
}
return ip;
}
void MainWindow::on_act_bind_triggered()
{
//绑定端口
quint16 port = ui->lineEdit_bind_port->text().toInt();//本地UDP端口
if(udpsocket->bind(port))
{
//进入则说明绑定成功
ui->plainTextEdit->appendPlainText("**已成功绑定");
ui->plainTextEdit->appendPlainText("**绑定端口: "+QString::number(udpsocket->localPort()));
ui->act_bind->setEnabled(false);
ui->act_Unbind->setEnabled(true);
}
else
{
ui->plainTextEdit->appendPlainText("**绑定端口失败");
}
}
void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketstate)
{
}
void MainWindow::onSocketReadyRead()
{
//读取收到的数据报
while(udpsocket->hasPendingDatagrams())
{
/*
hasPendingDatagrams()表示是否有待读取的传入数据报
pendingDatagramSize()返回待读取数据报的字节数
readDatagram()函数用于读取数据报的内容。其函数原型:
readDatagram(char *data(),qint64 maxsize,QHostAddress *address = Q_NULLPTR,quint16 *port = Q_NULLPTR);
data 和 maxsize是必须的,表示最多读取maxSize字节的数据到变量data里。address和port变量是可选的额,用于获取数据报来源的地址和端口
*/
QByteArray datagram;
datagram.resize(udpsocket->pendingDatagramSize());
QHostAddress peerAddr;
quint16 peerPort;
udpsocket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);
QString str = datagram.data();
QString peer = "[From "+peerAddr.toString()+": "+QString::number(peerPort)+"]";
ui->plainTextEdit->appendPlainText(peer+str);
}
}
void MainWindow::on_act_Unbind_triggered()
{
//解除绑定
udpsocket->abort();//解除绑定
ui->act_bind->setEnabled(true);
ui->act_Unbind->setEnabled(false);
ui->plainTextEdit->appendPlainText("**已解除绑定");
}
void MainWindow::on_btn_send_msg_clicked()
{
//发送信息按钮
QString targetip = ui->lineEdit_target_ip->text();
QHostAddress targetaddr(targetip);
quint16 targetport = ui->lineEdit_target_port->text().toInt();
QString msg = ui->lineEdit_msg->text();
QByteArray str = msg.toUtf8();
udpsocket->writeDatagram(str,targetaddr,targetport);//发出数据报
ui->plainTextEdit->appendPlainText("[out] "+msg);
ui->lineEdit_msg->clear();
ui->lineEdit_msg->setFocus();
}
void MainWindow::on_btn_radio_msg_clicked()
{
//广播消息
quint16 targetport = ui->lineEdit_target_port->text().toInt();
QString msg = ui->lineEdit_msg->text();
QByteArray str = msg.toUtf8();
udpsocket->writeDatagram(str,QHostAddress::Broadcast,targetport);
ui->plainTextEdit->appendPlainText("[广播消息] "+msg);
ui->lineEdit_msg->clear();
ui->lineEdit_msg->setFocus();
}