Программирование сокета C: зависает connect () - PullRequest
3 голосов
/ 16 апреля 2010

Привет всем, я собираюсь вырвать мои волосы. У меня есть этот клиент, который пытается подключиться к серверу, все вроде бы нормально, используя gethostbyname(), socket(), bind(), но при попытке connect() он просто там висит и сервер ничего не видит от клиента. Я знаю, что сервер работает, потому что другой клиент (также в C) может подключиться просто отлично. Что заставляет сервер не видеть это входящее соединение? Я в конце моего ума здесь. Два разных клиента тоже очень похожи, так что я еще больше растерялся.

    if (argc == 2)  {
    host = argv[1];         // server address
}
else    {
    printf("plz read the manual\n");
    exit(1);
}

hserver = gethostbyname(host);
if (hserver)    {
    printf("host found: %p\n", hserver);
    printf("host found: %s\n", hserver->h_name );
}
else    {
    printf("host not found\n");
    exit(1);
}

bzero((char * ) &server_address, sizeof(server_address)); // copy zeroes into string
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(hserver->h_addr);
server_address.sin_port = htons(SERVER_PORT);

bzero((char * ) &client_address, sizeof(client_address)); // copy zeroes into string
client_address.sin_family = AF_INET;
client_address.sin_addr.s_addr = htonl(INADDR_ANY);
client_address.sin_port = htons(SERVER_PORT);

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
    exit(1);
else    {
    printf("socket is opened: %i \n", sockfd);
    info.sock_fd = sockfd;
    rv = fcntl(sockfd, F_SETFL, O_NONBLOCK); // socket set to NONBLOCK
    if(rv < 0)
        printf("nonblock failed: %i %s\n", errno, strerror(errno));
    else
        printf("socket is set nonblock\n");
}

timeout.tv_sec = 0;     // seconds
timeout.tv_usec = 500000; // micro seconds ( 0.5 seconds)
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval));

rv = bind(sockfd, (struct sockaddr *) &client_address, sizeof(client_address));
if (rv < 0)     {
    printf("MAIN: ERROR bind() %i: %s\n", errno, strerror(errno));
    exit(1);
}
else
    printf("socket is bound\n");

rv = connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address));
printf("rv = %i\n", rv);
if (rv < 0)     {
    printf("MAIN: ERROR connect() %i:  %s\n", errno, strerror(errno));
    exit(1);
}
else
    printf("connected\n");

Любые мысли или идеи очень высоко ценятся.

-преобразование

EDIT: Если сокет НЕ установлен на неблокируемый, то он зависает. Если сокет установлен на неблокируемый, то я получаю ERROR connect() 115: Operation now in progress

[EINPROGRESS] O_NONBLOCK установлен для файлового дескриптора сокета, и соединение не может быть немедленно установлено; соединение должно быть установлено асинхронно.

Я также хотел бы упомянуть, что сервер и клиент работают на компьютерах рядом друг с другом, связанных как один маршрутизатор.

Ответы [ 4 ]

3 голосов
/ 16 апреля 2010

Функция gethostbyname() производит адреса в сетевом порядке байтов, поэтому вам не нужно пропускать их через htonl(). Также запись hostent->h_addr является указателем на адрес. Заменить эту строку:

server_address.sin_addr.s_addr = htonl(hserver->h_addr);

с:

memcpy(&server_address.sin_addr, hserver->h_addr, hserver->h_length);
1 голос
/ 16 апреля 2010

Я вижу, вы установили сокет в режим O_NONBLOCK.

Таким образом, connect должен вернуть -1 и установить errno в EAGAIN в соответствии с страницей руководства по подключению .

После этого вы можете узнать, когда установилось успешное соединение, используя select() на сокете.

Это очень распространенный шаблон для управления тайм-аутом соединения (поскольку select() должен быть передан с тайм-аутом).

0 голосов
/ 16 апреля 2010

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

Вы связываете clientocket. Ваш код очень точно привязывает сокет client к фиксированному порту (порту сервера). Это оставляет O / S НЕ свободным в выборе доступного порта для установления соединения ОТ. Если одному процессу выделен порт (он успешно связал () и подключил () к серверу), то другой процесс не сможет использовать этот же порт.

Если нет веских причин для отправки трафика с определенного порта, пусть O / S найдет свободный порт, изменив эту строку

client_address.sin_port = htons(SERVER_PORT);

до

client_address.sin_port = 0;
0 голосов
/ 16 апреля 2010

Проверьте, можете ли вы подключиться к программе telnet (она принимает имя сервера и номер порта). Если это работает, ошибка должна быть в вашем коде. Если telnet также зависает, проверьте настройки брандмауэра.

...