Sherlock
Sherlock

Reputation: 5627

Async socket confusion

My socket client does not appear to be handling situations where the buffer is full and there is more data to be received.

Here is my on receive method, simple version:

private void Recieve()
{
    this._clientSocket.BeginReceive(this._buffer, 0, this._buffer.Length, 0,
        new AsyncCallback(OnReceive), this._clientSocket);
}

private void OnReceive(IAsyncResult result)
{
    Socket clientSocket = (Socket)result.AsyncState;
    int bytesRead = clientSocket.EndReceive(result);
    this.Recieve();
    string data = Encoding.ASCII.GetString(this._buffer, 0, bytesRead);
    ThreadPool.QueueUserWorkItem(new WaitCallback(this.HandleDataReceived), data);
}

This doesn't handle situations where there is more data to be received at all. So then I tried this (http://msdn.microsoft.com/en-us/library/bew39x2a.aspx):

private string receivedString = string.Empty;
private void OnReceive(IAsyncResult result)
{
    Socket clientSocket = (Socket)result.AsyncState;
    int bytesRead = clientSocket.EndReceive(result);
    if (bytesRead > 0)
    {
        receivedString += Encoding.ASCII.GetString(this._buffer, 0, bytesRead);
        this.Recieve();
    }
    else
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback(this.HandleDataReceived), this.receivedString);
        this.receivedString = string.Empty;
    }
}

But the problem i'm having with this is that when bytesRead > 0 and I call BeginReceive again I do not get another callback. Did I make some kind of mistake ?

Thanks

Upvotes: 0

Views: 453

Answers (1)

Jim Mischel
Jim Mischel

Reputation: 133950

In the first code, you have a race condition. Consider:

private void OnReceive(IAsyncResult result)
{
    Socket clientSocket = (Socket)result.AsyncState;
    int bytesRead = clientSocket.EndReceive(result);
    this.Recieve();
    string data = Encoding.ASCII.GetString(this._buffer, 0, bytesRead);
    ThreadPool.QueueUserWorkItem(new WaitCallback(this.HandleDataReceived), data);
}

You call Receive again, which could overwrite buffer before you send the data to your HandleDataReceived method. I think you want to move that Receive call to after you've converted the data:

private void OnReceive(IAsyncResult result)
{
    Socket clientSocket = (Socket)result.AsyncState;
    int bytesRead = clientSocket.EndReceive(result);
    string data = Encoding.ASCII.GetString(this._buffer, 0, bytesRead);
    ThreadPool.QueueUserWorkItem(new WaitCallback(this.HandleDataReceived), data);
    this.Recieve();
}

In the second case, you never read 0 bytes because the socket is waiting for data. If there is no data, Socket.Receive will block until there is data available, or until the connection is closed. BeginReceive is waiting for data.

Upvotes: 2

Related Questions