There are many tutorials on the Internet. They say that sending
sendto
and receivingrecvfrom
can be used, and it is true. But will you use it?
Let's take QT (C++) as an example to use this udp to realize the function of self-sending and self-receiving (we will use QThread to open our thread on the way)
server (thread)
#include "udpserverthread.h"
#include <QDebug>
#include <string>
UdpServerThread::UdpServerThread(QObject *parent)
:QThread(parent)
{
if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0){
qDebug("server init faild");
}
isStop = true;
}
//SOCKET serverSocket
//sockaddr_in serverAddr
//int serverLen = sizeof(serverAddr)
void UdpServerThread::run(){
qDebug() << "server thread is run";
uint8_t recv[896]; //接收字符
isStop = false; //控制循环标志位
while(!isStop){
int size = recvfrom(serverSocket,(char *)recv,sizeof(recv),
0,(SOCKADDR *)&serverAddr,&serverLen); //接收
if(size > 0){
qDebug() << "size:" << size; //打印接收到数据的大小
}
}
}
void UdpServerThread::stop(){
isStop = true;
}
UdpServerThread::~UdpServerThread(){
}
Here we are just a case of printing when data is received
client (thread)
#include "udpclientthread.h"
#include <QDebug>
UdpClientThread::UdpClientThread(QObject *parent)
:QThread(parent)
{
if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0){
qDebug("client init faild");
}
isStop = true;
}
void UdpClientThread::run(){
qDebug() << "client thread is run";
while (!isStop) {
//发送,没什么效果,不用去管
/*int dataSize = sendto(clientSocket,buffer_char,sizeof(buffer),0,
(SOCKADDR *)&clientAddr,clientLen);
if(dataSize <= 0){
closesocket(clientSocket);
}*/
}
}
void UdpClientThread::stop(){
isStop = true;
}
UdpClientThread::~UdpClientThread(){
}
Nothing here, just a thread
main function
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//实例化客户端和服务端(线程)
clientThread = new UdpClientThread;
serverThread = new UdpServerThread;
//信号和槽
connect(ui->pushButton,&QPushButton::clicked,this,&MainWindow::on_pushButton_network);
connect(ui->pushButton_testSend,&QPushButton::clicked,this,&MainWindow::on_pushButton_TestSend);
}
void MainWindow::on_pushButton_network(){
//client
clientThread->clientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
//udpThread->sockWIN: SOCKET sockWIN;
if(clientThread->clientSocket != INVALID_SOCKET){
//INVALID_SOCKET:检查错误以确保套接字是有效的套接字
closesocket(clientThread->clientSocket);//关闭套接字
}
clientThread->clientSocket = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(clientThread->clientSocket == INVALID_SOCKET){
//INVALID_SOCKET:检查错误以确保套接字是有效的套接字
QMessageBox::critical(this, tr("错误"), tr("无法创建 Socket!"));//显示提示
return;
}
clientThread->clientAddr.sin_family = AF_INET;
clientThread->clientAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.191");
clientThread->clientAddr.sin_port = htons(8080);
clientThread->serverAddr.sin_family = AF_INET;
clientThread->serverAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.191");
clientThread->serverAddr.sin_port = htons(5505);
if (bind(clientThread->clientSocket, (sockaddr *)&clientThread->clientAddr,
sizeof(clientThread->clientAddr)) == SOCKET_ERROR)
{
//绑定出错
closesocket(clientThread->clientSocket);
clientThread->clientSocket = INVALID_SOCKET;
QMessageBox::critical(this, tr("错误"), tr("端口无法打开或被占用!"));
return;
}
//server
serverThread->serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
//udpThread->sockWIN: SOCKET sockWIN;
if(serverThread->serverSocket != INVALID_SOCKET){
//INVALID_SOCKET:检查错误以确保套接字是有效的套接字
closesocket(serverThread->serverSocket);//关闭套接字
}
serverThread->serverSocket = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(serverThread->serverSocket == INVALID_SOCKET){
//INVALID_SOCKET:检查错误以确保套接字是有效的套接字
QMessageBox::critical(this, tr("错误"), tr("无法创建 Socket!"));//显示提示
return;
}
serverThread->clientAddr.sin_family = AF_INET;
serverThread->clientAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.191");
serverThread->clientAddr.sin_port = htons(5505);
serverThread->serverAddr.sin_family = AF_INET;
serverThread->serverAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.191");
serverThread->serverAddr.sin_port = htons(8080);
if (bind(serverThread->serverSocket, (sockaddr *)&serverThread->clientAddr,
sizeof(serverThread->clientAddr)) == SOCKET_ERROR)
{
//绑定出错
closesocket(serverThread->serverSocket);
serverThread->serverSocket = INVALID_SOCKET;
QMessageBox::critical(this, tr("错误"), tr("端口无法打开或被占用!"));
return;
}
clientThread->start();
serverThread->start();
}
void MainWindow::on_pushButton_TestSend(){
//发送
uint8_t buffer[896];
uint8_t recv[896];
buffer[0] = 0x66;
buffer[1] = 0xff;
buffer[2] = 0xec;
char *buff_char = reinterpret_cast<char *>(buffer);
char *recv_char = reinterpret_cast<char *>(recv);
int dataSize = sendto(clientThread->clientSocket,buff_char,sizeof(buff_char),0,
(SOCKADDR *)&clientThread->serverAddr,clientThread->serverLen);
qDebug() << "main test send size:" << dataSize;
// int size = recvfrom(serverThread->serverSocket,(char *)recv,sizeof(recv),0,
// (SOCKADDR *)&serverThread->clientAddr,&serverThread->clientLen);
// qDebug() << "main test recv size" << size;
}
MainWindow::~MainWindow()
{
delete ui;
}
About signals and slots , you only need to know here, we pass a button on the ui interface, press the button to trigger on_pushButton_network(打开线程和网路)
and on_pushButton_TestSend(客户端发送固定数据)
two functions
About Qt thread | About C++ thread
important point
The contents of our two functions of receiving
recvfrom
and sendingsendto
参数一
: The sending is bound to the sending socket; the receiving is the receiving socket参数二
: What is sent is the sent array (buffer); what is received is the received array (buffer)参数三
: What is sent is the size of the sent array (buffer); what is received is the size of the received array (buffer)参数四
: Don’t worry about it, it’s 0 by default参数五
: is oneSOCKADDR
. Note that the sender is发送端绑定的对方地址
and发送端绑定的对方地址的大小
; the server is服务端绑定的对方(可以是发送端)地址
and服务端绑定的对方(可以是发送端)地址的大小
When the client and the server are self-binding, if the two ports want to
Tx->Rx
comeRx->Tx
together anyway , they can’tTx->Tx
,Rx->Rx
Even with the protection of clients and threads,
run()
data cannot be sent directly in