Udp programming - considerations for client and server

There are many tutorials on the Internet. They say that sending sendtoand receiving recvfromcan 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
insert image description here

important point

The contents of our two functions of receiving recvfromand sendingsendto

  1. 参数一: The sending is bound to the sending socket; the receiving is the receiving socket
  2. 参数二: What is sent is the sent array (buffer); what is received is the received array (buffer)
  3. 参数三: What is sent is the size of the sent array (buffer); what is received is the size of the received array (buffer)
  4. 参数四: Don’t worry about it, it’s 0 by default
  5. 参数五: is one SOCKADDR. 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->Rxcome Rx->Txtogether anyway , they can’t Tx->Tx,Rx->Rx

Even with the protection of clients and threads, run()data cannot be sent directly in

Guess you like

Origin blog.csdn.net/yasinawolaopo/article/details/131851294