水下ROV双Raspberry Pi UDP跨设备通信故障排查求助
水下ROV UDP跨设备通信故障排查请求
我正在开发一款水下ROV,水面控制单元与ROV各搭载一台Raspberry Pi,二者通过100米光纤传输控制信号、环境数据及视频。选用UDP传输简单ASCII消息,同一Pi上运行客户端与服务端代码通信正常,但部署到不同设备后完全无法通信:
- 试过两台设备分别连接不同DHCP路由器(网段10.0.10.151-155与10.0.10.161-165)
- 试过连接同一路由器
均无通信。已关闭WiFi(原VNC测试网段10.0.0.xxx),使用以太网口通信。当前UDP程序绑定了固定inet_addr地址,每台设备仅用一个端口,怀疑是绑定地址的问题,但没找到明确的双端口使用示例。
以下是使用的UDP服务端与客户端代码:
UDP服务端代码
#include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <stdlib.h> #include <inttypes.h> #include <arpa/inet.h> int main(){ int udpSocket, nBytes; char buffer[1024]; struct sockaddr_in serverAddr, clientAddr; struct sockaddr_storage serverStorage; socklen_t addr_size, client_addr_size; int i; /*Create UDP socket*/ udpSocket = socket(PF_INET, SOCK_DGRAM, 0); /*Configure settings in address struct*/ serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(7891); serverAddr.sin_addr.s_addr = inet_addr("10.0.10.170"); memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); /*Bind socket with address struct*/ bind(udpSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); /*Initialize size variable to be used later on*/ addr_size = sizeof serverStorage; while(1){ /* Try to receive any incoming UDP datagram. Address and port of requesting client will be stored on serverStorage variable */ nBytes = recvfrom(udpSocket,buffer,1024,0,(struct sockaddr *)&serverStorage, &addr_size); /*Send message back to client, using serverStorage as the address*/ sendto(udpSocket,buffer,nBytes,0,(struct sockaddr *)&serverStorage,addr_size); } return 0; }
UDP客户端代码
#include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <stdlib.h> #include <arpa/inet.h> int main(){ int clientSocket, portNum, nBytes; char buffer[1024]; struct sockaddr_in serverAddr; socklen_t addr_size; /*Create UDP socket*/ clientSocket = socket(PF_INET, SOCK_DGRAM, 0); /*Configure settings in address struct*/ serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(7891); serverAddr.sin_addr.s_addr = inet_addr("10.0.10.172"); memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); /*Initialize size variable to be used later on*/ addr_size = sizeof serverAddr; while(1){ printf("Type a sentence to send to server:\n"); fgets(buffer,1024,stdin); printf("You typed: %s",buffer); nBytes = strlen(buffer) + 1; /*Send message to server*/ sendto(clientSocket,buffer,nBytes,0,(struct sockaddr *)&serverAddr,addr_size); /*Receive message from server*/ nBytes = recvfrom(clientSocket,buffer,1024,0,NULL, NULL); printf("Received from server: %s\n",buffer); } return 0; }
核心问题分析与修复步骤
1. 绑定地址错误(最可能原因)
服务端代码绑定了固定IP 10.0.10.170,这意味着socket只会监听这个特定IP的数据包。如果Raspberry Pi的实际以太网IP不是这个值,数据包根本无法被接收。正确做法是绑定到通配地址INADDR_ANY,让socket监听所有可用网络接口的数据包:
// 替换服务端中的绑定地址行 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
2. 客户端目标IP配置错误
客户端代码中设置的目标IP是10.0.10.172,需确认该IP确实是服务端设备的以太网实际IP。可在服务端Pi上执行ifconfig eth0或ip a show eth0查看当前IP。
3. 网络连通性验证(先于代码调试)
修改代码前,先确认两台设备的网络可达性:
- 在客户端Pi上ping服务端IP:
ping 10.0.10.xxx(替换为服务端实际IP) - 使用
nc工具测试UDP连通性:- 服务端运行:
nc -ul 7891 - 客户端运行:
nc -u <服务端IP> 7891,输入文本验证双向传输
- 服务端运行:
4. 防火墙/iptables检查
Raspberry Pi可能默认开启防火墙,阻止UDP端口7891的数据包。执行以下命令临时关闭防火墙(测试用)或开放端口:
# 临时关闭防火墙 sudo iptables -F # 永久开放UDP 7891端口 sudo iptables -A INPUT -p udp --dport 7891 -j ACCEPT sudo iptables -A OUTPUT -p udp --sport 7891 -j ACCEPT
5. 代码优化建议
- 服务端添加错误检查:
bind、recvfrom、sendto调用后检查返回值,用perror打印错误信息 - 客户端
recvfrom不要传NULL作为地址参数,至少传入空的sockaddr结构和长度,避免潜在问题 - 添加超时机制,避免
recvfrom无限阻塞
修改后的服务端关键代码片段:
/*Configure settings in address struct*/ serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(7891); serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 使用通配地址 memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); /*Bind socket with address struct*/ if (bind(udpSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) == -1) { perror("bind failed"); exit(EXIT_FAILURE); }
内容的提问来源于stack exchange,提问作者Dfansler
相关产品推荐
相关产品推荐

