2014-11-20 4 views
0

Я пытаюсь использовать сокеты с C. Теперь я пишу серверное программное обеспечение. Мой новый обработчик соединения:C Розетки на Mac OS X

int handle_new_connection(SOCKET *server_socket_descriptor, unsigned int *max_known_socket_descriptor, fd_set *main_socket_set) 
{ 
    const int yes = 1; 

    struct sockaddr_in remote_address; 
    SOCKET new_connection_socket_descriptor; 
    int address_size; 
    char buffer[1000] = {0}; 
    struct hostent *host_entry; 

    address_size = sizeof(struct sockaddr_in); 

    if (SOCKET_ERROR == (new_connection_socket_descriptor = accept((*server_socket_descriptor), (struct sockaddr *)&remote_address, (socklen_t *)&address_size))) 
    { 
     return SOCKET_ERROR; 
    } 

    if (SOCKET_ERROR == setsockopt(new_connection_socket_descriptor, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) 
    { 
     return SOCKET_ERROR; 
    } 

    printf ("Server: new connection from \'%s\' accepted successfully.\n", inet_ntoa(remote_address.sin_addr)); 

    unsigned long remote_address_size = sizeof(remote_address.sin_addr); 

    if (NULL == (host_entry = gethostbyaddr((void *)&(remote_address.sin_addr), (socklen_t)&(remote_address_size), AF_INET))) 
    { 
     closesocket (new_connection_socket_descriptor); 
     printf ("Server: new connection from \'%s\' was immediately closed because of gethostbyaddr() failure.\n", host_entry -> h_addr); 
     return SOCKET_ERROR; 
    } 

    printf("Been here!\n"); 


    return 1; 
} 

Когда новые подключает пользователей (через Telnet) if предложение if (NULL == (host_entry = gethostbyaddr((void *)&(remote_address.sin_addr), (socklen_t)&(remote_address_size), AF_INET))) приносит ошибка: Segmentation fault: 11. Кроме того, этот код отлично работает на Linux. Моей операционной системой является Mac OS X. Как решить эту проблему?

+0

Установка 'SO_REUSEADDR' в принимаемом сокете бесполезна. Какой бы адрес он ни имел, у него уже есть, уже слишком поздно. Что именно вы пытаетесь сделать с этим? – EJP

ответ

2

Вы передаете адрес remote_address_size как параметр lengethostbyaddr(). Этот параметр не должен быть адресом, просто значением длины, напрямую.


Update:

Кроме того, вы не можете быть получение struct sockaddr_in от accept(). Например, если соединение представляет собой соединение IPv6, вы получите struct sockaddr_in6. Самый безопасный подход - использовать struct sockaddr_storage.

В идеале, вы должны переключиться с gethostbyaddr() на getnameinfo(). Последний принимает аргумент struct sockaddr*, на который вы можете указать указатель на struct sockaddr_storage, не заботясь о том, какое семейство адресов оно фактически содержит. Страница руководства содержит пример кода.

Если вы хотите продолжать использовать gethostbyaddr(), вам необходимо изучить поле sa_familystruct sockaddr_storage. Если это AF_INET, вы должны использовать &((struct sockaddr_in*)&remote_address)->sin_addr в качестве первого аргумента. Если это AF_INET6, вы должны использовать &((struct sockaddr_in6*)&remote_address)->sin6_addr. Второй аргумент будет размером одного поля.

Если семья - это что-то еще, вам нужно либо посмотреть, как справиться с этим, либо вернуть ошибку для случая, который не понимается вашим кодом.

+0

Извините, я пока не понимаю. Можете ли вы привести мне пример? –

+0

Код 'if (NULL == (host_entry = gethostbyaddr ((void *) & (remote_address.sin_addr), (socklen_t) remote_address_size, AF_INET)))' также приводит к сбою сервера ... –

+0

Я расширил свой ответ по теории, что вы получаете адрес IPv6, который не вписывается в предоставленную переменную. –