2016-12-20 2 views
1

У меня есть два процесса в системе Centos 6 (Linux 2.6.32), которые разговаривают друг с другом через сокет AF_INET/SOCK_STREAM. Когда я стресс тестирую ссылку, разбивая достаточно небольшие пакеты, чтобы заполнить сокет, а затем выйти из процесса отправки, процесс получения теряет последние 3/4 или около того пакетов.Centos 6 пишите в розетку без проблем?

Как только процесс отправки выходит, опрос приемника() начинает возвращать извержения POLLIN | ПОЛРДХУП | POLLERR | POLLHUP. В какой-то момент он не может прочитать полный пакет, который он ожидает (read() возвращает меньшее число, чем длина переданного), а следующее read() возвращает -1 с errno, установленным в ECONNRESET). Мне, конечно, кажется, что он прочитал все данные в трубе, и больше нечего ждать.

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

Я предполагаю, что это означает, что запись write() s отправителя заканчивается тем, что где-то буферизуется, причем этот буфер получает бросок, если он выходит, вместо того, чтобы возвращать сбой. Отключение Nagle (включение TCP_NODELAY) не изменяет этого поведения.

Код, который делает запись является:

iov[0].iov_base = &len; 
iov[0].iov_len = sizeof(uint32_t); 
iov[1].iov_base = buf; 
iov[1].iov_len = len; 
if ((wlen = writev(fd, iov, NELEM(iov))) != (iov[0].iov_len + iov[1].iov_len)) { 
    ... // error handling 

(он посылает длину 32-битного следуют данные).

Может ли кто-нибудь дать мне подсказку о том, что происходит, и как я могу достоверно узнать, преуспели ли мои записи()?

+0

Если вы замените вызов writev() двумя раздельными вызовами write(), проблема исчезнет? (или, если нет, характер проблемы становится более очевидным, если у вас есть доступ к отдельным возвращаемым значениям из каждого из двух вызовов write()?) –

+0

Нет, проблема остается. (Кстати, writev() необходимо, потому что без него будет передан первый 4-байтовый пакет, а затем второй пакет будет удерживаться до тех пор, пока не будет принят ACK (если не установлен NODELAY)). – Jabberwock

+0

@Jabberwock * Кстати, writev() необходимо, потому что без него будет передан первый 4-байтовый пакет, а затем второй пакет будет удерживаться до тех пор, пока не будет принят ACK (если не установлен NODELAY) * Если ' writev() 'является« необходимым », приемник неправильно обрабатывает полученные данные как поток, подлежащий разбивке на ** любую ** точку и, таким образом, подвергается всем видам ошибок. –

ответ

0

Перед закрытием процесса writter, вы должны закрыть чисто сокет с помощью shutdown вызова:

shutdown(fd, SHUT_WR); 

Это будет действовать как немного, как если бы вы промывку сокета.

Вы также можете найти close сокет, см. Этот вопрос: close vs shutdown socket?.

+0

Вызов shutdown() не имеет значительного эффекта (poll() начинает возвращать POLLIN | POLLRDHUP, но никаких других изменений не видно). Он ставит в очередь FIN для сервера (который получает правильное значение, следовательно, POLLRDHUP), но если сокет близок() d после выключения() и до того, как все данные будут переданы, я вижу ту же потерю данных, которые записывают() сообщило, что оно отправлено. – Jabberwock