user2536272
user2536272

Reputation: 69

c# asynchronous server with beginReceive

Hi stack overflow members. I'm struggling with some simple code but I can't get it done. I have this asynchronous server which waits for connections.

while (clientSocket.Connected)
{             
    try
    {
        clientSocket.BeginReceive(so.buffer, 0, 200, SocketFlags.None
                                  , new AsyncCallback(wait),so);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }                
}

where so(shorted StateObject) it's my class:

internal class StateObject
{
    public TcpClient client;
    public byte[] buffer;

    public StateObject()
    {
        buffer = new byte[200];
        client = new TcpClient();
    }
}

I use this class to put out the information on the callback function. However I get the system lacked sufficient buffer space or because a queue was full. I posted a short piece from the actual program. One interesting issue, is that if I write:

while (clientSocket.Connected)
{             
    try
    {
        byte[] buffer = new byte[200];
        clientSocket.BeginReceive(buffer, 0, 200, SocketFlags.None
                                  , new AsyncCallback(wait),so);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }                
}

it will work, but I will not be able to pull out the buffer from the asynchronous function(wait). I'm struggling with this and I can't find answers.

Upvotes: 1

Views: 9685

Answers (4)

user2536272
user2536272

Reputation: 69

I resolved my previous problem(I just needed to remove the while loop, however I messed it up with some code from a synchronous server). Now I have another problem, so I will use this same thread. From what I've searched, and understood, you can open an asynchronous server with BecinAccept like this(main method):

IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 8082);

TcpListener tcpListener = new TcpListener(IPAddress.Any, 8082);           

server = tcpListener.Server;
server.Bind(ipEndPoint);
server.Listen(4);

server.BeginAccept(new AsyncCallback(beginConnection), server);

Then:

static void beginConnection(IAsyncResult iar)
        {
            Console.WriteLine("Client connected");
            Socket s = (Socket)iar.AsyncState;
            server = s.EndAccept(iar);

            server.Listen(4); // this line was initially absent
            server.BeginAccept(beginConnection, s);
        }

I want to be able to connect to this server multiple clients. However, when I try to do this, only the first client connects itself. The client it's a simple socket, which just echoes back from the server, what we read from the console. I thought that since in the main method I've called server.Listen(4), I will be able to connect 4 clients. Then I thought of calling recursively BeginAccept in the beginConnection method. And last, I received the error, that I must call first the Listen method, so I added that too. Still no luck.

Upvotes: -1

I4V
I4V

Reputation: 35363

How about using some TPL functions. So your code can be simplified a lot

int readBytes  = await s.ReceiveTaskAsync(buffer, 0, buffer.Length);

This is the extension method ReceiveTaskAsync

public static class SocketExtensions
{
    public static Task<int> ReceiveTaskAsync(this Socket socket, byte[] buffer, int offset, int count)
    {
        return Task.Factory.FromAsync<int>(
                       socket.BeginReceive(buffer, offset, count, SocketFlags.None, null, socket),
                       socket.EndReceive);
    }
}

Upvotes: 4

Jeroen van Langen
Jeroen van Langen

Reputation: 22083

The while loop shouldn't be there, just call beginreceive after the endreceive.

This is a poor example, but may give you some ideas:

public class AsyncTCP
{

    public void StartReceive()
    {
        byte[] buffer = new byte[200];
        clientSocket.BeginReceive(buffer, 0, 200, SocketFlags.None, (state) =>
        {
            int bytesReceived = clientSocket.EndReceive(state);

            // handle buffer.

            if(bytesReceived != 0)
                StartReceive();
        } ,so);
    }
}

If it's about getting the state within the EndReceive handler:

private void StartReceive()
{
    StateObject myState = new StateObject();
    myState.buffer = new byte[200];
    myState.client = _client; // or whatever

    myState.client.BeginReceive(so.buffer, 0, 200, SocketFlags.None, new AsyncCallback(wait),myState);

}

private void EndReceive(IAsyncResult result)
{
    StateObject myState = (StateObject)result.State;

    int bytesReceived = myState.client.EndReceive(result);

    // handle myState.buffer

    StartReceive();

}

I think there are better ways to do this, like: - only constructing a receive buffer ones. - put some packet header/data with lengths in it.

Good luck

Upvotes: 4

Sriram Sakthivel
Sriram Sakthivel

Reputation: 73502

The problem is here

while (clientSocket.Connected)//checks connected
{             
    try
    {
        clientSocket.BeginReceive(so.buffer, 0, 200, SocketFlags.None, new AsyncCallback(wait),so);//says begin receive and continues to do endlessly
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex.Message);
     }                
}

You've to call BeginReceive again only after you received the data.

Here's and example from msdn how to do that.

Upvotes: 1

Related Questions