При чтении данных в кусках, скажем, 1024, как мне продолжать читать из сокета, который получает сообщение размером более 1024 байт, пока не осталось данных? Должен ли я просто использовать BeginReceive только для чтения префикса длины пакета, а затем как только он будет извлечен, используйте Receive() (в потоке async), чтобы прочитать остальную часть пакета? Или есть другой способ?
изменить
Я думал, что ссылка на Jon Skeet имеет решение, но есть немного паролей с этим кодом. Используемый мной код:
public class StateObject
{
public Socket workSocket = null;
public const int BUFFER_SIZE = 1024;
public byte[] buffer = new byte[BUFFER_SIZE];
public StringBuilder sb = new StringBuilder();
}
public static void Read_Callback(IAsyncResult ar)
{
StateObject so = (StateObject) ar.AsyncState;
Socket s = so.workSocket;
int read = s.EndReceive(ar);
if (read > 0)
{
so.sb.Append(Encoding.ASCII.GetString(so.buffer, 0, read));
if (read == StateObject.BUFFER_SIZE)
{
s.BeginReceive(so.buffer, 0, StateObject.BUFFER_SIZE, 0,
new AyncCallback(Async_Send_Receive.Read_Callback), so);
return;
}
}
if (so.sb.Length > 0)
{
//All of the data has been read, so displays it to the console
string strContent;
strContent = so.sb.ToString();
Console.WriteLine(String.Format("Read {0} byte from socket" +
"data = {1} ", strContent.Length, strContent));
}
s.Close();
}
Теперь это исправление отлично работает отлично, но оно терпит неудачу, когда размер пакета кратен буферу. Причина этого заключается в том, что буфер заполняется при чтении, предполагается, что имеется больше данных; но та же проблема возникает, как и раньше. 2-байтовый буфер, для exmaple, заполняется дважды в 4-байтовом пакете и предполагает, что есть больше данных. Затем он блокируется, потому что читать нечего. Проблема заключается в том, что функция приема не знает, когда заканчивается пакет.
Это заставило меня подумать о двух возможных решениях: я мог либо иметь разделитель конца пакета, либо я мог бы прочитать заголовок пакета, чтобы найти длину, а затем получить именно эту сумму (как я изначально предложил).
Есть проблемы с каждым из них. Мне не нравится идея использования разделителя, так как пользователь может каким-то образом работать в пакете во входной строке из приложения и вкручивать его. Это также просто кажется мне неаккуратным.
Заголовок длины звучит нормально, но я планирую использовать протокольные буферы - я не знаю формат данных. Есть ли длина заголовка? Сколько байтов это? Будет ли это то, что я реализую сам? Etc..
Что мне делать?