Я работаю над проектом на базе Linux, состоящим из «основного» приложения, написанного на C, и веб-сервера, вероятно, написанного на Python. Главный сервер и веб-сервер должны иметь возможность связываться друг с другом через TCP / IP. Я сосредоточен на основном приложении на C.
Из-за разных языков программирования, используемых для ядра и веб-сервера, я ищу протокол сообщений, который легко использовать на обоих языках. В настоящее время я думаю, что JSON - хороший кандидат. Мой вопрос, однако, не столько в протоколе сообщений, сколько в том, как я могу определить количество байтов для чтения из (и, возможно, отправки) сокета, особенно при использовании протокола сообщений, такого как JSON или XML.
Насколько я понимаю, независимо от того, используете ли вы JSON, XML или какой-либо другой протокол сообщений, вы не можете включать размер сообщения в само сообщение, потому что для анализа сообщения вам потребуется все сообщение и, следовательно, нужно знать размер его заранее. Обратите внимание, что под «сообщением» я подразумеваю данные, отформатированные в соответствии с используемым протоколом сообщений.
Я думал и читал о решении этой проблемы и пришел к следующим двум возможностям:
Поскольку все предлагаемые решения, которые я прочитал, не были специально предназначены для использования какого-либо протокола сообщений, такого как JSON, я думаю, что, возможно, я что-то упускаю.
Итак, какая из двух предложенных мной возможностей является лучшей, или я не знаю другого решения этой проблемы?
С уважением.
На самом деле вам нужен протокол высокого уровня, чтобы иметь возможность собирать полное сообщение JSON. Но поскольку JSON ориентирован на текст, вы также можете использовать специальные байты, отличные от ascii, в качестве разделителей сообщений, потому что они не могут быть включены в сообщение JSON.
Или, скорее, не-Unicode, если вы позволяете это. Если вы собираетесь выбрать кодировку текста, вероятно, лучше всего использовать utf-8.
@Gerhardh: Спасибо. Под сообщением я подразумеваю то, что я, как программист, определяю как сообщение. Скажем, размер этого сообщения составляет X байт. Тогда разве не правда, что вы читаете X байтов из сокета блокирующим образом, так что, когда вы заканчиваете чтение, вы читаете X байтов, что является сообщением?
@sudo: JSON кодирует байт не ASCII в ASCII, поэтому UTF8 не имеет значения.
@Vincent в потоках TCP нет корреляции между отдельными вызовами чтения из сокета и пакетами, отправленными по сети. Сам TCP использует это преимущество с помощью алгоритма Нэгла, который очень немного задерживает передачу очень маленьких пакетов в случае, если сразу после этого в очередь ставится другой пакет.
@SergeBallesta неверно - JSON может нести UTF-8 изначально и не кодирует его специально.
@Vincent Я очень рекомендую добавить значение длины сообщения. DNS через TCP делает это, используя двухбайтовое поле длины (отправляемое в двоичном, а не текстовом порядке, в прямом порядке) для максимального размера сообщения 65535 байт. Незначительным недостатком этого является то, что вы должны отображать свои данные в JSON (то есть в память), чтобы вы знали, сколько времени пройдет, прежде чем вы сможете начать их отправку.
@sudo: Вы правы в общем случае. Модуль Python json кодирует символы, отличные от ascii, и json допускает такую кодировку, но сообщение JSON может содержать любой не управляющий символ Unicode.
Я думаю, что строки @SergeBallesta Python 2 по умолчанию являются ASCII. Я забыл, как это работает, потому что я всегда использую 3, где строки - это Unicode, а модуль json кодирует символы Unicode.





Это классическая проблема, с которой сталкиваются потоки, в том числе TCP, часто называемая «проблемой границы сообщения». Вы можете поискать более подробные ответы, чем то, что я могу дать здесь.
Чтобы определить границы, у вас есть несколько вариантов:
{ должен быть закрыт с помощью } в JSON), но я не вижу в этом никаких преимуществ.Если это не просто учебный процесс, вы можете вместо этого использовать существующий протокол, чтобы сделать все это за вас. Например, HTTP (неэффективный) или gRPC (более эффективный).
Изменения: изначально я сказал что-то совершенно неправильное о необходимости включать контрольную сумму для обработки потери пакетов, несмотря на TCP ... TCP не будет продвигаться, пока эти пакеты не будут должным образом получены, так что это не проблема. ИДК, о чем я думал.
Похоже, вы не знаете, как работает TCP. Вы не можете «потерять» такой пакет в TCP. Потерянный пакет будет обнаружен операционной системой и автоматически передан повторно.
Моя беда, я полностью пропустил ошибку и забыл, что TCP не продвинется вперед без получения последнего сообщения. Редактирование ...
@Alnitak В спецификации JSON говорится, что управляющие символы должны быть экранированы, если вы перейдете к tools.ietf.org/html/rfc7159 и выполните поиск «кроме символов, которые должны быть экранированы». Библиотеки C JSON, которые я видел, используют строки с завершающим нулем, как и многие библиотеки в C, и Python выдает ошибку, если вы пытаетесь декодировать строку, содержащую нулевые байты.
Я пропустил бит на json.org, где написано «кроме управляющего символа»! В любом случае, в этом случае я бы все равно не стал использовать разделители.
Добро пожаловать в SO. Вы должны знать, что для TCP / IP нельзя полагаться на получение только одного сообщения. Вы также можете получить менее одного или более одного сообщения, поскольку соединение является потоком. Вы должны подготовиться к чтению части и дождаться получения оставшейся части.