отправить успешно, даже если соединение больше не доступно? - PullRequest
2 голосов
/ 16 ноября 2011

Чего мне не хватает?

У меня очень простой клиент и сервер.Сервер использует recv с таймаутом (используя select) в течение 3 секунд.Затем он shutdown s и close s сокетов и выходов.

Клиент подключается к серверу, спит 30 секунд и отправляет очень короткое сообщение.Отправка составляет около 27 секунд после того, как сервер закрыл сокеты и завершил работу.
И send не дает сбоя ..?Зачем?Почему он не возвращает -1 для ошибки?


Обратите внимание: я обрезал все проверки кодов возврата и удалил все журналы, чтобы сделать это как можно короче.Также я удалил все включения, чтобы сделать это короче.Но это настоящий код.

код клиента:

int main( int argc, char* argv[] )
{
    addrinfo hints;
    memset(&hints, 0, sizeof hints); // make sure the struct is empty

    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM; // TCP stream sockets

    addrinfo *res;
    getaddrinfo( "127.0.0.1", "1313", &hints, &res );
    int nSocketFD = socket( res->ai_family, res->ai_socktype, res->ai_protocol );
    assert( -1 != connect( nSocketFD, res->ai_addr, res->ai_addrlen) );
    freeaddrinfo( res ); // free the linked-list, we don't need it anymore

    sleep( 30 );
    if( send( nSocketFD, "bla", 4, 0 ) > 0 )
    {
        printf( "Message successfully sent!\n" );
    }   

    close( nSocketFD );

    return 0;
}

и сервер:

int main()
{
    addrinfo hints;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;

    addrinfo *res;  // will point to the results
    getaddrinfo( NULL, "1313", &hints, &res );
    int nSocketFD = socket( res->ai_family, res->ai_socktype, res->ai_protocol );
    bind( nSocketFD, res->ai_addr, res->ai_addrlen );
    freeaddrinfo( res ); // free the linked-list
    listen( nSocketFD, 1 );

    sockaddr_storage their_addr;
    socklen_t addr_size = sizeof( sockaddr_storage );
    int nAcceptedSocket = accept( nSocketFD, (sockaddr*)&their_addr, &addr_size );
    assert( -1 != nAcceptedSocket );

    fd_set fds;
    FD_ZERO( &fds );
    FD_SET( nAcceptedSocket, &fds );
    timeval tv; 
    tv.tv_sec = 3;
    tv.tv_usec = 0;

    if( 0 == select( nAcceptedSocket + 1, &fds, NULL, NULL, &tv) )
    {   
        printf( "recv timeout! Exiting..\n" );
        shutdown( nSocketFD, SHUT_RDWR );
        close( nSocketFD );
        shutdown( nAcceptedSocket, SHUT_RDWR );
        close( nAcceptedSocket );
        return 1;
    }   
    assert( false );
    return 0;
}

Когда я его выполняю, я вижу сообщения для recvтайм-аут и для успешного отправленного сообщения.

Извините за длинный и, вероятно, глупый вопрос.

Ответы [ 2 ]

3 голосов
/ 16 ноября 2011

Как правило, вам нужно читать из сокета, чтобы он заметил, что удаленный конец закрыл соединение.

На странице руководства send (которая просто write, но с флагами):

No indication of failure to deliver is implicit in a send().  Locally
detected errors are indicated by a return value of -1.
1 голос
/ 16 ноября 2011

Вы не закрывали сокет в вашем клиенте - так что это действительный сокет.Со страницы руководства send ()

No indication of failure to deliver is implicit in a send().  Locally detected errors are indicated by a return value of -1.

У нас есть проблема с некоторыми из наших программ - если сетевое оборудование выходит из строя где-то вдоль линии, и оно возвращается снова - тогда любой конец все еще думает, что сокетдопустимо - и без тестов keepalive - оно останется таким.

ДОБАВЛЕНИЕ: посмотрите параметры сокета (man setsockopt и man tcp) SO_KEEPALIVE

со страницы руководства TCP tcp_keepalive_intvl (integer;по умолчанию: 75; начиная с Linux 2.4) Количество секунд между пробами поддержания активности TCP.

   tcp_keepalive_probes (integer; default: 9; since Linux 2.2)
          The  maximum  number  of  TCP  keep-alive  probes  to  send before giving up and killing the connection if no response is obtained from the other end.

   tcp_keepalive_time (integer; default: 7200; since Linux 2.2)
          The number of seconds a connection needs to be idle before TCP begins sending out  keep-alive  probes.   Keep-alives  are only  sent when the SO_KEEPALIVE socket option is enabled.  The default value is 7200 seconds (2 hours).  An idle connection is terminated after approximately an additional 11 minutes (9 probes an interval of 75  seconds  apart)  when  keep-alive is enabled.

          Note that underlying connection tracking mechanisms and application timeouts may be much shorter.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...