Parial Write для сокетов в LINUX - PullRequest
1 голос
/ 11 мая 2011

В нашем приложении есть связь между сервером и клиентом. Розетки используются для связи. Мы используем сокеты AF_INET с SOCK_STREAM (TCP / IP). Также эти сокеты находятся в неблокирующем режиме (O_NONBLOCK). Приложение написано на C ++ в UNIX.

В нашей системе Сервер будет писать в сокет, а Клиент будет читать с него. Мы написали код для обработки частичной записи. Если произойдет частичное, мы попробуем еще 30 раз записать все данные.

Наш сервер пытается записать 2464 байта в сокет. В некоторых случаях он не мог записать все данные. Таким образом, сервер попытается написать еще 30 раз, чтобы передать все данные. В большинстве случаев все данные будут записаны в течение 30 попыток. Но иногда даже после 30-ти пенсий сервер не сможет записать все данные. Здесь будет выкидывать ошибку EAGAIN. Проблема возникает на стороне клиента, когда он пытается прочитать эти частично записанные данные.

Считайте, что сервер пытался записать 2464 байта. Но после повторных 30 попыток он мог записать только 1080 байт. Сервер поднимет EAGAIN в этот момент. Клиент пытается прочитать 2464 байта. Команда чтения вернет 2464, и, следовательно, само чтение в порядке. Но полученные нами данные повреждены (только частично записанные данные). Так что клиент вылетает.

Может ли кто-нибудь посоветовать, пожалуйста,

1) Можно ли удалить только частично записанные данные самим сервером. Таким образом, клиент не получит поврежденные неполные данные ». (Мы не можем использовать функцию read () с сервера, чтобы удалить это. Рассмотрим, как сервер успешно записал n сообщений в сокет. Клиент находится в занятом состоянии и не может их прочитать. Затем сервер пытается написать n + 1-е сообщение и Произошла частичная запись. Если мы используем команду чтения с сервера, удаляются все n успешных сообщений. Нам нужно удалить только сообщение Частично остроумие (n + 1-е))

2) Есть ли способ идентифицировать на стороне клиента, что мы прочитали частично написанное сообщение?.

Обратите внимание, что мы сталкиваемся с проблемой частичной записи только в LINUX (REDHAT 5.4). В Solaris система работает нормально (в солярисе либо будут записаны все данные, либо НЕТ данных, которые будут записаны при 30 попытках записи).

Заранее спасибо.

Ответы [ 2 ]

3 голосов
/ 11 мая 2011

В вашем коде что-то ужасно не так.

  • Вы должны вызывать write столько раз, сколько необходимо для передачи всех данных, которые вы хотите, я не вижу причин останавливаться после 30 раз

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

  • что-то не так с принимающей стороной - если вы отправили менее 2464, вы не сможете прочитать эту сумму из клиентского сокета.Вы проверяете значение, возвращаемое read () (т.е. количество прочитанных байтов)?Опять же, на стороне клиента вы должны использовать select() и т. Д. И вызывать read столько раз, сколько необходимо для получения полного сообщения.

1 голос
/ 11 мая 2011

То, что вы видите, является нормальным поведением для неблокирующего сокета. Когда буферы (локальные и удаленные) заполняются, вы получаете частичную запись.

Вы не должны сдаваться после 30 попыток, которые дают EAGAIN / EWOULDBLOCK, но продолжайте попытки. Вы должны использовать select () / poll () или аналогичный, чтобы получать уведомления, когда вы можете возобновить запись, или вы должны просто использовать блокировку вызовов. То, что вы видите разные результаты на Solaris vs RHEL, это просто (не) удача.

  1. Нет, в таком случае вам придется закрыть соединение, и клиенту придется обрабатывать частичные данные.

  2. Нет, если только вы не закроете TCP-соединение. (*)

Если вы всегда отправляете сообщения размером 2464 байта, вы, вероятно, в порядке - но имейте в виду, что TCP - это поток, он не работает с «сообщениями»

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...