In C# you have 3 ways to try and receive TCP data on a Socket:
Socket.Receive is a synchronous, blocking method. It doesn't return until it succeeds, barring failure or [optionally] timeout.
Socket.BeginReceive is asynchronous, a supplied callback/delegate is called when there is data to receive, using the now-antiquated Begin/End pattern
Socket.ReceiveAsync begins an asynchronous request to receive data
However my understanding is none of these actually let you cancel the receive operation? The docs suggest EndReceive is used for completing a read, not something one could call to terminate the request?
You often see code like
while(socket.Available==0 && !cancel)Sleep(50); if(!cancel)socket.Receive(...);
But that's pretty terrible.
If I want to sit waiting for data but at some point cancel the receive, say the user hits "stop" button how can this neatly be done so I don't get a callback triggered later on when unexpected?
I had wondered about closing the socket, which would cause the Receive operation to fail, but it seems somewhat ugly. Am I thinking along the right lines or do the various API methods listed above allow a direct cancellation so I don't risk dangling async operations?
There is no known way to cancel it (AFAIK)
One thing you can do it set the Socket.Blocking = false. The receive will return immediately when there is no data. This way it will not hang.
You should check the Socket.Blocking property.
I advise you to use the BeginReceive(IList<ArraySegment<Byte>>, SocketFlags, SocketError, AsyncCallback, Object) overload to prevent it throwing exceptions.
Check the SocketError on "Would Block", meaning "there is not data". So you can try again.
Didn't tested it but ->
A nice idea is using the non-async version Receive to receive 0 bytes (use a static byte[] emptyBuffer = new byte[0]) , and if the sockerError returns with a 'would block', you can have a short delay and retry it. When it doesn't return a socketError there is probably data. So you can start an async version.
What you could do is get a NetworkStream from the socket being read and use it's ReadTimeout property, for example:
// Get stream from socket:
using NetworkStream ns = new NetworkStream(socket);
// Set timeout:
stream.ReadTimeout = 10 * 1000; // 10 sec
var buffer = new List<byte>();
try
{
do
{
buffer.Add((byte) stream.ReadByte());
}
while (stream.DataAvailable);
}
catch (IOException)
{
// Timeout
}
return buffer.ToArray();
Related
I am new here and by no means an expert at c# programming.
I am writing an application that connects to a device over TCP. It sends the device a command and the device responds. Sometimes The device will send another message after it has responded to my command. For example if I say "Read Tag" It will respond with the tag value "Tag: abcdefg". But sometimes, after a couple of hundred milliseconds, it will respond with something like "Buffer Low: 14" telling me the size of its buffer.
Here is how I am currently receiving data:
public Task<string> ReceiveDataAsync()
{
receiveBuffer = new byte[receiveBufferSize];
Task<int> streamTask = _networkstream.ReadAsync(receiveBuffer, 0, receiveBufferSize);
// Since the read is async and data arrival is unknown, the event
// must sit around until there is something to be raised.
var resultTask = streamTask.ContinueWith<String>(antecedent =>
{
Array.Resize(ref receiveBuffer, streamTask.Result); // resize the result to the size of the data that was returned
var result = Encoding.ASCII.GetString(receiveBuffer);
OnDataReceived(new TCPEventArgs(result));
return result;
});
return resultTask;
}
I am confused about reading the network stream. When I use the ReadAsync method, and then I get something back, how do I handle the delay? In my mind, I get the first response of the tag data, then I start to work on that task. Even though I work on the task ".ContinueWith" will my stream continue to receive data? Will the task automatically go back and process more data as it comes in the stream? Do I need to call the ReceiveDataAsync method every time I think some data should be arriving or will it remain open until Dispose of the stream?
Yes, you need to call ReceiveDataAsync repeatedly, usually call it in callback of ContinueWith, or just put it in a loop if you use async/await, so that you read some data, process it and then go back to read (or wait) the next bytes.
Like this:
private static void OnContinuationAction(Task<string> text)
{
Console.WriteLine(text);
ReceiveDataAsync().ContinueWith(OnContinuationAction);
}
...
ReceiveDataAsync().ContinueWith(OnContinuationAction);
Or with async/await:
private async void ReceiveDataContinuously()
{
while(true)
{
var text = await ReceiveDataAsync();
Console.WriteLine(text);
}
}
If you don't call ReadAsync on the stream repeatedly, as long as the underlying TCP connection is open it will continue receiving data into the buffer, but your program cannot get them.
I have written a socket for a server in C++ CLI that is using winsock. The sockets are using async methods for sending, receiving and accepting connections. After implementing my socket in the production environment, the send function stops working giving me the error WSAEWOULDBLOCK. Out from my research on the net, this means the network buffer for socket IO is full or the networking is too busy to do my operation at this moment. However, I have not seen any specific solution which can address this problem. My temporary solution was to create a do-while loop around the WSASend function, making the thread sleep for X amount of MS and then try again. This resulted in far higher latency than the previous socket (.NET socket class) and large lag spikes.
My code for sending data is as following:
void Connectivity::ConnectionInformation::SendData(unsigned char data[], const int length)
{
if (isClosed || sendError)
return;
Monitor::Enter(this->syncRoot);
try
{
sendInfo->buf = (char*)data;
sendInfo->len = length;
do
{
state = 0;
if (WSASend(connection, sendInfo, 1, bytesSent, 0, NULL, NULL) == SOCKET_ERROR)
{
state = WSAGetLastError();
if (state == WSAEWOULDBLOCK)
{
Thread::Sleep(SleepTime);
//Means the networking is busy and we need to wait a bit for data to be sent
//Might wanna decrease the value since this could potentially lead to lagg
}
else if (state != WSA_IO_PENDING)
{
this->sendError = true;
//The send error bool makes sure that the close function doesn't get called
//during packet processing which could cause a lot of null reffernce exceptions.
}
}
}
while (state == WSAEWOULDBLOCK);
}
finally
{
Monitor::Exit(this->syncRoot);
}
}
Is there a way to use for example the WSAEventSelect method in order to get a callback when I am able to send data? Out from the documentation on MSDN, the wait for data method could also get stuck in this error. Anyone got any solutions for getting around this?
The error code WSAEWOULDBLOCK means that you attempted to operate on a non-blocking socket but the operation could not be completed immediately. This is not a real error - it means that you can retry later or schedule an asynchronous IO (which wouldn't fail). But this is not what you want in the first place. Let me explain:
You are supposed to use sockets in one of two ways:
Synchronous, blocking.
Asynchronous, non-blocking, callback-based.
You are mixing the two which gets you the worst of both. You created a non-blocking socket and use it in a potentially blocking way.
Alas I'm not full qualified to give best-practices for native-code sockets. I suggest you read all of the docs for WSASend because they seem to explain all of this.
Now, why would this strange error code even exist? It is a performance optimization. You can speculatively try to send synchronously (which is very fast). And only if it fails you are supposed to schedule an asynchronous IO. If you don't need that optimization (which you don't) don't do it.
As #usr says, I need to have either LPWSAOVERLAPPED or LPWSAOVERLAPPED_COMPLETION_ROUTINE set to a value in order to make the operation non-blocking. However, after testing, I found out I need t have a LPWSAOVERLAPPED object in order to make the completion routine called. It is also mentioned on MSDN on the documentation of the WSASend function that if the overlapped object and the completion routine is NULL, the socket would behave as a blocking socket.
Thanks, and merry xmas everyone! :)
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.
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!
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.