Как я должен обрабатывать неполные буферы пакетов? - PullRequest
4 голосов
/ 15 марта 2010

Я пишу клиент для сервера, который обычно отправляет данные в виде строк по 500 или менее байтов. Однако данные могут иногда превышать это, и один набор данных может содержать 200 000 байтов, для всех клиент знает (об инициализации или значимых событиях). Однако я бы не хотел, чтобы каждый клиент работал с буфером сокета 50 МБ (если это вообще возможно).

Каждый набор данных ограничен нулевым \0 символом. Какую структуру следует искать для хранения частично отправленных наборов данных?

Например, сервер может отправить ABCDEFGHIJKLMNOPQRSTUV\0WXYZ\0123!\0. Я хотел бы обработать ABCDEFGHIJKLMNOPQRSTUV, WXYZ и 123! независимо. Также сервер может отправлять ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890LOL123HAHATHISISREALLYLONG без завершающего символа. Я хотел бы, чтобы этот набор данных хранился где-то для последующего добавления и обработки.

Кроме того, я использую асинхронные методы сокетов (BeginSend, EndSend, BeginReceive, EndReceive), если это имеет значение.

В настоящее время я спорю между List<Byte> и StringBuilder. Любое сравнение двух в этой ситуации было бы очень полезно.

Ответы [ 4 ]

4 голосов
/ 15 марта 2010

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

Кроме того, помните, что TCP - это поток , а не пакет. Таким образом, вы никогда не должны предполагать, что вы получите все, отправленное за один раз в одном чтении.

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

Если у вас есть несколько входящих соединений, вы можете захотеть сделать что-то вроде создания пула буферов и просто вернуть «большие» в пул, когда закончите с ними.

2 голосов
/ 15 марта 2010

Вы можете просто использовать List<byte> в качестве буфера, поэтому .NET Framework позаботится об его автоматическом расширении по мере необходимости. Когда вы найдете нулевой терминатор, вы можете использовать List.RemoveRange(), чтобы удалить это сообщение из буфера и передать его на следующий уровень вверх.

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

(Это очень похоже на ответ Бена С., но я думаю, что байтовый массив немного более устойчив, чем StringBuilder, несмотря на проблемы с кодированием. Декодирование байтов в строку лучше всего выполнить выше, когда у вас будет полный сообщение.)

1 голос
/ 15 марта 2010

Я бы просто использовал StringBuilder и читал по одному символу за раз, копируя и очищая конструктор всякий раз, когда я нажимал на нулевой терминатор.

0 голосов
/ 15 марта 2010

Я написал этот ответ относительно сокетов Java, но концепция та же самая.

Какой лучший способ отслеживать сокет для новых данных и затем обрабатывать эти данные?

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