好的,首先是代码:
int recvMast_sock;
struct sockaddr_in serv_addr, cli_addr;
socklen_t cli_len;
if ((recvMast_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
critErr("listen:socket=");
}
fillSockaddrAny(&serv_addr, UDP_NODE_LISTEN_PORT);// fills the sockaddr_in works fine elsewhere
if ((bind(recvMast_sock, (struct sockaddr*) &serv_addr, sizeof serv_addr)) < 0)
{
critErr("listen:bind recv_mast_sock:");
}
recvReturn_i = recvfrom(recvMast_sock, &recvBuff[0], (size_t)1, 0, (struct sockaddr*) &cli_addr, &cli_len);
if(recvReturn_i <0)
printf("recv error%d\n",errno);
critErr
是一个处理错误的函数,它还包括错误的打印和 exit
。
这在线程中运行,如果有任何相关性的话。如果我在具有 ARM Cortex A9 和 Linaro Linux(基于精确的 Ubuntu)的 Zedboard(ZYNQ-7000 SoC)上编译并运行它。它打印错误 22
但在 recvBuff[0]
中仍然有接收到的值。
使用 xubuntu 在我的 VM 中运行它工作正常。
错误 22
等于 EINVAL
,它被描述为无效参数。
在 recvfrom(2)
的联机帮助页中它声明 EINVAL
表示设置了 MSG_OOB
标志,但我没有使用任何标志(传递 0
)。
在星期五离开之前,我开始了 apt-get
升级,因为我希望它是一个错误的库或类似的东西。我可以在星期一回来查看,但也许这里有人有其他想法出了什么问题。
最佳答案
在将 cli_len
传递给 recvfrom()
之前,您需要对其进行初始化:
cli_len = sizeof(cli_addr);
你没有初始化它,所以它有一个随机值。如果该值恰好是 <sizeof(cli_addr)
,recvfrom()
可能会因 EINVAL
而失败,或者至少会截断地址,因为它认为 cli_addr
不够大,无法接收客户端地址。如果该值远大于 sizeof(cli_addr)
,recvfrom()
可能会认为缓冲区超出了有效内存范围。
您必须告诉 recvfrom()
cli_addr
实际上有多大。 documentation 中明确说明了这一点:
The argument addrlen is a value-result argument, which the caller should initialize before the call to the size of the buffer associated with src_addr, and modified on return to indicate the actual size of the source address. The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a value greater than was supplied to the call.
所以你必须在调用recvfrom()
之前用cli_addr
的总大小初始化cli_len
,然后调用recvfrom()
使用实际写入 cli_addr
的地址大小更新 cli_len
。 cli_addr
可以大于地址,例如当使用 sockaddr_storage
结构在双栈套接字上接受 IPv4 或 IPv6 地址时。在问题的示例中,正在使用 IPv4 套接字,因此 cli_len
必须初始化为一个值 >= sizeof(sockaddr_in)
。
关于c- recvfrom 错误 22,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32921833/