2015-12-30 4 views
1

У меня есть следующий код, который просто создает udp socket для прослушивания в группу многоадресной передачи.select() не удается при добавлении флага m32 в Makefile

Я скомпилирую его с помощью gcc, с флагами -c -g, на машине x64. При добавлении -m32 флага ссылки & компиляции фазы в Makefile, выберите() вызова неудача с недопустимым аргументом.

После отладки немного и без флага, я обнаружил, что с помощью флага я получить все то же значение для всех переменных, за исключением:

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; 
} 
+0

Почему вы используете 'select (sock_no + 1 ...' вместо 'select (sock_no ...'? – ryyker

+0

@ryyker , потому что выбор идет за nfds descriptos (от 0 до nfds -1), в соответствии с: http://www.freebsd.org/cgi/man.cgi?select (см линий 5-6 in ОПИСАНИЕ) – Adiel

+0

Я всегда использовал фактическое значение для сокета в этом аргументе. Не видели «-1». Может быть разница в определении сокетов windows для 'select()' Вы на Linux тогда? Я еще не заметил. – ryyker

ответ

4

Вы не устанавливая tv_usec поле тайм-аута аргумента, поэтому он будет содержать некоторое количество мусора (что бы ни случилось быть в стеке, где timeout_value была выделена). Если этот случайный мусор окажется отрицательным числом, вы получите неверную ошибку аргумента EINVAL. Если это будет нормально, вы не будете. Незначительные изменения в вещах (например, с использованием -m32 или нет) будут иметь тенденцию изменять это.

+0

OP еще не подтвердил его, но, похоже, ваш ответ более конкретно решает проблему. – ryyker

+0

@ chris-dodd Возможно, это произойдет, я проверю его позже, когда вы приедете домой. Последний вопрос - Если я хочу, чтобы значение тайм-аута использовало только параметр «tv_sec», что я должен установить в «tv_usec»? будет только 0 будет вызывать какое-либо другое поведение, а не использовать параметр «tv_sec» в качестве значения тайм-аута? Большое спасибо – Adiel

+0

'tv_usec' должно всегда находиться в диапазоне 0..999999 - это для доли второй части, если вы не хотите, чтобы тайм-аут составлял точно целое число секунд. Обратите внимание, что как 'tv_sec', так и' tv_usec' являются целыми числами. –

1

EDIT
ли вы определить максимальное количество ФД-х годов?

В общем, определить максимальное число, а затем передать его, чтобы выбрать:

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)

+0

Это будет ждать всех сокетов до 'sock_no - 1' в соответствии с страницами man. – 1213

+0

@ 1213 - Спасибо, я отредактировал сообщение. – ryyker

+0

Он устанавливает только один сокет ('sock_no') в fd_set, поэтому' sock_no + 1' явно корректен ... –