嵌入式上位机开发入门(五):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 继续带你从原理到实践,掌握嵌入式上位机开发的核心技能,敬请关注~

相关推荐
JNX_SEMI13 小时前
EG2226 全桥驱动芯片技术解析:600V/1A 耐压、SSOP16 封装,助力逆变器与无刷电机驱动设计
单片机·嵌入式硬件·物联网
longxiangam14 小时前
esp-idf 中 mipi dsi 使用的笔记
笔记
EntyIU14 小时前
JVM内存与GC笔记
java·jvm·笔记
星恒随风15 小时前
C语言数据结构排序算法详解(下):冒泡排序、快速排序、归并排序和计数排序
c语言·数据结构·笔记·学习·排序算法
周周记笔记16 小时前
【元器件专题】用阻抗等效分析法来分析开关电路
单片机·嵌入式硬件
iCxhust16 小时前
如何利用iret修改cs ip
汇编·单片机·嵌入式硬件·微机原理·8088单板机
米小葱16 小时前
【学习笔记】cmake
笔记·学习
m0_3771081417 小时前
stm32平衡车
stm32·单片机·嵌入式硬件
小+不通文墨18 小时前
把树莓派外接的DHT11接收的温湿度发送到emqx上
经验分享·笔记·嵌入式硬件·学习·树莓派