Получение фрагментированных данных из сокета в один буфер
Вопрос
Я пытаюсь написать простой клиент SNPP (простой протокол сетевого пейджинга), используя сокеты.Кажется, все работает хорошо, за исключением небольшого несоответствия между серверами.
Когда я отправляю команду, мне нужно прочитать ответ, который обычно представляет собой один фрагмент данных.Однако сервер SNPP Sprint отправляет ответы в двух частях.Первый фрагмент данных — это первая цифра кода состояния.Второй кусок — это остаток.Например, когда я пытаюсь получить ответ «Шлюз 220 готов», он приходит следующим образом:
2
Мне нужно отправить еще одну пустую команду, чтобы получить остальное:
20 Gateway ready
На данный момент я использую:
byte[] buffer = new byte[256];
socket.Receive(buffer);
Как я могу быть уверен, что получу все доступные данные после ввода команды, не выделяя отдельный буфер для каждого фрагмента данных?
Решение
Для фрагментированных ответов я бы порекомендовал вам прочитать такие данные:
using (var resultStream = new MemoryStream())
{
const int CHUNK_SIZE = 2 * 1024; // 2KB, could be anything that fits your needs
byte[] buffer = new byte[CHUNK_SIZE];
int bytesReceived;
while ((bytesReceived = socket.Receive(buffer, buffer.Length, SocketFlags.None)) > 0)
{
byte[] actual = new byte[bytesReceived];
Buffer.BlockCopy(buffer, 0, actual, 0, bytesReceived);
resultStream.Write(actual, 0, actual.Length);
}
// Do something with the resultStream, like resultStream.ToArray() ...
}
Другие советы
Попробуйте проверить свойство Socket.Available, чтобы определить, нужно ли вам снова вызывать метод получения.
Я думаю, что понимаю ваш вопрос. Эта перегрузка Socket.Receive позволяет передавать целое число для указания позиция смещения для начала размещения данных. Если вы получили 1 байт, при первом вызове, как в вашем примере, вы можете вызвать эту перегрузку со смещением 1 и использовать тот же буфер.
Socket.Receive
возвращает целое число, которое является количеством полученных байтов. Вы можете проверить, равен ли это 1, и снова вызвать Receive
.
byte[] buffer = new byte[256];
int len = socket.Receive(buffer);
if (len == 1)
socket.Receive(buffer, 1, buffer.Length - 1, SocketFlags.None);
Все,
Когда веб-сервер отправляет данные «кусками», перед каждым фрагментом указывается его длина (в виде строки, указывающей шестнадцатеричное значение).
размером с чан [;
например:разбить 15 байт:
Ф;123456789ABCDEF
Самая большая проблема при получении HTTP-данных из сокета — определение объема данных для чтения:если вы получили все доступные данные и снова вызываете метод Recieve, метод Recieve будет блокироваться до тех пор, пока удаленный сокет не отправит больше данных, чего для соединения HTTP/1.0 никогда не произойдет.
Вам нужно реализовать считыватель, который охватывает сокет;он должен получать данные в буфер и предоставлять метод «ReadLine», который считывает содержимое буфера до тех пор, пока не будет прочитано 13, а затем 10 (CRLF).