2013-02-27 2 views
1

Клиент сообщил об ошибке, которую я не смог понять. Клиент, основанный на TCP, подключается к серверу, с которого он получает данные, редко отправляя что-либо. Обычно все работает отлично, но когда-то в голубой луны ситуация, как это происходит:Каким образом вызов чтения сокета tcp никогда не возвращается

  • сервер отправляет некоторые данные
  • клиент получает данные
  • клиент обрабатывает данные
  • ... и в сервер отправляет тем временем намного больше данных
  • клиент заканчивает обработку
  • клиент пытается прочитать данные из сокета
  • клиент навсегда нависает на первом чтение() заявление после обработки
  • сервер закрывает соединение
  • клиент по-прежнему висит

Вот как установлено соединение TCP (лишен всех журналов, вернуть чеки и т.д.)

ret = inet_pton(AF_INET, conn->address, &addr.sin_addr); 
addr.sin_port  = htons(conn->port); /* Server port */ 
addr.sin_family  = AF_INET; 
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 
connect(sock, (struct sockaddr *) &addr, sizeof(addr)); 

А вот чтение обертка:

int32_t _readn (int fd, uint8_t *vptr, int32_t n) 
{ 
    int32_t nleft; 
    int32_t nread; 
    uint8_t*  ptr; 

    ptr = vptr; 
    nleft = n; 
    while (nleft > 0) { 
    if ((nread = read (fd, ptr, nleft)) < 0) { 
     if (errno == EINTR) { 
     nread = 0; 
     } else { 
     return E_NETWORK_ERROR; 
     } 
    } else if (nread == 0) { 
     break; 
    } 
    nleft -= nread; 
    ptr += nread; 
    } 
    return (n-nleft); 
} 

возможно ли вызов чтения для блокировки навсегда, даже после закрытия соединения?

Есть ли какая-то сложная ошибка в моей обертке, которую я не заметил, что может вызвать это? Должен ли я устанавливать флажки для сокета при подключении?

+1

Есть ли причина, почему не использовать его без блокировки и положить как 'select' на fd вместо этого? – Jite

+0

Нет, их нет. Это может быть решением. Есть несколько других способов, я могу думать, что это было бы хорошим способом. Но я хочу знать источник проблемы. – Dariusz

ответ

4

Источником проблемы является отсутствие данных для чтения чтения. Например. если количество написанных n байтов меньше, чем ожидалось. Это называется блокировкой чтения.

Чтобы узнать, есть ли данные, используйте select, как говорит Jite.

Наконец, вы можете отключить брандмауэр. Некоторые брандмауэры сконфигурированы так, чтобы разрезать соединения, которые были открыты дольше, чем заданное время, например. 30 минут. Наверное, это не то, что у вас есть.

+0

Нет данных = блок не является источником - это результат. Источник остается неоткрытым. – Dariusz

+0

@DariuszWawer Откуда вы получаете 'n'? Как вы знаете, сколько байтов ожидается? – Ben

+0

протокол прикладного уровня предоставляет эту информацию. Сначала я прочитал три байта заголовков для всех сообщений, на основе которых я решаю, сколько данных нужно читать. – Dariusz

2

В результате я использовал функцию на основе выбора, чтобы проверить, доступны ли данные.

Хотя причина таинственной потери данных пока неизвестно (не convirmed не ошибка сервера), это, кажется, сделать трюк:

int32_t isReadDataAvailableOnSocket (int sock, uint32_t waitTimeUs) 
{ 
    fd_set fds; 
    int16_t ret = 0; 
    struct timeval timeout; 
    struct timeval* timeoutPtr = NULL; 

    if (waitTimeUs>0) { 
    timeout.tv_sec = waitTimeUs/1000000; 
    timeout.tv_usec = waitTimeUs % 1000000; 
    timeoutPtr = &timeout; 
    } 

    FD_ZERO (&fds); 
    FD_SET (sock, &fds); 

    ret = select (sock+1, &fds, NULL, NULL, timeoutPtr); 
    if (ret == -1) { 
    WARN("select failed for udp socket=[%d]", sock); 
    return E_NETWORK_ERROR; 
    } 
    if (! FD_ISSET(sock, &fds)) 
    { 
    return E_NO_DATA; 
    } 
    else 
    { 
    return 0; 
    } 
} 
+1

Сети теряют данные. TCP подсчитывает это, используя «кричать об этом снова и снова, пока не приходит», но для достижения успеха может потребоваться неограниченное количество времени, если сеть очень несчастна ... –

+0

@DonalFellows Это не является неограниченным. Попытки тайм-аута и неудача в конечном итоге. – EJP

+0

Неправильная отправка. Сторона приема будет продолжать ждать навсегда. –

Смежные вопросы