Страницы

Поиск по вопросам

пятница, 28 февраля 2020 г.

C Socket: Долго сбрасывается соединение

#c #сокет


есть такой код:

int read_s, str_size;
char recive_msg[TEXTSIZE_BUFER];
struct sockaddr_in server, client;

str_size = sizeof(struct sockaddr_in);
server.sin_port = htons(100);
server.sin_addr.s_addr = INADDR_ANY;
server.sin_family = AF_INET;

for (;;) {
    int socket_r = socket(AF_INET, SOCK_STREAM, 0), clnt_r;

    setsockopt(socket_r, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
    setsockopt(socket_r, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
    printf("22\n");

    memset(server.sin_zero, '\0', sizeof(server.sin_zero)); 
    if (bind(socket_r, (struct sockaddr *)&server, sizeof(server)) < 0)
        goto close_socket;

    printf("aa\n");

    listen(socket_r, 10);
    if ((clnt_r = accept(socket_r, (struct sockaddr *)&client, &str_size)) <= 0)
        goto close_socket;

    read_s = recv(clnt_r, recive_msg, TEXTSIZE_BUFER, 0);
    printf("close\n>%s\n", recive_msg);

close_socket:
    setsockopt(socket_r, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
    setsockopt(clnt_r, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
    close(clnt_r);
    close(socket_r);
}


Проблема: Когда софт выполняет SO_REUSEADDR и close(), возвращается в начале и потом
секунд 20-30 циклится на printf("22\n");, только после этого идет дальше. Вопрос такой:
в чем может быть причина?

Изначально у меня задумка была поделить клиент и сервер часть в 2 отдельных потока...и
когда освобождается порт выполняется тот или иной поток.
    


Ответы

Ответ 1



SO_REUSEADDR говорит, что этот сокет можно привязать к адресу, даже если он уже привязан. Делать его перед закрытием сокета - бессмысленно. Изменять эту опцию имеет смысл только, если сокет создан, но ещё не привязан.

Ответ 2



В месте закрытия сокета поменять на следующий код: close_socket: shutdown(clnt_r, SHUT_RDWR); close(clnt_r); shutdown(socket_r, SHUT_RDWR); close(socket_r); } по вкусу, если таймаут закрытия велик на ваш взгляд, можно добавить: close_socket: struct linger lng = { 0, 0 }; if (setsockopt(clnt_r, SOL_SOCKET, SO_LINGER,(void*)(&lng), sizeof(struct linger)) < 0) { perror("set: linger 1"); } shutdown(clnt_r, SHUT_RDWR); close(clnt_r); if (setsockopt(socket_r, SOL_SOCKET, SO_LINGER,(void*)(&lng), sizeof(struct linger)) < 0) { perror("set: linger 2"); } shutdown(socket_r, SHUT_RDWR); close(socket_r); } но лучше искать причину медленного закрытия.. Она легко может быть и на стороне клиента. И в общем, с лингером не все так просто, вы изменяете запланированное поведение системы, в области очереди отправки пакетов. Это не всегда есть правильное решение. Если опция SO_LINGER разрешена, то вызовы close(2) или shutdown(2) приведут к задержке процесса до отправки всех сообщений в очереди сокета или до истечения времени задержки. В противном случае выход из вызовов будет произведен немедленно и закрытие будет произведено в фоновом режиме. Если сокет закрывается как часть вызова exit(2), то задержка всегда происходит в фоновом режиме. Собственно мануал В вашем случае, разумно пересмотреть код, делать bind и listen в цикле непонятно зачем.. система явно против.. :) В цикле надо читать из сокета, и возможно отвечать, уверен что клиент ожидает общения :) Функция accept и read должна быть в цикле, и её удобно обернуть во что то более приемлемое, для выхода из неё в случае ошибки. Попробуйте перейти к более приспособленным оберткам, избегая использование goto, например: do { accept() .... if (error) break; read() ... // другой код if (noerror) break; } while (0); close_socket_code()...

Комментариев нет:

Отправить комментарий