Reputation: 69
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
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
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
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
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