概述

1目标地址和目标端口都是自己写的,绑定端口也是自己写的
2udp是无连接传输,每个客户机都有一个自己的socket
3.每一个客户机的socket中在开始连接之前都要写本机的信息(本机IP,端口,想要的目标机的ip和端口等)和想要发的内容
4.当每个客户机都完善自己的socket后,每个客户机的socket都自动在网络中寻找对应的socket,并见面后自动更新数据把对方的信息放在自己里面
5.这样一来只要socket里的信息增加了就可以去读取里面的对方的内容

步骤

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
   1.头文件
include <QMainWindow>
include<QLabel>
include<QUdpSocket>
1 定义udp的socket
QUdpSocket *udpSocket;
2 实现槽函数
private slots:
//自定义槽函数

//状态改变
void onSocketStateChange(QAbstractSocket::SocketState socketState);
//读取socket传入的数据
void onSocketReadyRead();

//点击绑定
void on_actStart_triggered();
//点击解绑
void on_actStop_triggered();
//点击发送
void on_btnSend_clicked();
//点击清空文本
void on_action_3_triggered();
//点击广播
void on_btnBroadcast_clicked();

函数实现过程

一 完善socket信息
1.绑定端口void on_actStart_triggered();
2.向socket写入目标ip,目标端口和发送内容void on_btnSend_clicked();
主要是socket里的writeDatagram写入(eg: //socket里放入目标ip目标端口和发送的消息
udpSocket->writeDatagram(str,targetAddr,targetPort);)
二读取收到的数据 void onSocketReadyRead();
若socket有新数据返回,则自动产生readyRead()信号
若socket有新数据则socket里的hasPendingDatagrams()会返回1
通过socket里的readDatagram()函数可以读取对对方的信息(包括IP,端口)
三 解除端口绑定不再连接void on_actStop_triggered();
socket里有abort()函数可以消灭连接
四若实现广播,第二步在写socket时writeDatagram(发送内容,QHostAddress::Broadcast,目标端口);//指明了方式Broadcast,所以没写目标IP

函数代码

获取本机ip

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 QString MainWindow::getLocalIp()
{ //获取本机ip
QString hostName=QHostInfo::localHostName();//本地主机名
QHostInfo hostInfo=QHostInfo::fromName(hostName);
QString localIP="";

QList<QHostAddress> addList=hostInfo.addresses();//

if (!addList.isEmpty())
for (int i=0;i<addList.count();i++)
{
QHostAddress aHost=addList.at(i);
if (QAbstractSocket::IPv4Protocol==aHost.protocol())
{
localIP=aHost.toString();
break;
}
}
return localIP;
}

构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
LabSocketState=new QLabel("Socket状态:");//状态栏标签
LabSocketState->setMinimumWidth(200);
ui->statusBar->addWidget(LabSocketState);
QString localIp=getLocalIp();//本机IP
this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIp);
//这里只是测试,自己可以输入对方的ip
ui->comboTargetIP->addItem(localIp);
udpSocket=new QUdpSocket(this);
connect(udpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
connect(udpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));

}

读取socket传入的数据

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
void MainWindow::onSocketReadyRead()
{

//读取缓冲区行文本
//有数据报时读取
while(udpSocket->hasPendingDatagrams())
{
//用一个数组接收
QByteArray datagram;
//设置数组大小(根据数据报大小)
datagram.resize(udpSocket->pendingDatagramSize());
//读取对方ip地址
//读取对方端口号
QHostAddress peerAddr;
quint16 peerPort;
//读数据报的数据,大小,对方ip和端口
udpSocket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);
//数据转化类型
QString str=datagram.data();
//对方ip转化类型
//对方端口转化类型
QString peer="来自"+peerAddr.toString()+"的"+QString::number(peerPort)+"端口:";
//显示对方ip,端口
ui->plainTextEdit->appendPlainText(peer);
//显示收到消息内容
ui->plainTextEdit->appendPlainText(str);

}

}

点击绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void MainWindow::on_actStart_triggered()
{ //绑定端口
quint16 port=ui->spinBindPort->value();
//udpSocket->bind(port)绑定端口并返回bool类型
if(udpSocket->bind(port))
{
ui->plainTextEdit->appendPlainText("**已成功绑定");
ui->plainTextEdit->appendPlainText("**绑定端口:"+QString::number(udpSocket->localPort()));
ui->actStart->setEnabled(false);
ui->actStop->setEnabled(true);
}
else{
ui->plainTextEdit->appendPlainText("**绑定失败");
}
}

点击解绑

1
2
3
4
5
6
7
void MainWindow::on_actStop_triggered()
{ //解除端口绑定
udpSocket->abort();
ui->actStart->setEnabled(true);
ui->actStop->setEnabled(false);
ui->plainTextEdit->appendPlainText("**已经解除绑定");
}

点击发送

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void MainWindow::on_btnSend_clicked()
{//点击发送
QString targetIp=ui->comboTargetIP->currentText();
//通过ip生成一个QHostAddress对象
QHostAddress targetAddr(targetIp);
quint16 targetPort=ui->spinTargetPort->value();
QString msg=ui->editMsg->text();
QByteArray str=msg.toUtf8();
//socket里放入目标ip目标端口和发送的消息
udpSocket->writeDatagram(str,targetAddr,targetPort);
ui->plainTextEdit->appendPlainText("[out]"+msg);
ui->editMsg->clear();
ui->editMsg->setFocus();
}

点击广播

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void MainWindow::on_btnBroadcast_clicked()
{ //获取自己写的目标端口
quint16 targetPort=ui->spinTargetPort->value();
//获取自己要发的消息
QString msg=ui->editMsg->text();
//消息换成QByteArray 类型保证不会乱码
QByteArray str=msg.toUtf8();
//向socket里写数据并表明这条数据用来广播
udpSocket->writeDatagram(str,QHostAddress::Broadcast,targetPort);
//显示广播信息(同网段的这个端口都能收到)
ui->plainTextEdit->appendPlainText("本机已发布广播:"+msg);
ui->editMsg->clear();
ui->editMsg->setFocus();
}

点击清空文本

1
2
3
4
void MainWindow::on_action_3_triggered()
{
ui->plainTextEdit->clear();
}

源码:链接:https://pan.baidu.com/s/1Pl-YGquor1JMVlOHI57dog?pwd=waat
提取码:waat