I have a question about at what point after a BeginAccept on a socket can I tell my listener thread that it can start accepting connections again.
This is the code I have:
while(!mStopWaitHandle.WaitOne(0, false)) // <-- Manual Reset event to check if the service has stopped.
{
Logging.Debug("Waiting for a connection...");
socket.BeginAccept(new AsyncCallback(AcceptConnection), socket);
mReadyToAcceptWaitHandle.WaitOne(); // <-- AutoResetEvent to block until I can continue accepting connections
}
then in my Async Callback:
private void AcceptConnection(IAsyncResult ar)
{
mReadyToAcceptWaitHandle.Set(); // <-- Tell the listener thread to start accepting connections again
Socket socket = (Socket)ar.AsyncState;
Socket workerSocket = socket.EndAccept(ar);
... handle connection on workerSocket ...
}
This is how they do it in the Asynchronous Server Socket Example on msdn.
But from what I have read BeginAccept is not a blocking call. The blocking call is EndAccept, and it blocks until there is a connection to accept.
So having the mReadyToAcceptWaitHandle.Set();, to tell the listener thread to keep accepting connections, before EndAccept() seems odd to me because wouldn't that just cause it to keep opening AcceptConnection handler threads (from what I've seen from execution, it doesn't seem to do this, but I don't know why?) that all just block on EndAccept?
Would it not be better to have mReadyToAcceptWaitHandle.Set(); after EndAccept, so that it only deals with accepting one connection at a time, and once it has accepted, but before it actually handles the communication on the connection.
Both ways seem to work, but I want to know which one is the correct way, and whether one way will have subtle negative side effects that the other doesn't.
What am I missing here?
Thanks in advance.
The blocking call is EndAccept, and it blocks until there is a connection to accept.
That's not an accurate description.
EndAccept is called from the callback of BeginAccept when a connect request has been received from a client. You can call BeginAccept again from the BeginAccept callback to immediately accept another connection while establishing the (previous) connection you just received via EndAccept (still in the connection callback).
So it is not actually necessary to use events at all to synchronize when to accept new connections. Simply call BeginAccept again from the callback.
Related
I am coming from Java programming language. I am just beginning my adventure with C# and .Net.
I am creating a Server socket application using C# - based on Microsoft example (https://learn.microsoft.com/en-us/dotnet/framework/network-programming/asynchronous-server-socket-example).
This is the sample code (from the page above):
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
... where allDone is a ManualResetEvent defined in the class scope.
I can't understand what actually listener.BeginAccept does. For instance if I don't call method allDone.WaitOne() to wait until connection is made, then what would have happend - how many times the call to listener.BeginAccept method would execute (be successful) inside the loop until it starts waiting (or maybe it would crash eventually). I am probably missing something here. Can someone explain this to me please?
Regards,
Janusz
The intent here is for the AcceptCallback method to set the allDone event when a connection is accepted. The loop can then go on to accept another incoming connection while the just accepted one continues with whatever it needs to do.
You could have done other useful work on the listening thread after the call to BeginAccept, if you had any that made sense.
Oddly the documentation does not explicitly state (that I could find) what happens if you just repeatedly call BeginAccept without waiting, but my recommendation would be to not do that.
I am creating a simple server (C#) and client (python) that communicate using sockets.
The server create a
var listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp)
then binds, listens in a infinite loop
while (true)
{
// Set the event to nonsignaled state.
AllDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(AcceptCallback, listener);
// Wait until a connection is made before continuing.
AllDone.WaitOne();
}
the AcceptCallback calls BeginReceive whose callbackk reads the buffer and sends back a message to the client
everything works. Client sends a message, server sees it, replies, client sees it. But when the client tries to send a message again (for testing client is in a loop), nothing happens
the python client:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
while True:
sock.sendall(data)
blockLen = sock.recv(32) #server sends back a string prefixed with how long the string is
serverReply = sock.recv(blockLen)
how do i keep the socket from dying?
this is from MSDN(Remarks on EndAccept):
Your callback method should invoke the EndAccept method. When your
application calls BeginAccept, the system usually uses a separate
thread to execute the specified callback method and blocks on
EndAccept until a pending connection is retrieved. EndAccept will
return a new Socket object that you can use to send and receive data
with the remote host. You cannot use this returned Socket to accept
any additional connections from the connection queue. If you want the
original thread to block after you call the BeginAccept method, use
WaitHandle.WaitOne. Call the Set method on a ManualResetEvent in the
callback method when you want the original thread to continue
executing.
and there is another question on stackoverflow check.will it be helpful?
Socket SocketSrv;
public static ManualResetEvent Done = new ManualResetEvent(false);
IPEndPoint IPP = new IPEndPoint(IPAddress.Any, 1234);
void Listening()
{
SocketSrv = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
try
{
SocketSrv.Bind(IPP);
SocketSrv.Listen(5);
while (true)
{
Done.Reset();
info.Text = "Waiting for connections....";
SocketSrv.BeginAccept(new AsyncCallback(Connection),
SocketSrv);
Done.WaitOne();
}
}
catch(Exception error)
{
MessageBox.Show(error.Message);
}
}
void Connection(IAsyncResult ar)
{
Done.Set();
Socket con= (Socket)ar.AsyncState;
Socket handler = con.EndAccept(ar);
}
I'm trying to understand the ManualResetEvent in this asynchronus operation since I've never used it.
Step1. The SocketSrv is created to accept TCP connections and the type of sending and receving "commands" is stream.
Step2. The socket is binded with the ip,port and then we start listening for connections.
Step3. In the while loop :
The ManualResetEvent is Reset (I understand that the ManualResetEvent is a class which type is Boolean and indicates whenever a thread is busy or not).In this case , the event is always reset because if there's a connection made and another one is coming I need to reset it and start the "operation" again.
In the BeingAccept I'm being starting the asynchronous operation, the callback function which is executed and the IAsyncResult argument which will become the "socket".
Step4. The ResetEvent is now Waiting blocking the current thread and waiting for the handler in the connection method to be ended so it can finish initializing the current connection.
Step5. In the connection thread the ResetEvent sets the signal true which means... well I don't know what does it means. I think it tells to the ResetEvent to unblock the main thread.
In the 'con' socket I'm getting the AsyncState. I have no idea what does it means.
In the handler socket I'm telling the ResetEvent that the connection was made.
Things being said, could someone tell me if what I've said is true/wrong and why?
The event is used so that when a connection occurs BeginAccept won't be called again until the Connect method has been invoked. e.g. WaitOne halts the thread until Set is called. Reset is called to set the state of the event back to signalled so that WaitOne will halt the thread again so that it will wait for Connect to be called again.
Personally, I don't use this particular pattern. I've never seen an explanation of the point of this pattern. If there were some shared state between the BeginAccept loop and the Connect method, it might make sense. But, as written no state is guarded by use of the event. When I use BeginAccept I simply don't use an event, and I've used code like this to deal with many connections a second. Use of the event will do nothing to prevent errors with too many connections at a time. And quite frankly, to use an asynchronous method and force it to effectively be synchronous defeats the purpose.
The AysncState, from the point of view of BeginAccept, is simply opaque data. It's the "state" that is used for that particular async operation. This "state" is application-specific. You use whatever you need when you want to process a connection asynchronously. In the case of the BeginAccept callback, you usually want to do something with the server socket and it's passed in for the state so you have access to it to call EndAccept. Since SocketSrv is a member field, you don't really need to do this, you could do this instead:
SocketSrv.BeginAccept(new AsyncCallback(Connection), null);
//...
void Connection(IAsyncResult ar)
{
Socket handler = SocketSrv.EndAccept(ar);
//...
}
Your comments seem to suggest you have a good grasp of this particular bit of code. Your "Step4" is a bit off, it's not waiting for the Connection method to end, just for it to start (since Set is called as the first line). And yes, "Step5", the Set means it unblocks the WaitOne so the main thread call call Reset then BeginAccept.
Unlike the synchronous Accept, BeginAccept doesn't provide a socket for the newly created connection. EndAccept however does, but it also stops future connections from being accepted; so I concocted the following code to allow multiple 'clients' to connect to my server:
serverSocket.BeginAccept(AcceptCallback, serverSocket);
AcceptCallback code:
void AcceptCallback(IAsyncResult result)
{
Socket server = (Socket)result.AsyncState;
Socket client = server.EndAccept(result);
// client socket logic...
server.BeginAccept(AcceptCallback, server); // <- continue accepting connections
}
Is there a better way to do this? It seems to be a bit 'hacky', as it essentially loops the async calls recursively.
Perhaps there is an overhead to having multiple calls to async methods, such as multiple threads being created?
The way are doing this is correct for using asynchronous sockets. Personally, I would move your BeginAccept to right after you get the socket from the AsyncState. This will allow you to accept additional connections right away. As it is right now, the handling code will run before you are ready to accept another connection.
As Usr mentioned, I believe you could re-write the code to use await with tasks.
This is normal when you deal with callback-based async IO. And it is what makes it so awful to use!
Can you use C# await? That would simplify this to a simple while (true) { await accept(); } loop.
I am a little bit confused about what does the Async approach achieve. I encountered it when looking up how to make a server accept multiple connections. What confuses me while looking up what Aync does in C# exactly, is that from what I can tell its not its own thread. However, it also allows you to avoid locking and stalling. For instance, if I have the following:
ConnectionManager()
{
listener = new TcpListener(port);
listener.BeginAcceptSocket(new AsyncCallback(acceptConnection), listener);
}
public void acceptConnection(IAsyncResult ar)
{
//Do stuff
}
does this mean that as soon as it finds a connection, it executes the "acceptConnection" function but then continues to execute through the caller function? (in this case going out of scope). How does this allow me to create a server application that will be able to take multiple clients? I am fairly new to this concept even though I have worked with threads before to manage server/client interaction. If I am being a little vague, please let me know. I have looked up multiple examples on MSDN and am still a little confused. Thank you ahead of time!
as soon as it finds a connection, it executes the "acceptConnection" function
Yes
then continues to execute through the caller function?
No.
what does the Async approach achieve
When done right, it allows processing much higher number of requests/second using fewer resources.
Imagine you're creating a server that should accept connections on 10 TCP ports.
With blocking API, you’ll have to create 10 threads just for accepting sockets. Threads are expensive system resource, e.g. every thread has its own stack, and switching between threads takes considerable time. If a client connecting to some socket, the OS will have to wake up the corresponding thread.
With async API, you post 10 asynchronous requests. When client is connecting, your acceptConnection method will be called by a thread from the CLR thread pool.
And one more thing.
If you want to continue executing the caller function after waiting for asynchronous I/O operation to complete, you should consider new C#’s async/await syntax, it allows you to do just that. The feature is available as a stand-alone library “Async CTP” for visual studio 2010, and included in visual studio 2012.
I don't profess to be a c# or sockets guru but from what I understand the code you've got above will accept the first connection and then no more. You would need to establish another BeginAccept.
Something like:
TcpListener listener = null;
ConnectionManager()
{
listener = new TcpListener(port);
listener.BeginAcceptSocket(new AsyncCallback(acceptConnection), listener);
}
public void acceptConnection(IAsyncResult ar)
{
// Create async receive data code..
// Get ready for a new connection
listener.BeginAcceptSocket(new AsyncCallback(acceptConnection), listener);
}
So by using Async receive data in addition to the async connection, the accept connection finishes pretty quickly and sets up listening for a new connection. I guess you could re-order this too.
For straight socket connection (not TcpListener) this is what i used:
(connectedClient is a my own class which handles the receive & transmit functions and holds other info about the connection).
int Port = 7777; // or whatever port you want to listen on
IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, port);
listenSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(ipLocal);
// create the call back for any client connections...
listenSocket.BeginAccept(new AsyncCallback(OnClientConnection), null);
private void OnClientConnection(IAsyncResult asyn)
{
if (socketClosed)
{
return;
}
try
{
Socket clientSocket = listenSocket.EndAccept(asyn);
ConnectedClient connectedClient = new ConnectedClient(clientSocket, this);
connectedClient.MessageReceived += OnMessageReceived;
connectedClient.Disconnected += OnDisconnection;
connectedClient.MessageSent += OnMessageSent;
connectedClient.StartListening();
// create the call back for any client connections...
listenSocket.BeginAccept(new AsyncCallback(OnClientConnection), null);
}
catch (ObjectDisposedException excpt)
{
// Deal with this, your code goes here
}
catch (Exception excpt)
{
// Deal with this, your code goes here
}
}
I hope this has answered what you're looking for ?