手记

网络通讯核心原理:TCP vs UDP

在网络编程的世界里,Socket(套接字) 是支持 TCP/IP 协议簇进行双向通信的基本操作单元。它就像是不同主机进程间通信的端点。在实际开发中,我们最常接触的是 TCPUDP 两种协议,它们的性格截然不同:

1. TCP (传输控制协议):可靠的“电话”

  • 面向连接:通信前必须先建立连接(三次握手),通信结束后断开连接(四次挥手)。
  • 可靠传输:通过确认应答、超时重传、错误校验机制,保证数据不丢失、不重复、按序到达。
  • 适用场景:文件传输、指令交互、数据上报等对完整性要求高的场景。

2. UDP (用户数据报协议):高效的“广播”

  • 无连接:发送数据前不需要建立连接,资源消耗小,传输效率高。
  • 不可靠:不保证数据一定送达,也不进行重传,数据包大小限制在 64KB 以内。
  • 适用场景:音视频流媒体、即时通讯、广播通知、DNS 查询等对实时性要求高、允许少量丢包的场景。

核心区别对比表

特性 UDP (无连接) TCP (面向连接)
连接方式 无需建立连接,随时发送 必须先建立连接才能通信
可靠性 不保证,可能丢包 可靠,确保数据完整有序
传输效率 高,头部开销小 相对较低,有复杂的控制机制
资源占用
通信模式 支持一对一、一对多(广播/多播) 仅支持一对一(点对点)

💻 实战开发:嵌入式鸿蒙下的 Socket 编程

基于嵌入式开发环境(OpenHarmony + LwIP),以下是 TCP/UDP 客户端与服务端的核心开发逻辑梳理。

1. TCP 编程实战

TCP 客户端 (Client) 流程:

  1. 创建套接字socket(AF_INET, SOCK_STREAM, 0)
  2. 连接服务端connect() 指定 IP 和端口。
  3. 循环发送/接收:使用 send() 发送数据,recv() 接收数据。

TCP 服务端 (Server) 流程:

  1. 创建套接字socket()
  2. 绑定地址bind() 绑定本地 IP 和端口。
  3. 监听连接listen() 开始监听。
  4. 接受连接accept() 阻塞等待客户端接入,生成新的通信套接字。
  5. 数据收发:通过 accept 返回的 client_fd 进行 recv/send

2. UDP 编程实战

UDP 客户端/服务端 (通用):

  1. 创建套接字socket(AF_INET, SOCK_DGRAM, 0) (注意类型为 DGRAM)。
  2. 配置地址:填充 sockaddr_in 结构体,指定目标 IP 和端口。
  3. 发送数据:使用 sendto() 替代 send,需指定目标地址。
  4. 接收数据:使用 recvfrom() 替代 recv,可获取发送方地址。

UDP 广播 (Broadcast) 特殊配置:
在发送广播前,必须设置套接字选项以开启广播权限:

int yes = 1;
setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (char *) &yes, sizeof(yes));
  • 广播地址:目标 IP 设置为 INADDR_BROADCAST (通常是 255.255.255.255)。

🛠️ 核心代码逻辑参考 (C语言/LwIP)

以下是提炼的通用逻辑伪代码,适用于嵌入式 IoT 开发:

TCP 客户端核心逻辑

// 1. 创建 socket
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);

// 2. 配置服务器地址
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("192.168.1.100"); // 服务端IP
server_addr.sin_port = htons(8080); // 端口

// 3. 建立连接
connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));

// 4. 循环发送
while(1) {
    send(sock_fd, "Hello", strlen("Hello"), 0);
    usleep(1000000); // 1秒
}

UDP 广播核心逻辑

// 1. 创建 UDP socket
int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);

// 2. 启用广播选项
int broadcast_enable = 1;
setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, &broadcast_enable, sizeof(broadcast_enable));

// 3. 配置广播地址
struct sockaddr_in broadcast_addr;
broadcast_addr.sin_family = AF_INET;
broadcast_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); // 广播地址
broadcast_addr.sin_port = htons(8080);

// 4. 循环广播
while(1) {
    sendto(sock_fd, "Broadcast Msg", strlen("Broadcast Msg"), 0, 
           (struct sockaddr*)&broadcast_addr, sizeof(broadcast_addr));
    usleep(1000000);
}

💡 总结与建议

  1. 选型建议

    • 如果你需要传输文件、传感器精确数据,或者需要确保每一条指令都必须被执行,请使用 TCP
    • 如果你在做视频推流、局域网设备发现(广播)、或者对实时性要求极高(如游戏数据同步),请使用 UDP
  2. 调试技巧
    • 开发时务必确保设备与 PC 处于同一局域网(同一热点或路由器下)。
    • 利用 PC 端的“网络调试助手”模拟服务端或客户端,配合串口打印进行双向调试。
0人推荐
随时随地看视频
慕课网APP