Задержка в recv () - PullRequest
       36

Задержка в recv ()

0 голосов
/ 29 октября 2011

У меня есть две программы, которые используют программирование сокетов для связи. Сначала я укажу нет. хмеля относительно того, сколько раз они должны обмениваться сообщениями друг с другом. Каждый раз, когда он получает сообщение, он добавляет к нему свой идентификатор. Следовательно, размер строки увеличивается каждый раз. Моя программа работает нормально для 8000 прыжков, но после того, как она пересекает 8000, хотя программа p1 отправляет строку длиной 16388, p2 определяет, что в сокете есть только 16385, готовых для чтения. Я использую ioctl (), чтобы определить количество символов, готовых для recv () в сокете, и затем записываю его в переменную char * ...

Из-за задержки в send () в p1 и recv () в p2 p2 идентифицирует только 16385 символов в сокете?

Например: Если P1 отправляет длину (16388)

P2 получает только следующую длину (16385)

Ответы [ 2 ]

5 голосов
/ 29 октября 2011

Скажи, я пытаюсь отправить тебе 8 тыкв. Я положил 6 из них на стол. Вы думаете: «Я ожидаю 8 тыкв, а не 6. Я подожду, пока он положит последние две на стол». Я думаю: «Я не хочу, чтобы слишком много тыкв« в полете »сразу. Я подожду, пока он возьмет 2 из 6, прежде чем я положу последние 2 на стол». Застряли. Мы каждый ждем другого. Мы будем ждать вечно.

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

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

0 голосов
/ 29 октября 2011

Возможно, вы достигли лимита буфера ядра.Вероятно, вы можете увеличить SO_RCVBUF на приемнике, и он будет работать так, как вы ожидаете: SIOCINQ в конечном итоге вернет полный размер непрочитанных данных.

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

Вы должны реструктурировать код так, чтобы вам никогда не приходилось спрашивать ядро, сколько байтов доступно.Просто прочитайте до разумного предела (например, 4096) и разберитесь с одним сообщением уровня приложения, разбитым на несколько частей.Если вам нужны длины / границы сообщений, вы ДОЛЖНЫ реализовать их самостоятельно поверх TCP.

Вот несколько глупых кодов для чтения сообщения с заголовком длины:

int ret, len = 0, have_read;
have_read = 0;
while (have_read < sizeof(len)) {
    // This will likely always return sizeof(len) the first time.
    ret = read(fd, ((char*)&len) + have_read, sizeof(len) - have_read);
    if (ret <= 0) {
        // Handle error.
    }
    have_read += ret;
}
char* buf = malloc(len);
if (!buf) {
    // Handle error.
}
have_read = 0;
while (have_read < len) {
    ret = read(fd, buf + have_read, len - have_read);
    if (ret <= 0) {
        // Handle error.
    }
    have_read += ret;
}
// Handle message in buf.
...