C# SocketAsyncEventArgs обработка приема и отправки данных

Я пытаюсь понять класс 'SocketAsyncEventArgs' в C#. http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.aspx

Я следую этому руководству: http://www.codeproject.com/Articles/83102/C-SocketAsyncEventArgs-High-Performance-Socket-Cod

теперь я застрял в том, как именно я должен обрабатывать данные с моим сервером. Я пытаюсь использовать SocketAsyncEventArgs для подключенного клиента с выделенным буферным пространством 512 байт в BufferManager. Затем я хочу декодировать данные byte[] в свой собственный класс (ClientPacket), который содержит byte[] для декодирования и чтения.

Это все хорошо, но мой сервер не всегда отвечает данными вопрос:

использую ли я 1 SocketAsyncEventArgs для приема и цикла обработки данных приема, а затем выделяю SocketAsyncEventArgs из пула, когда мне нужно отправить вернуть его по завершении?

и как SocketAsyncEventArgs знает, когда чтение завершено? (когда он закончит с буфером byte [], прежде чем он запишет его с новыми данными), например, как он возвращается в пул, когда это делается, если я не отвечаю?

1 ответов


Я использую только один экземпляр 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 байта, которое указывает длину сообщения. Я могу рассказать больше, если понадобится.

надеюсь, что это поможет.