2010-03-15 2 views
3

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

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

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

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

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

ответ

2

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

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

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

+0

Возможно, 'MemoryStream', а не' List '? И 'stream.Seek (0, SeekOrigin.Begin)' вместо 'RemoveRange'. –

+0

Это тоже возможность. Я полагаю, это зависит от того, как структурирован код. Если он обрабатывает сообщение, как только встречается нулевой терминатор, то поиск 0 будет работать нормально. Однако, если он сначала считывает все ожидающие данные сокетов, а затем ищет нулевой ограничитель, поиск 0 будет потерять все после первого сообщения. Я принимал последнее. – EMP

4

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

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

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

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

1

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

+0

Это то, о чем я думал, но я беспокоился, что это будет убийца эффективности. –

+0

Этого не должно быть, он был разработан для эффективной обработки добавленных произвольных строк. –

Смежные вопросы