嵌入式上位机开发入门(五):UDP 编程 —— Server 端实现

嵌入式上位机开发入门(五):UDP 编程 ------ Server 端实现

目录

一、前言

大家好,这里是 Hello_Embed 。前几篇我们完成了 TCP 的服务端与客户端编程,本篇开始学习 UDP 通信。UDP 是无连接的传输协议,流程比 TCP 更简单,但需要注意收发函数的使用方式有所不同。

UDP 通信程序代码实现可以结合之前的 TCP 代码以及流程图对比学习,有助于加深理解。


二、UDP Server 通信流程

UDP Server 端只需四个步骤,比 TCP 少了 listenaccept

步骤 函数 说明
1 socket 创建套接字
2 bind 绑定 IP、Port
3 recvfrom / sendto 收发数据
4 close 关闭套接字

与 TCP 最大的区别:UDP 无需建立连接,直接收发数据,使用 recvfromsendto 替代 recvsend


三、完整代码实现

cpp 复制代码
#define _WIN32_WINNT 0x0600
#include<iostream>
#include<WinSock2.h>
#include<ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
#define PORT 8888

int main()
{
    WSADATA wsa;
    int iSocketServer;
    struct sockaddr_in tSocketServerAddr;
    struct sockaddr_in tSocketClientAddr;
    int msg_cnt = 0;
    char acRecvBuf[1000];
    if(WSAStartup(MAKEWORD(2,2), &wsa) != 0) return -1;

    //第一步:创建socket
    iSocketServer = (int)socket(AF_INET, SOCK_DGRAM, 0);
    tSocketServerAddr.sin_family = AF_INET;
    tSocketServerAddr.sin_port = htons(PORT);
    tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
    memset(&tSocketServerAddr.sin_zero, 0, sizeof(tSocketServerAddr.sin_zero));

    //第二步:绑定socket
    int iRet = bind(iSocketServer, (const struct sockaddr*)&tSocketServerAddr, sizeof(struct sockaddr));
    if(-1 == iRet)
    {
        printf("bind error\n");
        return -1;
    }

    //第三步:接收数据
    while(1)
    {
        int iAddrLen = sizeof(tSocketClientAddr);
        int iRecvLen = recvfrom(iSocketServer, acRecvBuf, sizeof(acRecvBuf), 0, (struct sockaddr*)&tSocketClientAddr, &iAddrLen);
        if(iRecvLen > 0)
        {
            acRecvBuf[iRecvLen] = '\0';
            char ip[20];
            inet_ntop(AF_INET, &tSocketClientAddr.sin_addr, ip, sizeof(ip));
            printf("Get Msg From %s:%d\n", ip, acRecvBuf);

            //回复
            snprintf(acRecvBuf, 1000, "Get_Msg %d", msg_cnt++);
            iAddrLen = sizeof(tSocketClientAddr);
            sendto(iSocketServer, acRecvBuf, strlen(acRecvBuf), 0, (struct sockaddr*)&tSocketClientAddr, iAddrLen);
        }
    }

    //第四步:关闭socket
    closesocket(iSocketServer);
    return 0;
}

四、代码解析

1. 创建 UDP 套接字

cpp 复制代码
iSocketServer = (int)socket(AF_INET, SOCK_DGRAM, 0);

与 TCP 的区别:SOCK_STREAM 改为 SOCK_DGRAM,表示使用 UDP 数据报模式。

2. 绑定地址

cpp 复制代码
tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
bind(iSocketServer, (const struct sockaddr*)&tSocketServerAddr, sizeof(struct sockaddr));

INADDR_ANY 表示监听本机所有网卡的数据,绑定失败时返回 -1。

3. 接收数据(recvfrom)

cpp 复制代码
int iRecvLen = recvfrom(iSocketServer, acRecvBuf, sizeof(acRecvBuf), 0, (struct sockaddr*)&tSocketClientAddr, &iAddrLen);

recvfromrecv 的区别:recvfrom 会同时获取发送方的 IP 和端口,保存在 tSocketClientAddr 中,这是 UDP 回复数据的关键。

4. 回复数据(sendto)

cpp 复制代码
snprintf(acRecvBuf, 1000, "Get_Msg %d", msg_cnt++);
sendto(iSocketServer, acRecvBuf, strlen(acRecvBuf), 0, (struct sockaddr*)&tSocketClientAddr, iAddrLen);

sendto 需要指定目标地址,这里直接使用 recvfrom 获取到的客户端地址进行回复,实现"收到即回复"的效果。


五、运行与测试

UDP 模式下测试更简单,无需手动建立连接:

  1. 运行 udp_server_test.exe
  2. 打开 SSCOM,选择 UDP 模式 ,端口设置为 8888
  3. 直接发送数据即可,无需点击连接

依次发送 123abc 进行测试,通信正常:

UDP 不需要像 TCP 那样先建立连接,只需保持端口一致(8888)即可直接通信,这正是 UDP 无连接特性的体现。


六、总结

  • SOCK_DGRAM:创建 UDP 套接字的关键参数
  • recvfrom:接收数据的同时获取发送方地址
  • sendto:向指定地址发送数据
  • UDP 无需 listen / accept / connect,流程比 TCP 更简洁

七、结尾

本篇实现了 UDP Server 端程序,下一篇将学习 UDP 客户端编程,完成 UDP 通信的完整闭环。

Hello_Embed 继续带你从原理到实践,掌握嵌入式上位机开发的核心技能,敬请关注~

相关推荐
热水过敏2 小时前
前路迷茫,再次起航
笔记·程序人生·职场和发展
chase。2 小时前
【学习笔记】RoboForge:让文本指令“落地”到人形机器人——一个物理优化与隐式驱动的端到端框架
笔记·学习·机器人
凌盛羽2 小时前
在MDK-ARM编译后用python解析map文件在编译窗口输出Flash和RAM使用及剩余情况
arm开发·python·stm32·单片机·mysql·链表·esp32
chase。2 小时前
【学习笔记】从经典算法到通用神经运动规划器
笔记·学习·算法
牛奶咖啡133 小时前
免费笔记软件且优先本地私有化——Joplin、Obsidian
笔记·obsidian·joplin·待办事项应用程序·开源笔记应用·可私有化本地笔记应用·笔记的同步与插件安装
会飞的大可3 小时前
服务间通信:OpenFeign vs Dubbo 的 RPC 选型
网络协议·rpc·dubbo
松小白song3 小时前
Modbus RTU/TCP 的区别
网络·网络协议·tcp/ip
为爱停留3 小时前
HTTPS 域名访问与 Nginx 全链路说明
网络协议·nginx·https
项目題供诗3 小时前
51单片机入门-红外遥控(十七)
单片机·嵌入式硬件·51单片机