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

news2024/12/26 11:32:40

网上有很多教程,他们说发送使用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()中一直发送数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/789415.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL数据库配置及创建用户和授权

注意&#xff1a; 都是基于MySQL8.0以上版本 1、检查是否安装过sql [rootlocalhost ~]# rpm -[qa](https://so.csdn.net/so/search?qqa&spm1001.2101.3001.7020) | grep mysql[rootlocalhost ~]# rpm -qa | grep [mariadb](https://so.csdn.net/so/search?qmariadb&…

Day 66-68 主动学习之ALEC

代码&#xff1a; package dl;import java.io.FileReader; import java.util.*; import weka.core.Instances;/*** Active learning through density clustering.*/ public class Alec {/*** The whole dataset.*/Instances dataset;/*** The maximal number of queries that …

修改密码和再次确认密码的js和element-ui的使用

<template><div><!-- plan的插槽 --><plan title"修改密码"><!-- 插槽的名字 --><span slot"header">修改密码</span><el-form:model"ruleForm2"status-icon:rules"rules2"ref"rul…

微服务安全简介

​由于其可扩展性、灵活性和敏捷性&#xff0c;微服务架构已经变得越来越受欢迎。然而&#xff0c;随着这种架构的分布和复杂性增加&#xff0c;确保强大的安全措施变得至关重要。微服务的安全性超越了传统的方法&#xff0c;需要采用全面的策略来保护免受不断演变的威胁和漏洞…

Linuxの Shell 函数、$(())、$( )、``与${ }

删除 # 标准定义 function funName () {....[return int;]}# 简写 function 可以省略 funName () {....[return int;] }# 简写 &#xff08;&#xff09; 可以省略 function funName {....[return int;] }## 函数调用 # 直接 函数名即可 无参数 funName # 参数 函数名即…

基本排序算法

目录 一&#xff0c;插入排序 二&#xff0c;希尔排序 三&#xff0c;选择排序 四&#xff0c;冒泡排序 五&#xff0c;快排 5.1 Hoare法 5.2 挖坑法 5.3 指针法 5.4 非递归写法 六&#xff0c;归并排序 6.1 递归 6.2 非递归 一&#xff0c;插入排序 基本思想&…

蓝牙HID配对过程

配对通常调用分两步 &#xff11;. Bluetooth AdapterService.cancelDiscovery btif_dm_cancel_discovery BTfM_CancelInquiry BTA_DM_SEARCH_CANCEL_CMPL_EVT BTM_BLI_INQ_CANCEL_EVT BTM_BLI_INQ_DONE_EVT discovery_state_changed_cb btif_dm_cancel_discovery BTA_DM_SE…

ElasticSearch学习--自动补全

目录 自定义分词器 介绍 配置自定义分词器 拼音分词器的问题​编辑 总结 DSL自动补全查询 RestAPI实现自动补全 自定义分词器 介绍 自定义分词器只在当前库中有效 配置自定义分词器 拼音分词器的问题 总结 DSL自动补全查询 RestAPI实现自动补全

VLAN---虚拟局域网

VLAN— 虚拟局域网 LAN—局域网 MAN—城域网 WAN—广域网 1.一个VLAN相当于是一个广播域 VLAN—通过路由器和交换机协同工作后&#xff0c;将原本的一个广播域逻辑上&#xff0c;拆 分为多个虚拟的广播域。 VLAN配置&#xff1a; 1.创建VLAN VID—VLAN ID------用来区分和…

1、传统锁回顾(Jvm本地锁,MySQL悲观锁、乐观锁)

目录 1.1 从减库存聊起1.2 环境准备1.3 简单实现减库存1.4 演示超卖现象1.5 jvm锁1.6 三种情况导致Jvm本地锁失效1、多例模式下&#xff0c;Jvm本地锁失效2、Spring的事务导致Jvm本地锁失效3、集群部署导致Jvm本地锁失效 1.7 mysql锁演示1.7.1、一个sql1.7.2、悲观锁1.7.3、乐观…

行为型设计模式之观察者模式【设计模式系列】

系列文章目录 C技能系列 Linux通信架构系列 C高性能优化编程系列 深入理解软件架构设计系列 高级C并发线程编程 设计模式系列 期待你的关注哦&#xff01;&#xff01;&#xff01; 现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everythi…

Alluxio技术分析

Alluxio技术分析 Alluxio: A Virtual Distributed File System Alluxio主要解决的基于磁盘的分布式存储层性能低下的问题&#xff0c;通过alluxio提供的分布式内存来加速数据分析。 Alluxio的这种通过内存加速数据的想法其实是有明确的使用场景的&#xff1a; Immutable da…

【安全】web中的常见编码浅析浏览器解析机制

目录 常见编码 一、ASCII码 二、URL编码 三、Unicode编码 四、HTML实体编码 结合编码理解浏览器解析机制 常见编码 一、ASCII码 ASCII (American Standard Code for Information Interchange&#xff0c;美国信息交换标准代码&#xff09; 计算机内部&#xff0…

QString和QByteArray的区别

QString和QByteArray的区别 本质格式转换QString字符串格式化打印长度 本质 QString是对QByteArray的再次封装 QString可以通过char*来构造&#xff0c;也可以通过QByteArray来构造 QByteArray就是char* QString是编码后的char* QString也是封装了字符串, 但是内部的编码为utf…

Linux笔记——搜索命令find、解压缩命令、vi编辑器、用户权限命令、系统信息相关命令讲解

系列文章目录 Linux笔记——磁盘进行分区与挂载介绍 Linux笔记——管道相关命令以及shell编程 Linux笔记——进程管理与网络监控技术讲解​​​​​​ Linux笔记——rpm与yum下载软件命令介绍 文章目录 系列文章目录 准备工作 一 搜索命令—— find 搜索 1.1 目标 1.…

【UE5 多人联机教程】04-加入游戏

效果 步骤 1. 新建一个控件蓝图&#xff0c;父类为“USC_Button_Standard” 控件蓝图命名为“UMG_Item_Room”&#xff0c;用于表示每一个搜索到的房间的界面 打开“UMG_Item_Room”&#xff0c;在图表中新建一个变量&#xff0c;命名为“Session” 变量类型为“蓝图会话结果…

Matlab 点云曲面特征提取

文章目录 一、简介二、实现代码2.1基于k个邻近点2.2基于邻近半径参考资料一、简介 这里基于每个点的邻域协方差来获取点云中具有的曲面几何特征的点,计算方式如下图所示: 二、实现代码 2.1基于k个邻近点 SurfaceVar.m %% *******</

零信任网络架构与实现技术的研究与思考

目前&#xff0c;国外已有较多有关零信任网络的研究与实践&#xff0c;包括谷歌的 BeyondCorp、BeyondProd&#xff0c;软件定义边界&#xff08;Software Defined Perimeter&#xff0c;SDP&#xff09; 及盖特提出的“持续自适应风险与信任评估”等。国内也有不少安全厂商积极…

Unity 性能优化一:性能标准、常用工具

性能标准 推荐耗时&#xff1a; 性能提现到玩家直观感受&#xff0c;就是帧率&#xff0c;为了达到要求的帧率&#xff0c;就要控制CPU的耗时&#xff0c;不同类型的游戏&#xff0c;对帧率要求不一样。下面是推荐耗时&#xff1a; 推荐内存&#xff1a; 避免游戏闪退的重点…

network failed to load response data: no resource with given ide...

Chrome 开发者工具无法显示服务器正常返回的 HTTP 请求 - Failed to load response data 今天做开发时遇到一个问题&#xff0c;Chrome 开发者工具 network 标签里&#xff0c;虽然一个 HTTP 请求已经成功从服务器端返回&#xff0c;但是 Chrome 开发者工具里&#xff0c;仍然…