2014-01-10 3 views
0

Я использую методы sendto/recvfrom для отправки/получения UDP-пакетов в моем приложении. Теперь мой получить метод заключается в следующем:Почему возвращаемое значение из метода recvfrom равно 4294967295, которое должно быть 0 или -1?

- (void)listenForPackets 
{ 
    int listeningSocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 
    if (listeningSocket <= 0) { 
     NSLog(@"Error: listenForPackets - socket() failed."); 
     return; 
    } 

    // set timeout to 2 seconds 
    struct timeval timeV; 
    timeV.tv_sec = 2; 
    timeV.tv_usec = 0; 

    if (setsockopt(listeningSocket, SOL_SOCKET, SO_RCVTIMEO, &timeV, sizeof(timeV)) == -1) { 
     NSLog(@"Error: listenForPackets - setsockopt failed"); 
     close(listeningSocket); 
     return; 
    } 

    // bind the port 
    struct sockaddr_in sockaddr; 
    memset(&sockaddr, 0, sizeof(sockaddr)); 

    sockaddr.sin_len = sizeof(sockaddr); 
    sockaddr.sin_family = AF_INET; 
    sockaddr.sin_port = htons(18686); 
    sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); 

    int status = bind(listeningSocket, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); 
    if (status == -1) { 
     close(listeningSocket); 
     NSLog(@"Error: listenForPackets - bind() failed."); 
     return; 
    } 

    // receive 
    struct sockaddr_in receiveSockaddr; 
    socklen_t receiveSockaddrLen = sizeof(receiveSockaddr); 

    size_t bufSize = 9216; 
    void *buf = malloc(bufSize); 
    size_t result = recvfrom(listeningSocket, buf, bufSize, 0, (struct sockaddr *)&receiveSockaddr, &receiveSockaddrLen); 

    NSData *data = nil; 

    if (result > 0) { 
     NSLog(@"reslut:%zu",result); 
     if (result != bufSize) { 
      buf = realloc(buf, result); 
     } 
     data = [NSData dataWithBytesNoCopy:buf length:result freeWhenDone:YES]; 

     char addrBuf[INET_ADDRSTRLEN]; 
     if (inet_ntop(AF_INET, &receiveSockaddr.sin_addr, addrBuf, (size_t)sizeof(addrBuf)) == NULL) { 
      addrBuf[0] = '\0'; 
     } 

     NSString *address = [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding]; 
     NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      [self didReceiveMessage:msg fromAddress:address]; 
     }); 

    } else { 
     free(buf); 
    } 

    close(listeningSocket); 
} 

когда я нажмите на одну кнопку я пошлю один UDP вещания и вызвать вышеописанный метод для прослушивания. В начале я не использовал setsockopt(listeningSocket, SOL_SOCKET, SO_RCVTIMEO, &timeV, sizeof(timeV)) для установки тайм-аута в приеме. но при нажатии более одного раза будет ошибка привязки. Возможно, первый из них все еще прослушивает порт и не завершен. поэтому я добавляю второй тайм-аут, чтобы убедиться, что предыдущий закончен. Однако, когда я устанавливаю тайм-аут, значение результата выше, это 4294967295. а затем вызывает сбой в моем приложении. Журнал аварии ниже:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSConcreteData initWithBytes:length:copy:deallocator:]: absurd length: 4294967295, maximum size: 2147483648 bytes' 
*** First throw call stack: 
(0x2ed14e83 0x390716c7 0x2ed14dc5 0x2f64799b 0x2f63fe53 0x2f63fd4d 0x2f64dbab 0x2f64db69 0x13cffb 0x13cdb3 0x395560c3 0x3955b7d9 0x3955b9c5 0x39685dff 0x39685cc4) 
libc++abi.dylib: terminating with uncaught exception of type NSException 

почему возвращаемое значение 4294967295 вместо 0 или -1, если установить тайм-аут? Как это исправить? Любое предложение было бы очень оценено.

ответ

1

Использование не ssize_t size_t

int result = recvfrom(listeningSocket, buf, bufSize, 0, (struct sockaddr *)&receiveSockaddr, &receiveSockaddrLen); 

size_t является тип без знака, -1 будет приведен к 4294967295 (uint_t32). Попробуйте следующий код:

uint32_t i = -1 ; 
NSLog(@"%u", i) ; // you get 4294967295 

метод объявляет, как это:

ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags, 
     struct sockaddr *restrict address, socklen_t *restrict address_len); 

Благодаря @MartinR для коррекции.

+0

спасибо за ваш ответ – chancyWu

+2

Правильный тип: 'ssize_t' (« тип размера подписи »), а не' int'. –

+0

@MartinR Вы правы, спасибо за исправление. – KudoCC

1

size_t is unsigned integer - так что если вы оцениваете -1 - это то, что вы получаете.

Используйте вместо этого обычный «int».

+2

Правильный тип: 'ssize_t' (« тип подписи типа »), а не' int'. –