Как использовать буфер на объекте SocketAsyncEventArgs - PullRequest
2 голосов
/ 21 марта 2010

Мы застряли с использованием буферов на объекте SocketAsyncEventArgs.

При старом методе сокета мы приводим наш объект состояния следующим образом:

clientState cs = (clientState)asyncResult.AsyncState;

Однако платформа 3.5 отличается.

Имея строки, поступающие от клиента порциями, и мы не можем понять, как работают буферы, поэтому мы можем обработать всю строку, когда найдем char3.

Код на данный момент:

private void ProcessReceive(SocketAsyncEventArgs e)
{
    string content = string.Empty;

    // Check if the remote host closed the connection.
    if (e.BytesTransferred > 0)
    {
        if (e.SocketError == SocketError.Success)
        {
            Socket s = e.UserToken as Socket;
            //asyncResult.AsyncState;

            Int32 bytesTransferred = e.BytesTransferred;

            // Get the message received from the listener.
            content += Encoding.ASCII.GetString(
                e.Buffer, e.Offset, bytesTransferred);

            if (content.IndexOf(Convert.ToString((char)3)) > -1)
            {
                e.BufferList = null;

                // Increment the count of the total bytes receive by the server
                Interlocked.Add(ref this.totalBytesRead, bytesTransferred);
            }
            else
            {
                content += Encoding.ASCII.GetString(
                    e.Buffer, e.Offset, bytesTransferred);
                ProcessReceive(e);
            }
        }
        else
        {
            this.CloseClientSocket(e);
        }
    }
}

1 Ответ

5 голосов
/ 16 апреля 2010

Я начну с того, что никогда не работал с сокетами .NET 3.5, так что этот ответ - немного обоснованное предположение.

Проблема, с которой вы столкнулись, заключается в том, что вы не сохраняете содержимое в каком-то состоянии при каждом чтении. Итак, проблемы:
Во-первых

  1. Вы вызываете ProcessReceive: string content = string.Empty;

  2. Вы добавляете к контенту: 'content + = Encoding.ASCII.GetString (e.Buffer, e.Offset, ew.BytesTransferred); `

  3. Вы снова вызываете ProcessReceive: string content = string.Empty;
  4. Цикл продолжается, и контент всегда устанавливается в пустую строку.

Во-вторых
Чтобы получить оставшиеся данные, которые вы вызываете ProcessReceive, это неверно. Вам необходимо выполнить еще одно чтение для нижележащего сокета с помощью ReceiveAsync.

Я изменил ваш код с помощью этого сообщения в блоге.

// You'll need some state object, if you don't already have one
class AsyncServerState
{
   public byte[] Buffer = new byte[8192]; // 8K buffer
   public StringBuilder Content = new StringBuilder0; // Place to store the content as it's received
   public SocketAsyncEventArgs ReadEventArgs = new SocketAsyncEventArgs();
   public Socket Client;
}

// You'll need to setup the state where ever you process your connect
// something similar to this.
void Accept_Completed(object sender, SocketAsyncEventArgs e)
{
    if (e.SocketError == SocketError.Success)
    {
        Socket client = e.AcceptSocket;
        AsyncServerState state = new AsyncServerState();
        state.ReadEventArgs.AcceptSocket = client;
        state.ReadEventArgs.Completed += new EventHandler(                                              IO_Completed);
        state.ReadEventArgs.UserToken = state;
        state.Client = client;
        state.ReadEventArgs.SetBuffer(state.Buffer, 0, state.Buffer.Length);

        if (!client.ReceiveAsync(state.ReadEventArgs))
        {   
            // Call completed synchonously
            ProcessReceive(state.ReadEventArgs);
        }
    }
    ProcessAccept(e);
}

private void ProcessReceive(SocketAsyncEventArgs e)
{        
    var state = e.UserToken as AsyncServerState;

    // Check if the remote host closed the connection.
    if (e.BytesTransferred > 0)
    {
        if (e.SocketError == SocketError.Success)
        {
            // Get the message received from the listener.
            sting content = Encoding.ASCII.GetString(state.Buffer, 0, e.BytesTransferred);

            // Append the received data to our state
            state.Content.Append(content);                          

            // Increment the count of the total bytes receive by the server
            Interlocked.Add(ref this.totalBytesRead, bytesTransferred);

            if (content.IndexOf(Convert.ToString((char)3)) > -1)
            {
                // Final Message stored in our state
                string finalContent = state.Content.ToString();
                return;                
            }
            else
            {
                // You need to issue another ReceiveAsync, you can't just call ProcessReceive again
                if (!state.Client.ReceiveAsync(state.ReadEventArgs))
                {
                    // Call completed synchonously
                    ProcessReceive(state.ReadEventArgs);
                }                
            }
        }
        else
        {
            this.CloseClientSocket(e);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...