如何在SocketAsyncEventArgs对象上使用缓冲区

Rob*_*Rob 2 c# sockets

我们一直坚持在SocketAsyncEventArgs对象上使用缓冲区.

使用旧的套接字方法,我们将转换我们的状态对象,如下所示:

clientState cs = (clientState)asyncResult.AsyncState;
Run Code Online (Sandbox Code Playgroud)

但是,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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Par*_*ice 5

我首先要说的是我从未使用过.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向底层Socket发出另一个读取.

我已使用此博客文章修改了您的代码.

// 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)