I'm writing a server for a game, and I want to be able to handle thousands of concurrent users. For this reason, I went with non-blocking sockets and use the poll method. However, I do create multiple threads to handle database and web calls, and some of these threads will send a response to the user. In one of these threads, on send, I get the error "A non-blocking socket operation could not be completed immediately". What could cause this problem? I imagine it's because a poll is occurring at the same time as send is called. If I used beginAsync, would it take stop this error? I thought about locking the socket, but I don't want my main thread to be blocked for this.
I don't know what kind of non-blocking-polling socket calls are you using, but I would recommend that you use the Async socket calls (instead of the Begin). For more information on the difference between Async calls vs Begin see: What's the difference between BeginConnect and ConnectAsync?
The asynchronous calls automatically do "polling" on the OS level, which will be much more efficient than your polling. As a matter of fact, they use IO completion ports, which are probably the fastest and most efficient thing you can use on Windows to handle a large amount of client connections/requests.
As far as the error, I would consider this to be the normal operation of non-blocking sockets, so you just have to handle it gracefully.
Update
Your server should probably do something like this:
// Process the accept for the socket listener.
private void ProcessAccept(SocketAsyncEventArgs e)
{
Socket s = e.AcceptSocket;
if (s.Connected)
{
try
{
SocketAsyncEventArgs readEventArgs = this.readWritePool.Pop();
if (readEventArgs != null)
{
// Get the socket for the accepted client connection and put it into the
// ReadEventArg object user token.
readEventArgs.UserToken = new Token(s, this.bufferSize);
Interlocked.Increment(ref this.numConnectedSockets);
Console.WriteLine("Client connection accepted.
There are {0} clients connected to the server",
this.numConnectedSockets);
if (!s.ReceiveAsync(readEventArgs))
{
this.ProcessReceive(readEventArgs);
}
}
else
{
Console.WriteLine("There are no more available sockets to allocate.");
}
}
catch (SocketException ex)
{
Token token = e.UserToken as Token;
Console.WriteLine("Error when processing data received from {0}:\r\n{1}",
token.Connection.RemoteEndPoint, ex.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
// Accept the next connection request.
this.StartAccept(e);
}
}
Code sample courtesy of code project: http://www.codeproject.com/Articles/22918/How-To-Use-the-SocketAsyncEventArgs-Class
When a non-blocking socket tries to read data but finds none you get that error: the socket would like to wait for data but can't because it has to return immediately, being non-blocking.
I'd suggest you switch to blocking sockets, find out why data is missing, adjust accordingly then revert to non-blocking ones. Or, you could handle the error and retry the operation.
I was also receiving this exception on sending data and just found the solution.
You get the exception because the socket's send buffer is full. Because you are trying to send the data via a non-blocking send, the exception is raised to let you know that you MUST send it via a blocking send.
The data is not sent once the exception is raised, so you have to resend it. Your individual send call now becomes;
try
{
m_socket.Send(buffer, bufferSize, SocketFlags.None);
}
catch (SocketException e)
{
if(e.SocketErrorCode == WouldBlock)
{
m_socket.Blocking = true;
m_socket.Send(buffer, bufferSize, SocketFlags.None);
m_socket.Blocking = false;
}
}
It would also be a good idea to increase the socket's SendBufferSize. By default I think it is 8kb. For my needs I had to increase it to 2MB, and afterwards the Send call no longer threw that exception.
This exception is too general. Per MSDN,
If you receive a SocketException, use the SocketException.ErrorCode property to obtain the specific error code. After you have obtained this code, refer to the Windows Sockets version 2 API error code documentation in the MSDN library for a detailed description of the error.
Sockets error codes are here.
Related
We have a C# server that receives TCP messages using sockets. The normal flow is to call socket.Accept(), use socket.BeginReceive() and socket.EndReceive() to receive the message, then use socket.Send() to send a response. This works fine.
When too many requests come in at once, however, we want to reject the overflow immediately, so we don't overwhelm the server. It's easy enough to close the socket directly after Accept(); but that doesn't allow us to send a meaningful "too busy" message back to the client.
What I'd like to do is simply call Accept(), then call Send(), without receiving the incoming message. I have tried this, and the server claims to send my data, but my client receives nothing but an empty response. I have tried using both the synchronous Send() and the asynchronous BeginSend()/EndSend(), but neither gets the message back to the client.
Is it possible to send a message on an accepted socket without first receiving the incoming message? If so, is there a piece I'm missing to make it work?
Here's a code snippet showing what I'm trying to do:
while (!_Done)
{
Socket socket = null;
try
{
socket = _ListeningSocket.Accept();
}
catch (Exception) { }
if (socket != null)
{
if (TooBusy())
{
// My new code
byte[] send = GetTooBusyResponse();
int ret = socket.Send(send);
Console.WriteLine("socket.Send() returned " + ret);
socket.Close();
socket = null;
}
else
{
// Existing, working code (using custom objects)
ClientConnection connection = new ClientConnection(this, socket, !_RequireAuthentication);
lock (_ConnectionsToken)
_Connections.Add(connection);
connection.BeginReceive();
}
}
}
According to MSDN,
The Close method closes the remote host connection and releases all
managed and unmanaged resources associated with the Socket. Upon
closing, the Connected property is set to false.
For connection-oriented protocols, it is recommended that you call
Shutdown before calling the Close method. This ensures that all data
is sent and received on the connected socket before it is closed.
If you need to call Close without first calling Shutdown, you can
ensure that data queued for outgoing transmission will be sent by
setting the DontLinger Socket option to false and specifying a
non-zero time-out interval. Close will then block until this data is
sent or until the specified time-out expires. If you set DontLinger to
false and specify a zero time-out interval, Close releases the
connection and automatically discards outgoing queued data.
So either call Shutdown first, or set the DontLinger option to false and set a non-zero timeout.
I choose not the use the asynchronous calls since it requires a callback, I'm just curious if there's a way to solve this by utilizing Unix-alike non-blocking socket method: Poll(), as Asyn is created specifically for the Windows environment. I'm researching if this could be done without asynchronous.
To be noted: NON-BLOCKING != ASYNCHRONOUS:)
Therefore I have the following approach by turning off the blocking flag of socket & Poll() method:
try
{
IPEndPoint hostEp = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 11000);
Socket hostSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
hostSock.Blocking = false;
hostSock.Connect(hostEp);
}
catch (Win32Exception se)
{
if (ex.ErrorCode == 10035) // WSAEWOULDBLOCK is expected, means connect is in progress
while (true)
{
Console.WriteLine("Connecting in progress");
bool connected = hostSock.Poll(1000000, SelectMode.SelectWrite);
if (connected)
{
Console.WriteLine("Connected");
break;
}
}
}
But then SelectMode.SelectWrite doesn't seems reinitiates an connection attempts for me. So, what's the problem? And how could I solve this? Should I use Select() instead of Poll()?
Just use the asynchronous methods (ConnectAsync()), they're meant for this. Don't use exceptions for program logic.
You can synchronously Connect() a TCP socket without blocking:
Manual:
The Connect method will block, unless you specifically set the Blocking property to false prior to calling Connect. If you are using a connection-oriented protocol like TCP and you do disable blocking, Connect will throw a SocketException because it needs time to make the connection.
You can use SocketException.ErrorCode to obtain the specific error code. After you have obtained this code, refer to the Windows Sockets version 2 API error code documentation in the MSDN library for a detailed description of the error.
If the error returned WSAEWOULDBLOCK, the remote host connection has been initiated by a connection-oriented Socket, but has not yet completed successfully. Use the Poll method to determine when the Socket is finished connecting.
But that is exactly what your code does, so that should just work.
You can use threads or tasks in order to launch the Connect without blocking the main thread.
This will add complexity if interaction with UI (WinForms / WPF) is needed, due to the Cross-Thread protection.
Also you can use a BackgroundWorker to avoid this issues.
Actually, your code is working on my system. However, you need of course a server which accepts your TCP connection. If you do not have that, then you will wait forever. So I guess you are missing a server.
I had the exact question, but for me the answer was rather silly: my code had the stock code for fetching the IpAddress from a string (from microsoft):
var ipHostInfo = Dns.GetHostEntry(hostname);
return ipHostInfo.AddressList[0];
This was all and good, but my tests was testing against "127.0.0.1:9000", which for some reason gnerated the ip address of my actual ethernet connection. Changing the parsing mechanism to:
if (hostname.Equals("localhost"))
{
return IPAddress.Parse("127.0.0.1");
}
try
{
return IPAddress.Parse(hostname);
}
catch (FormatException e)
{
var ipHostInfo = Dns.GetHostEntry(hostname);
return ipHostInfo.AddressList[0];
}
did the trick (at least for me!)
Naturally, BeginReceive() will never end if there's no data.
MSDN suggests that calling Close() would abort BeginReceive().
However, calling Close() on the socket also performs a Dispose() on it, as figured out in this great answer, and consequently EndReceive() would throw an exception because the object is already disposed (and it does!).
How should I proceed?
It seems like this is by (the very dumb) design. You must have this exception thrown and caught in your code.
MSDN looks silent about it indeed, but if you look at the documentation of another asynchronous socket method, BeginConnect(), here's what we find:
To cancel a pending call to the
BeginConnect() method, close the
Socket. When the Close() method is
called while an asynchronous operation
is in progress, the callback provided
to the BeginConnect() method is
called. A subsequent call to the
EndConnect(IAsyncResult) method will
throw an ObjectDisposedException to
indicate that the operation has been
cancelled.
If it is the proper way of doing for BeginConnect, it is probably so for BeginReceive as well. This is certainly a poor design on the part of Microsoft's async API, because making the user necessarily throw and catch exception as a part of a normal flow would annoy the debugger. You have really no way to "wait" until the operation is completed, because Close() is what completes it in the first place.
I am surprised no one recommended using SocketOptions.
Once the stack has the send or receive operation it is bound by the socket options of the socket.
Use a small send or receive timeout and use it before the operation so you don't care if it's changed during that same operation to something shorter or longer.
This will cause more context switching but will not require closing the socket under any protocol.
For example:
1) Set a small timeout
2) Perform operations
3) Set timeout larger
This is similar to using Blocking = false but with an automatic timeout that you specify.
You can read my solution of this problem here(using comment of Pavel Radzivilovsky here):
UdpClient.ReceiveAsync correct early termination
For TCP socket connections, you can use the Connected property to determine the state of the socket before trying to access any disposed methods. Per MSDN:
"The Connected property gets the connection state of the Socket as of the last I/O operation. When it returns false, the Socket was either never connected, or is no longer connected."
Since it says "no longer connected" it implies that a Close() was previously called on the socket. If you check whether the socket is Connected at the start of the receive callback, there will be no exception.
In the ReceiveCallback I checked client.Connected within the try block.
Now, when data is received after BeginReceive, I can call client.Close();
This way, I do not see exceptions. I send modbus-TCP requests every 200mS, and get responses in time. The console output looks clean. I used a windows forms app, to test this.
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
if (client.Connected)
{
// Read data from the remote device.
state.dataSize = client.EndReceive(ar);
if (state.dataSize > 0)
{
Console.WriteLine("Received: " + state.dataSize.ToString() + " bytes from server");
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, state.dataSize));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BUFFER_SIZE, 0,
new AsyncCallback(ReceiveCallback), state);
state.dataSizeReceived = true; //received data size?
dataSize = state.dataSize;
buffer = state.buffer.ToArray();
dataSizeReceived = state.dataSizeReceived;
string hex = ByteArrayToString(state.buffer, state.dataSize);
Console.WriteLine("<- " + hex);
receiveDone.Set();
client.Close();
}
else
{
Console.WriteLine("All the data has arrived");
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
Console.WriteLine("Length: " + state.sb.Length.ToString());
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
Another solution would be to send "yourself" a "control message" using a socket bound to a different port. It's not exactly an abort, but it would end your async operation.
I was struggling with this as well but as far as I can tell using a simple boolean flag before calling .BeginReceive() will work as well (so there'll be no need for exception handling). Since I already had start/stop handling, this fix was a matter of one if statement (scroll down to the bottom of the OnReceive() method).
if (_running)
{
_mainSocket.BeginReceive(_data, 0, _data.Length, SocketFlags.None, OnReceive, null);
}
Should I have overlooked something with this approach, let me know!
Is there a reason why a Socket should close by itself, after 2h? I am receiving data every second from this socket, and writing back some tiny "keep-alive" data every 30s.
Before sending, I check if socket is still connected using the following method:
public bool IsSocketReadyForWriting(Socket s)
{
try
{
if (!s.Connected)
{
Log.Info("Socket.Connected was false");
return false;
}
// following line will throw if socket disconnected
bool poll = s.Poll(2000, SelectMode.SelectWrite);
if (!poll)
{
try
{
// if poll is false, socket is closed
Log.Info("poll is false");
this.Close();
}
catch { }
return false;
}
Log.Debug("still connected");
return true;
}
catch (Exception ex)
{
Log.Error("Error while checking if socket connected", ex);
return false;
}
}
Everything works fine for about 2h, then suddenly Socket.Poll returns false, and the Socket gets closed.
Is there a setting which controls this, or am I doing something really wrong?
[Edit]
Forgot to mention: I control both server and client side of the link. These are both C# apps, one of them creates a listening socket, the other one opens a connection and sends data. They communicate without problems for 2h (no memory leaks and stuff), then the socket closes.
When this happens, I can reconnect the socket again easily, but I am just wandering if anyone knows why could be the reason for this.
By default a TCP socket is writable when there's at least one byte of space available in the socket send buffer. To reverse that - the socket is not writable when there's enough unacknowledged data sitting in the "output queue".
That said, pull out wireshark or whatever Microsoft provides for packet sniffing and see what's going on on the wire. Are your heartbeat chunks getting ACK-ed? Does the receiver window stay open or does it go to zero? Or are you just getting explicit RST or a FIN from some intermediate switch?
One way to mitigate temporary clogged pipe is to increase the send buffer size, which is kind of tiny by default on Windows - 8192 iirc. See the setsockopt (.NET probably has a version of that) and the SO_SNDBUF option.
Could be the server that is closing the connection? Do you have control over it?
With respect to C# and .NET's System.Net.Sockets.Socket.AcceptAsync method, one would be required to handle a return value of "false" in order to handle the immediately available SocketAsyncEventArgs state from the synchronously processed connection. Microsoft provides examples (found on the System.Net.Sockets.SocketAsyncEventArgs class page) which will cause a stack overflow if there are a large amount of pending connections, which can be exploited on any system that implements their handling model.
Other ideas for getting around this issue are to make a loop that calls the handler method, with the condition being that the value Socket.AcceptAsync returns is equal to false, and to break the loop (to allow deferred processing) if the value is indicating that the operation is being completed asynchronously (true). However, this solution also causes a stack overflow vulnerability because of the fact that the callback associated with the SocketAsyncEventArgs passed to Socket.AcceptAsync has at the end of the method, a call to Socket.AcceptAsync, which also has a loop for immediately available, synchronously accepted, connections.
As you can see, this is a pretty solid problem, and I've yet to find a good solution that does not involve System.Threading.ThreadPool and creating tons of other methods and scheduling processing. As far as I can see, the asynchronous socket model relating to Socket.AcceptAsync requires more than what is demonstrated in the examples on MSDN.
Does anyone have a clean and efficient solution to handling immediately pending connections that are accepted synchronously from Socket.AcceptAsync without going into creating separate threads to handle the connections and without utilizing recursion?
I wouldn't use AcceptAsync, but rather BeginAccept/EndAccept, and implement the common async pattern correctly, that is, checking for CompletedSynchronously to avoid callbacks in the callback thread on operations which completed .
See also AsyncCallBack CompletedSynchronously
Edit regarding the requirement to use AcceptAsync:
The MSDN documentation explicitly says that the callback will NOT be invoked for operations which completed synchronously. This is different to the common async pattern where the callback is always invoked.
Returns true if the I/O operation is
pending. The
SocketAsyncEventArgs.Completed event
on the e parameter will be raised upon
completion of the operation. Returns
false if the I/O operation completed
synchronously. The
SocketAsyncEventArgs.Completed event
on the e parameter will not be raised
and the e object passed as a parameter
may be examined immediately after the
method call returns to retrieve the
result of the operation.
I currently don't see how a loop would not solve the stack overflow issue. Maybe you can be more specific on the code that causes the problem?
Edit 2: I'm thinking of code like this (only in regard to AcceptAsync, the rest was just to get a working app to try it out with):
static void Main(string[] args) {
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(new IPEndPoint(IPAddress.Loopback, 4444));
listenSocket.Listen(100);
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.Completed += AcceptCallback;
if (!listenSocket.AcceptAsync(e)) {
AcceptCallback(listenSocket, e);
}
Console.ReadKey(true);
}
private static void AcceptCallback(object sender, SocketAsyncEventArgs e) {
Socket listenSocket = (Socket)sender;
do {
try {
Socket newSocket = e.AcceptSocket;
Debug.Assert(newSocket != null);
// do your magic here with the new socket
newSocket.Send(Encoding.ASCII.GetBytes("Hello socket!"));
newSocket.Disconnect(false);
newSocket.Close();
} catch {
// handle any exceptions here;
} finally {
e.AcceptSocket = null; // to enable reuse
}
} while (!listenSocket.AcceptAsync(e));
}
I have resolved this problem by simply changing the placement of the loop. Instead of recursively calling the accept handler from within itself, wrapping the code in a do-while loop with the condition being "!Socket.AcceptAsync(args)" prevents a stack overflow.
The reasoning behind this is that you utilize the callback thread for processing the connections which are immediately available, before bothering to asynchronously wait for other connections to come across. It's re-using a pooled thread, effectively.
I appreciate the responses but for some reason none of them clicked with me and didn't really resolve the issue. However, it seems something in there triggered my mind into coming up with that idea. It avoids manually working with the ThreadPool class and doesn't use recursion.
Of course, if someone has a better solution or even an alternative, I'd be happy to hear it.
I haven't looked carefully, but it smells like this might be helpful (see the section called "stack dive"):
http://blogs.msdn.com/b/mjm/archive/2005/05/04/414793.aspx
newSocket.Send(Encoding.ASCII.GetBytes("Hello socket!"));
newSocket.Disconnect(false);
newSocket.Close();
The problem with this snippet above is that this will block your next accept operation.
A better way is like this:
while (true)
{
if (e.SocketError == SocketError.Success)
{
//ReadEventArg object user token
SocketAsyncEventArgs readEventArgs = m_readWritePool.Pop();
Socket socket = ((AsyncUserToken)readEventArgs.UserToken).Socket = e.AcceptSocket;
if (!socket.ReceiveAsync(readEventArgs))
ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessReceiveEx), readEventArgs); .
}
else
{
HadleBadAccept(e);
}
e.AcceptSocket = null;
m_maxNumberAcceptedClients.WaitOne();
if (listenSocket.AcceptAsync(e))
break;
}
The SocketTaskExtensions contains useful method overloads for the Socket class. Rather than using the AsyncCallback pattern, the AcceptAsync extension method can be called with ease. It is also compatible with the task asynchronous programming (TAP) model.
There is two basic operation to consider:
Start the listening: As usual socket needs to Bind to a specific IP address and port. Then place the socket in listening state (Listen method). After that it is ready to handle the incoming communication.
Stop the listening: It stops accepting the incoming requests.
bool _isListening = false;
public Task<bool> StartListening()
{
Socket listeningSocket = new Socket(SocketType.Stream, ProtocolType.Tcp);
listeningSocket.Bind(new IPEndPoint(IPAddress.Any, 0));
listeningSocket.Listen(10);
return HandleRequests(listeningSocket);
}
public void StopListening()
{
_isListening = false;
}
In order to handle incoming requests, the listening socket accepts (AcceptAsync) the incoming client connection. Then Send or Receive message from the accepted socket. It accepts incoming connection until StopListening was called.
internal async Task<bool> HandleRequests(Socket listeningSocket)
{
try
{
_isListening = true;
while (_isListening)
{
byte[] message = Encoding.UTF8.GetBytes("Message");
byte[] receivedMessage = new byte[1024];
using (Socket acceptedSocket = await listeningSocket.AcceptAsync())
{
// Send messages
acceptedSocket.Send(message);
// Receive messagges
acceptedSocket.Receive(receivedMessage);
}
}
}
catch (SocketException)
{
// Handle error during communication.
return false;
}
return true;
}
Note:
Messages could be exceed the buffer size. In that case try continuously receive until end of the data. Stephen Clearly message framing blog post is good starting point.
Sending and receiving also could be asynchronous. NetworkStream can be created from the accepted socket then we can await to the ReadAsnyc and WriteAsync operations.