【问题标题】:select() fails when adding m32 flag to Makefile向 Makefile 添加 m32 标志时 select() 失败
【发布时间】:2016-04-04 20:28:10
【问题描述】:

我有以下代码,它只是创建 udp 套接字来监听 到一个多播组。

我在 x64 机器上使用带有 -c -g 标志的 gcc 编译它。 将 -m32 标志添加到 Makefile 中的链接和编译阶段时, select() 调用因 Invalid Argument 而失败。

在使用和不使用标志进行一点调试之后,我发现 使用标志我得到所有变量的所有相同值,除了:

readfds: 0x80..(重复 31 次) - 带有 -m32 标志

readfds: 0x80..(重复 15 次)- 没有标志

sock.sin_zero: 0x5c, 0xD5, 0xff, 和其他一些带有 -m32 标志的奇怪值

sock.sin_zero: 0x0,0x0,0x20,0x0,0x0 - 没有标志

所有变量的读取都是在文件循环中完成的,就在 FD_SET 之后

我真的不明白为什么它会整体发生变化(作为 32 位程序 假设在 64 位机器上运行得很好),或者为什么 select() 返回 无效参数在这种情况下。

有人可以帮忙吗?

#include <stdio.h>
#include <stdlib.h>
#include <linux/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "radio_listener.h"

int main_loop(int argc, char *argv[])
{
    int sock_no = 0;
    struct sockaddr_in sock;
    socklen_t sock_size;
    fd_set readfds;

    struct ip_mreq mreq_ip;
    uint16_t mreq_port = 0;

    char buffer[BUFF_SIZE];
    struct timeval timeout_value;

    if(VALID_ARGC != argc)
    {
        fprintf(stderr, "usage: %s <mc_address> <udp_port>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    mreq_port = atoi(argv[2]);

    /* Initialize a socket */
    sock_no = socket(AF_INET, SOCK_DGRAM, 0);
    if(sock_no < 0)
    {
        perror("socket() failed!");
        exit(1);
    }
    sock.sin_family = AF_INET;
    sock.sin_addr.s_addr = htonl(INADDR_ANY);
    sock.sin_port = htons(mreq_port);
    sock_size = sizeof(sock);

    bind(sock_no, (struct sockaddr *)&sock, sizeof(sock));

    /* Initialize the Multicast request */
    mreq_ip.imr_multiaddr.s_addr = inet_addr(argv[1]);
    mreq_ip.imr_interface.s_addr = htonl(INADDR_ANY);    

    setsockopt(sock_no, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq_ip, sizeof(mreq_ip));

    while (1)
    {
        timeout_value.tv_sec = TIMEOUT_VAL;
        FD_ZERO(&readfds);
        FD_SET(sock_no, &readfds);
        int retval = select(sock_no+1, &readfds, NULL, NULL, &timeout_value);

        if(-1 == retval)
        {
            perror("select() failed!");
            close(sock);
            exit(1);
        }
        if(0 == retval)
        {
            printf("Timeout - Closing socket and exiting\n");
            break;
        }

        if(recvfrom(sock_no, buffer, BUFF_SIZE, 0, (struct sockaddr *)&sock, &sock_size) < 0)
        {
            perror("recvfrom() failed!");
            close(sock);
            exit(1);
        }

        printf("%s", buffer);
    }

    close(sock);
    return EXIT_SUCCESS;
}

int main(int argc, char *argv[])
{
    int rc = 0;
    rc = main_loop(argc, argv);

    return rc;
}

【问题讨论】:

  • 你为什么用select(sock_no+1...而不是select(sock_no...?
  • @ryyker 因为 select 遍历了 nfds 描述(从 0 到 nfds -1 ),根据:freebsd.org/cgi/man.cgi?select(参见说明中的第 5-6 行)
  • 我一直只是在该参数中使用套接字的实际值。没见过-1。 select() 的 Windows 套接字定义可能有所不同,那么您是在 Linux 上吗?我还没有注意到。
  • @ryyker 是的,当然,抱歉没有提及 - 我在 linux dist (kubuntu) 中,在 64 位架构上
  • Windows (winsock) 忽略第一个参数来选择并测试所有 fd_sets 中的所有描述符。

标签: c linux select makefile 32bit-64bit


【解决方案1】:

您没有设置 timeout 参数的 tv_usec 字段,因此它将包含一些垃圾(无论发生在分配 timeout_value 的堆栈上的什么)。如果该随机垃圾恰好是负数,您将收到EINVAL 无效参数错误。如果碰巧没问题,你就不会。对事物的微小更改(例如是否使用-m32)往往会改变这一点。

【讨论】:

  • OP 尚未确认,但您的回答似乎更具体地解决了这个问题。
  • @chris-dodd 大概就是这个了,等我回家再看看。最后一个问题 - 如果我希望超时值仅使用“tv_sec”参数,我应该在“tv_usec”中设置什么?只有 0 会导致任何其他行为而不是使用“tv_sec”参数作为超时值吗?非常感谢
  • tv_usec 应始终在 0..999999 范围内——如果您不希望超时正好是整数秒,则它是秒的一小部分。注意tv_sec 和tv_usec 都是整数。
【解决方案2】:

编辑
你确定了 fd 的最大数量吗?

一般情况下,确定最大数,然后传给select:

  int maxfd;

  for (i = 0, maxfd = 0; i < nclients; i++)
  {
    FD_SET(sock[i], &read_fds);
    if (sock[i] > maxfd)
        maxfd = sock[i];
  }

  select(maxfd + 1, ........); 

如果您还没有确定 maxfd 是什么,那么它可能有问题。

(来自 discussion here)

【讨论】:

  • 根据手册页,这将等待直到 sock_no - 1 的所有套接字。
  • 他在 fd_set 中只设置了一个套接字(sock_no),所以sock_no + 1 显然是正确的......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-08
  • 2020-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多