Я использую только один экземпляр SocketAsyncEventArgs для всех своих нужд. Я просто сбрасываю буфер между каждым запросом (устанавливая его в новый байт []).
Как только я подключился и получил ссылку на сокет, я начинаю слушать так:
public void StartListening(SocketAsyncEventArgs e)
{
ResetBuffer(e);
e.Completed += SocketReceive;
socket.ReceiveAsync(e);
}
У меня есть вспомогательная функция, которая сбрасывает буфер:
private void ResetBuffer(SocketAsyncEventArgs e)
{
var buffer = new Byte[SocketBufferSize];
e.SetBuffer(buffer, 0, SocketBufferSize);
}
Я обрабатываю данные как:
private void SocketReceive(Object sender, SocketAsyncEventArgs e)
{
ProcessData(e.Buffer, 0, e.BytesTransferred);
ResetBuffer(e);
socket.ReceiveAsync(e);
}
В ProcessData вы можете использовать байтовый массив по мере необходимости для извлечения данных. Я использую его для создания MemoryStream, который затем десериализуем в свой класс (аналогично ClientPacket) следующим образом:
private void ProcessData(Byte[] data, Int32 count)
{
using (var stream = new MemoryStream(data, 0, count))
{
var serializer = new XmlSerializer(typeof(ClientPacket));
var packet = serializer.Deserialize(stream);
// Do something with the packet
}
}
Что касается вашего последнего вопроса. Каркас обрабатывает все, что связано с базовым протоколом TCP и т. Д., Поэтому вы можете рассчитывать на то, что обработчик событий вызывается всякий раз, когда есть данные для обработки. Используйте значение e.BytesTransferred, чтобы указать объем данных, которые вы фактически получили, который может быть меньше, чем размер буфера, но никогда не будет превышать его (SocketBufferSize в моем коде). Если сообщение было больше размера буфера, инфраструктура TCP будет буферизировать сообщения и отправлять их вам порциями на основе SocketBufferSize (вызывая событие один раз для каждого фрагмента). Если это проблема, просто увеличивайте SocketBufferSize до тех пор, пока большая часть вашего сообщения не будет получена за один блок.
Недостатком блока является то, что сообщения могут объединяться инфраструктурой, что означает, что вам может понадобиться способ узнать, когда закончилось первое сообщение. Типичные подходы включают предварительное добавление к вашему сообщению 4-байтового целого числа, которое указывает длину сообщения. Я могу уточнить, если нужно.
Надеюсь, это поможет.