Understanding ManualResetEvent in asynchronous server socket - c#

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.

Related

How many times can I call Socket.BeginAccept in C#

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.

C# Async Sockets - Thread Logic

How does the thread creation logic behind Socket.BeginSend, Socket.BeginReceive, Socket.BeginAccept, etc. works?
Is it going to create a new thread for each client that connects to my server to handle the code, or is it only going to create one thread for each function(accept, receive, send...) no mattering how many clients there are connected to the server? This way only executing the client 2 accept code once the client 1 accept code is completed and so on.
This is the code I made and I am trying to understand the logic behind it better:
public class SocketServer
{
Socket _serverSocket;
List<Socket> _clientSocket = new List<Socket>();
byte[] _globalBuffer = new byte[1024];
public SocketServer()
{
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public void Bind(int Port)
{
Console.WriteLine("Setting up server...");
_serverSocket.Bind(new IPEndPoint(IPAddress.Loopback, Port));
}
public void Listen(int BackLog)
{
_serverSocket.Listen(BackLog);
}
public void Accept()
{
_serverSocket.BeginAccept(AcceptCallback, null);
}
private void AcceptCallback(IAsyncResult AR)
{
Socket socket = _serverSocket.EndAccept(AR);
_clientSocket.Add(socket);
Console.WriteLine("Client Connected");
socket.BeginReceive(_globalBuffer, 0, _globalBuffer.Length, SocketFlags.None, ReceiveCallback, socket);
Accept();
}
private void ReceiveCallback(IAsyncResult AR)
{
Socket socket = AR.AsyncState as Socket;
int bufferSize = socket.EndReceive(AR);
string text = Encoding.ASCII.GetString(_globalBuffer, 0, bufferSize);
Console.WriteLine("Text Received: {0}", text);
string response = string.Empty;
if (text.ToLower() != "get time")
response = $"\"{text}\" is a Invalid Request";
else
response = DateTime.Now.ToLongTimeString();
byte[] data = Encoding.ASCII.GetBytes(response);
socket.BeginSend(data, 0, data.Length, SocketFlags.None, SendCallback, socket);
socket.BeginReceive(_globalBuffer, 0, _globalBuffer.Length, SocketFlags.None, ReceiveCallback, socket);
}
private void SendCallback(IAsyncResult AR)
{
(AR.AsyncState as Socket).EndSend(AR);
}
}
These kinds of asynchronous methods use threads from the thread pool to invoke your callback, once the underlying event, whatever it may be, occurs. In your case, the underlying event might be a connection was established, or you received some data.
When you set a socket to 'accept', no thread needs to exist. The old synchronous way of doing things was to have one thread that just blocks on socket.Accept() until a connection comes in, but the point of these Begin..() methods is to do away with that.
Here's a trick, one that .Net uses and one that you use: You can register any WaitHandle object (a lock such as Semaphore, SemaphoreSlim, Mutex, etc) and a callback method with the thread pool, such that when the WaitHandle becomes set, the thread pool will pick a thread, run your callback, and return the thread to the thread pool. See ThreadPool.RegisterWaitForSingleObject().
Turns out many of these Begin..() methods basically do the same thing. BeginAccept() uses a WaitHandle to know when a socket has received a connection - it registers the WaitHandle with the ThreadPool and then calls your callback on a ThreadPool thread when a connection occurs.
Every time you call Begin...() and provide a callback, you should assume that your callback method could be invoked on a new thread, simultaneously with every other Begin...() call you've ever made that's still outstanding.
Call BeginReceive() 50 times on 50 different sockets? You should assume 50 threads could try to invoke your callback method at the same time. Call a mix of 50 BeginReceive() and BeginAccept() methods? 50 threads.
In reality, how many simultaneous invocations of your callbacks occur will be limited by the policy set in the ThreadPool, eg, how fast it may make new threads, how many threads it keeps live ready to go, etc.
With that, you should understand that calling BeginReceive() on 50 different sockets, but passing in the same buffer - _globalBuffer - means that 50 sockets are going to write to that same buffer and just make a mess of it, resulting in arbitrary/corrupted data.
Instead, you should use a unique buffer per simultaneous BeginReceive() call. What I would recommend doing is creating a new class to store the context of a single connection - the socket for the connection, the buffer to use for reading, its state, etc. Every new connection gets a new context instance.
...
FYI, the modern way of performing asynchronous programming in C# is to use the async/await keywords and matching async methods from the API. That design is much more complicated and much more deeply integrated with the execution environment than these Begin...() methods, and the answers to questions like "when do my callbacks get called", "what thread(s) are my callbacks called on", and "how many callbacks might run simultaneously" depend entirely on the execution environment of your program consequent to the async/await design in C# / .Net.

Will ManualResetEvent block the entire program?

I have a program that begins itself by listening for connections. I wanted to implement a pattern in which the server would accept a connection, pass that individual connection to a user class for processing: future packet reception, and handling of the data.
I ran into trouble with the synchronous pattern before I found out that asynchronous use of the Socket class isn't scary. But then I ran into more trouble. It seemed that, in a while (true) loop, since BeginAccept() is asynchronous, the program would constantly move through this loop and eventually run into an OutOfMemoryException. I needed something to listen for a connection, and immediately hand off responsibility of that connection to some other class.
So I read Microsoft's example and found out about ManualResetEvent. I could actually specify when I was ready for the loop to begin listening again! But after reading some questions here on Stack Overflow, I have become confused.
My worry is that even though I have asynchronously accepted a connection, the entire program will block while it's trying to listen for a new connection upon re-entering the loop. This isn't ideal if I'm handling multiple users.
I'm very new to the world of asynchronous I/O, so I would appreciate even the angriest of comments about my vocabulary or a misuse of a phrase.
Code:
static void Main(string[] args)
{
MainSocket = new Socket(SocketType.Stream, ProtocolType.Tcp);
MainSocket.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.74"), 1626));
MainSocket.Listen(10);
while (true)
{
Ready.Reset();
AcceptCallback = new AsyncCallback(ConnectionAccepted);
MainSocket.BeginAccept(AcceptCallback, MainSocket);
Ready.WaitOne();
}
}
static void ConnectionAccepted(IAsyncResult IAr)
{
Ready.Set();
Connection UserConnection = new Connection(MainSocket.EndAccept(IAr));
}
The Microsoft example, in which they use the old-style WaitHandle based events, will work but frankly it is a very odd and awkward way to implement asynchronous code. I get the feeling that the events are there in the example mainly as a way of artificially synchronizing the main thread so it has something to do. But it's not really the right approach.
One option is to just not even accept sockets asynchronously. Instead, use the asynchronous I/O for when the socket is connected and use a synchronous loop in the main thread to accept sockets. This winds up being pretty much exactly what the Microsoft sample does anyway, but keeps all of the accept logic in the main thread instead of switching back and forth between the main thread (which starts the accept operation) and some IOCP thread that handles the completion.
Another option is to just give the main thread something else to do. For a simple example, this could be simply waiting for some user input to signal that the program should shut down. Of course, in a real program the main thread could be something useful (e.g. handling the message loop in a GUI program).
If the main thread is given something else to do, then you can use the asynchronous BeginAccept() in the way it was intended: you call the method to start the accept operation, and then don't call it again until that operation completes. The initial call happens when you initialize your server, but all subsequent calls happen in the completion callback.
In that case, your completion callback method looks more like this:
static void ConnectionAccepted(IAsyncResult IAr)
{
Connection UserConnection = new Connection(MainSocket.EndAccept(IAr));
MainSocket.BeginAccept(ConnectionAccepted, MainSocket);
}
That is, you simply call the BeginAccept() method in the completion callback itself. (Note that there's no need to create the AsyncCallback object explicitly; the compiler will implicitly convert the method name to the correct delegate type instance on your behalf).

Start Accepting new connections before or after EndAccept()

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.

Understanding the Async (sockets) in C#

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 ?

Categories

Resources