Получение фрагментированных данных из сокета в один буфер

StackOverflow https://stackoverflow.com/questions/816350

  •  03-07-2019
  •  | 
  •  

Вопрос

Я пытаюсь написать простой клиент 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).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top