嵌入式上位机开发入门(五):UDP 编程 ------ Server 端实现
目录
一、前言
大家好,这里是 Hello_Embed 。前几篇我们完成了 TCP 的服务端与客户端编程,本篇开始学习 UDP 通信。UDP 是无连接的传输协议,流程比 TCP 更简单,但需要注意收发函数的使用方式有所不同。
UDP 通信程序代码实现可以结合之前的 TCP 代码以及流程图对比学习,有助于加深理解。
二、UDP Server 通信流程
UDP Server 端只需四个步骤,比 TCP 少了 listen 和 accept:
| 步骤 | 函数 | 说明 |
|---|---|---|
| 1 | socket | 创建套接字 |
| 2 | bind | 绑定 IP、Port |
| 3 | recvfrom / sendto | 收发数据 |
| 4 | close | 关闭套接字 |
与 TCP 最大的区别:UDP 无需建立连接,直接收发数据,使用
recvfrom和sendto替代recv和send。
三、完整代码实现
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);
recvfrom与recv的区别: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 模式下测试更简单,无需手动建立连接:
- 运行
udp_server_test.exe - 打开 SSCOM,选择 UDP 模式 ,端口设置为 8888
- 直接发送数据即可,无需点击连接
依次发送 123 与 abc 进行测试,通信正常:

UDP 不需要像 TCP 那样先建立连接,只需保持端口一致(8888)即可直接通信,这正是 UDP 无连接特性的体现。
六、总结
- SOCK_DGRAM:创建 UDP 套接字的关键参数
- recvfrom:接收数据的同时获取发送方地址
- sendto:向指定地址发送数据
- UDP 无需
listen/accept/connect,流程比 TCP 更简洁
七、结尾
本篇实现了 UDP Server 端程序,下一篇将学习 UDP 客户端编程,完成 UDP 通信的完整闭环。
Hello_Embed 继续带你从原理到实践,掌握嵌入式上位机开发的核心技能,敬请关注~