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.
Related
I'm using a StreamSocketListener to await a connection on a port. I don't want it to listen forever, it must cancel after a specific number of seconds, for which I'm using the following code.
remoteListener = new StreamSocketListener();
try
{
CancellationTokenSource ctsTimeout = new CancellationTokenSource();
ctsTimeout.CancelAfter(1000); // in milliseconds
await remoteListener.BindServiceNameAsync(receivingPortForRemoteRequests.ToString()).AsTask(ctsTimeout.Token);
remoteListener.ConnectionReceived += remoteListener_ConnectionReceived;
}
catch (Exception exc) // supposed to produce a TaskCanceledException
{
isCancelled = true;
}
My problem is that this code never throws the Exception after any interval of time, but just keeps listening. The code is based on what I'd found from this MSDN page.
Does anyone know what I'm doing wrong ? Thanks in advance!
I would say that the primary mistake you have made is that you are passing the cancellation token to the task that binds the socket, and not any operation that actually listens. The binding operation simply assigns a port to the socket, and generally will complete within milliseconds at the worst, quite likely faster in the typical case. There's no way this operation would ever still be in progress after a full second.
Without a good Minimal, Complete, and Verifiable example that clearly illustrates your question, it's impossible to provide a thorough answer. However, some suggestions:
First, don't bother using the cancellation token. It's not how you should stop a socket from listening. Instead, just close the socket after the requisite time. You can use a timer for this purpose, or an async method that first calls await Task.Delay(...) and then closes the socket.
In the future, if you do have a scenario where using a cancellation token is appropriate, you should catch only TaskCanceledException. Never use catch (Exception) for routine exception handling; the only place it's appropriate is for scenarios where you intend to simply log or otherwise report the exception and then terminate the process. Otherwise, catch only the exceptions you expect and for which you have a good plan for handling.
You should subscribe to the ConnectionReceived event before you bind the socket. Otherwise, there is a chance (very small, granted) that a connection attempt would be made before your code is ready to be notified via the event.
The first and third points above are addressed in the MSDN documentation, which has a useful summary of the proper use of this class. From the documentation for StreamSocketListener:
The typical order of operations is as follows:
• Create the StreamSocketListener.
• Use the Control property to retrieve a StreamSocketListenerControl object and set the socket quality of service required.
• Assign the ConnectionReceived event to an event handler.
• Call the BindServiceNameAsync or BindEndpointAsync method to bind to a local TCP port number or service name. For Bluetooth RFCOMM, the local service name parameter is the Bluetooth Service ID.
• When a connection is received, use the StreamSocketListenerConnectionReceivedEventArgs object to retrieve the Socket property with the StreamSocket object created.
• Use the StreamSocket object to send and receive data.
• Call the Close method to stop listening for and accepting incoming network connections and release all unmanaged resources associated with the StreamSocketListener object. Any StreamSocket objects created when a connection is received are unaffected and can continue to be used as needed.
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).
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.
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.
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 ?