Udp编程 - 客户端和服务端的注意事项

11 篇文章 0 订阅

网上有很多教程,他们说发送使用sendto,接收使用recvfrom就可以,确实如此。但是你会用吗?

我们以QT(C++)为例,来使用这个udp实现自发自收的功能(途中我们会用到QThread来开启我们的线程)

服务端(线程)

#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(){

}

我们这里只是一个接收到数据就打印的案例

客户端(线程)

#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(){

}

这里也没什么,就一个线程

主函数

#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;
}

关于信号和槽这里你只需要知道,我们通过一个ui界面的按键,按下按键触发on_pushButton_network(打开线程和网路)on_pushButton_TestSend(客户端发送固定数据)俩个函数
关于Qt线程 | 关于C++线程
在这里插入图片描述

注意点

我们这个接收recvfrom和发送sendto的俩个函数中的内容

  1. 参数一: 发送的绑定的是发送的socket套接字; 接收的是接收的socket套接字
  2. 参数二: 发送的是发送的数组(缓存);接收的是接收的数组(缓存)
  3. 参数三:发送的是发送的数组(缓存)大小;接收的是接收的数组(缓存)大小
  4. 参数四:先不用管,默认给它0
  5. 参数五: 是一个SOCKADDR注意发送端是发送端绑定的对方地址发送端绑定的对方地址的大小;服务端是服务端绑定的对方(可以是发送端)地址服务端绑定的对方(可以是发送端)地址的大小

在客户端和服务端进行自我绑定的时候,俩个端口要想Tx->Rx,Rx->Tx那样要反正来不能Tx->Tx,Rx->Rx

即便是有客户端和线程的加护,也不能直接在run()中一直发送数据

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

结城明日奈是我老婆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值