c-从错误22中恢复

时间:2015-10-03 11:06:52

标签: c linux sockets linaro

首先,这里是代码:

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

如果这与任何相关性在线程中运行。如果我在Zedboard(ZYNQ-7000 SoC)上编译并运行它,它有一个ARM Cortex A9和Linaro Linux(基于精确的Ubuntu)。它打印错误22,但仍然在recvBuff[0]中收到了值。

使用xubuntu在我的VM中运行它可以正常工作。

错误22等于EINVAL,其被描述为无效参数。

recvfrom(2)的联机帮助页中,它指出EINVAL表示MSG_OOB标志已设置,但我不使用任何标记(传递0)。

在星期五离开之前,我开始进行apt-get升级,因为我希望它是一个有缺陷的库或类似的东西。我可以在星期一回来查看,但也许有人在这里有另一个想法是什么错误。

2 个答案:

答案 0 :(得分:5)

您需要先将cli_len初始化,然后再将其传递给recvfrom()

cli_len = sizeof(cli_addr);

您没有初始化它,因此它具有随机值。如果该值恰好是&lt; sizeof(cli_addr)recvfrom()可能会因EINVAL失败,或者至少截断地址,因为它认为cli_addr不足以接收客户端地址。如果该值远大于sizeof(cli_addr)recvfrom()可能会认为缓冲区超出了有效的内存范围。

您必须告诉recvfrom()实际有多大cli_addr。这在documentation

中明确说明
  

参数addrlen是一个value-result参数,调用者应该在调用与src_addr关联的缓冲区大小之前初始化,并在返回时修改以指示源地址的实际大小。如果提供的缓冲区太小,则截断返回的地址;在这种情况下,addrlen将返回一个大于提供给调用的值。

因此,在调用cli_len之前,您必须使用cli_addr的总大小初始化recvfrom(),然后recvfrom()使用地址大小cli_len更新cli_addr实际上是写入cli_addrsockaddr_storage可以大于地址,例如,当使用cli_len结构接受双栈套接字上的IPv4或IPv6地址时。在问题的示例中,正在使用IPv4套接字,因此必须将sizeof(sockaddr_in)初始化为值> = $path_parts = pathinfo($_SERVER['PHP_SELF']); echo $path_parts['dirname'];

答案 1 :(得分:0)

这不是由操作系统或架构引起的。由于互斥锁被阻塞,因此未在x86系统上调用该函数。所以我没有在那里得到错误。

问题在于我将套接字传递给了来自&#39; main&#39; (我没有在问题中说明,因为我认为这是无关紧要的,我的不好......) 在&#39; main&#39;我使用它并在此功能中使用它。即使它是互斥的,也有这个错误。

雷米的回答也很重要,但不能解决问题。如果它太小,不事先设置cli_len只会导致sockaddr的切割。没有为此生成错误。