I am trying to create a non-blocking socket in WM6 C# but I keep getting the following compiler error:
"Synchronous calls are not supported on non-blocking sockets. Set Blocking=true or use the asynchronous methods."
However when I use the BeginReceive() asynchronous methods, the EndReceive() is blocked. Same for BeginSend() and EndSend(). How do you do a non-blocking socket within the compact framework?
Here's my code. I am not using an AsyncCallback method because I want to return the bytesRecv and bytesSent variables.
private void asyncReceive(byte[] recvBytes, int offset, int size, SocketFlags sf)
{
IAsyncResult asyncResult = null;
int recvBytes = 0;
try
{
asyncResult = _socket.BeginSend(sendBytes, offset, size, sf, null, null);
recvBytes = _socket.EndSend(asyncResult); // <-- This blocks even with _socket.Blocking = false;
}
catch (SocketException)
{
//Check SocketException.ErrorCode...
}
return recvBytes;
}
Looks like you're missing the point- the behavior you're seeing is by design. I'd suggest reading up on async programming in .NET (lots of resources- maybe start here). Non-blocking socket reads/writes with BeginXXX will allow you to start the send/receive, then go do something else and be notified by the kernel when it's done (via the AsyncCallback), at which point you'd call the corresponding EndXXX method to get the result. If you call EndXXX right after the BeginXXX call before the operation is complete, it's designed to block until completion.
To get non-blocking behavior, you'll need to break up your code a bit to handle the callback correctly (eg, marshal the result back to your UI, whatever). You won't have the answer as to how many bytes were sent/received until that's actually been done by the underlying kernel bits.
Related
I am using NetworkStream with TcpClient.
First I setup my tcp client:
tcp = new TcpClient(AddressFamily.InterNetwork)
{ NoDelay = true, ReceiveTimeout = 5000};
My main data-receiving loop:
while (true)
{
//read available data from the device
int numBytesRead = await ReadAsync();
Console.WriteLine($"{numBytesRead} bytes read"); //BP2
}
And the actual TCP data reading:
public Task<int> ReadAsync()
{
var stream = tcp.GetStream();
return stream.ReadAsync(InBuffer, 0, InBuffer.Length); //BP1
}
I have this connected to a testbed which lets me send manual packets. Through setting breakpoints and debugging I have checked that stream.ReadTimeout takes the value 5000 from tcp.
If I send data frequently it all works as expected. But if I don't send any data, nothing appears to happen after 5s, no timeout. I see breakpoint BP1 being hit in the debugger but until I send data from my testbed, BP2 is not hit. I can leave it a minute or more and it just seems to sit waiting, but receives data sent after a minute, which appears to be incorrect behavior. After 5 seconds something should happen, surely (an exception as I understand it)?
It's late so I am expecting something really basic but can anyone see what my mistake is and a resolution?
Addendum
OK so when I RTFM for the actual .Net version I'm using (how may times have I been caught out by MS defaulting to .Net Core 3, I did say it was late) I see in the remarks sectio for ReadTimeout:
This property affects only synchronous reads performed by calling the
Read method. This property does not affect asynchronous reads
performed by calling the BeginRead method.
I'm unclear now if I can use modern awaitable calls at all to read socket data safely and with a timeout specifically. It's working except for the timeout but I'm not sure how given ReadAsync has no override in NetworkStream. Must I do some ugly hack or is there a simple solution?
In my case 5000 is the longest I can expect not to receive data before concluding there is a problem - the protocol has no ping mechanism so if nothing appears I assume the connection is dead. Hence thinking an Async read with a 5000ms timeout would be nice and neat.
Timeout values for network objects apply only to synchronous operations. For example, from the documentation:
This option applies to synchronous Receive calls only.
For Socket.ReceiveTimeout, TcpClient.ReceiveTimeout, and NetworkStream.ReadTimeout, the implementations all ultimately result in a call to SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, ...) which in turn is effectively calling the native setsockopt() function. From that documentation:
SO_RCVTIMEO DWORD Sets the timeout, in milliseconds, for blocking receive calls.
(emphasis mine)
It's this limitation in the underlying native API that is the reason for the same limitation in the managed API. Timeout values will not apply to asynchronous I/O on the network objects.
You will need to implement the timeout yourself, by closing the socket if and when the timeout should occur. For example:
async Task<int> ReadAsync(TcpClient client, byte[] buffer, int index, int length, TimeSpan timeout)
{
Task<int> result = client.GetStream().ReadAsync(buffer, index, length);
await Task.WhenAny(result, Task.Delay(timeout));
if (!result.IsCompleted)
{
client.Close();
}
return await result;
}
Other variations on this theme can be found in other related questions:
NetworkStream.ReadAsync with a cancellation token never cancels
Cancel C# 4.5 TcpClient ReadAsync by timeout
Closing the socket is really all that you can do. Even for synchronous operations, if a timeout occurs the socket would no longer be usable. There is no reliable way to interrupt a read operation and expect the socket to remain consistent.
Of course, you do have the option of prompting the user before closing the socket. However, if you were to do that, you would implement the timeout at a higher level in your application architecture, such that the I/O operations themselves have no awareness of timeouts at all.
I am a farily new .NET-developer and I'm currently reading up on async/await. I need to work on a framework used for testing devices that are controlled by remotely accessing servers using TCP and reading/writing data from/to these servers. This will be used for unit tests.
There is no application-layer protocol and the server may send data based on external events. Therefore I must be able to continuously capture any data coming from the server and write it to a buffer, which can be read from a different context.
My idea goes somewhere along the lines of the following snippet:
// ...
private MemoryStream m_dataBuffer;
private NetworkStream m_stream;
// ...
public async void Listen()
{
while (Connected)
{
try
{
int bytesReadable = m_dataBuffer.Capacity - (int)m_dataBuffer.Position;
// (...) resize m_dataBuffer if necessary (...)
m_stream.ReadTimeout = Timeout;
lock (m_dataBuffer)
{
int bytesRead = await m_stream.ReadAsync(m_dataBuffer.GetBuffer(),
(int)m_dataBuffer.Position, bytesReadable);
m_stream.Position += bytesRead;
}
}
catch (IOException ex)
{
// handle read timeout.
}
catch (Exception)
{
throw new TerminalException("ReadWhileConnectedAsync() exception");
}
}
}
This seems to have the following disadvantages:
If calling and awaiting the Listen function, the caller hangs, even though the caller must be able to continue (as the network stream should be read as long as the connection is open).
If declaring it async void and not awaiting it, the application crashes when exceptions occur in the Task.
If declaring it async Task and not awaiting it, I assume the same happens (plus I get a warning)?
The following questions ensue:
Can I catch exceptions thrown in Listen if I don't await it?
Is there a better way to constantly read from a network stream using async/await?
Is it actually sane to try to continuously read from a network stream using async/await or is a thread a better option?
async void should at the very least be async Task with the return value thrown away. That makes the method adhere to sane standards and pushes the responsibility into the caller which is better equipped to make decisions about waiting and error handling.
But you don't have to throw away the return value. You can attach a logging continuation:
async Task Log(Task t) {
try { await t; }
catch ...
}
And use it like this:
Log(Listen());
Throw away the task returned by Log (or, await it if you wish to logically wait).
Or, simply wrap everything in Listen in a try-catch. This appears to be the case already.
Can I catch exceptions thrown in Listen if I don't await it?
You can find out about exceptions using any way that attaches a continuation or waits synchronously (the latter is not your strategy).
Is there a better way to constantly read from a network stream using async/await?
No, this is the way it's supposed to be done. At any given time there should be one read IO outstanding. (Or zero for a brief period of time.)
Is it actually sane to try to continuously read from a network stream using async/await or is a thread a better option?
Both will work correctly. There is a trade-off to be made. Synchronous code can be simpler, easier to debug and even less CPU intensive. Asynchronous code saved on thread stack memory and context switches. In UI apps await has significant benefits.
I would do something like this:
const int MaxBufferSize = ... ;
Queue<byte> m_buffer = new Queue<byte>(MaxBufferSize);
NetworkStream m_stream = ... ;
...
// this will create a thread that reads bytes from
// the network stream and writes them into the buffer
Task.Run(() => ReadNetworkStream());
private static void ReadNetworkStream()
{
while (true)
{
var next = m_stream.ReadByte();
if (next < 0) break; // no more data
while (m_buffer.Count >= maxBufferSize)
m_buffer.Dequeue(); // drop front
m_buffer.Enqueue((byte)next);
}
}
When I call BeginExecuteReader (SQL) does it use IO Completion Ports? What makes it to be asynchronous? Should I call it from Begin[Operation]() or from the wrapper for IAsyncResult constructor?
does it use IO Completion Ports
Maybe, but that's an implementation detail deep in the native SQL Client's implementation.
Remember the SQL Server ADO.NET calls into the (local) native SQL Server client which will perform communication with the server.
What makes it to be async?
Its implementation. There is more than one way to do this, from approaches which fake it (perform blocking operations with a dedicated worker thread) through to IO Completion Ports and other "true" asynchronous APIs.
Where from should I call it ?
Wherever is right for your design.
for IAsyncResult constructor?
How you use the asynchronous APIs (callback passed to BeginExecuteReader, poll the returned IAsyncResult's IsComplete, wait on IAsyncResult, convert to a Task with TaskFactory.FromAsync, using the Reactive Extensions with Observable.FromAsyncPattern, or something else) is again part of the design of your code.
There are too many possibilities to give any form of guidance.
Whether or not the method uses IO Completion Ports is up to the implementation.
The call is asynchronous if it returns before the work is completed. Obviously that's also up to the implementation.
The standard way to use it would be
{
...
var fs = new FileStream(...); // using FileStream as an example
var data = new byte[100];
var ar = fs.BeginRead(data, 0, 100, MyCallback, new object[] { fs, data });
...
// you can check the IAsyncResult ar for completion,
// or do some work that doesn't depend on the data
}
private void MyCallback(IAsyncResult ar)
{
// AsyncState gets the last parameter from the call to BeginRead
var fs = (FileStream)(((object[])ar.AsyncState)[0]);
var data = (FileStream)(((object[])ar.AsyncState)[1]);
int numberOfBytesRead = fs.EndRead(ar);
// do something with data
}
You could also use a lambda expression as for a callback of course. With lambdas the state doesn't have to be captured manually so you could use it like
var ar = fs.BeginRead(data, 0, 100, result =>
{
int numberOfBytesRead = fs.EndRead(result);
// do something with data
}, null);
Ok, I think I have understood the whole async/await thing. Whenever you await something, the function you're running returns, allowing the current thread to do something else while the async function completes. The advantage is that you don't start a new thread.
This is not that hard to understand as it's somewhat how Node.JS works, except Node uses alot of callbacks to make this happen. This is where I fail to understand the advantage however.
The socket class doesn't currently have any Async methods (that work with async/await). I can of course pass a socket to the stream class, and use the async methods there, however this leaves a problem with the accepting of new sockets.
There are two ways of doing this, as far as I know. In both cases I accept new sockets in an infinite loop on the main thread. In the first case I can start a new task for every socket that I accept, and run the stream.ReceiveAsync within that task. However, won't an await actually block that task, since the task will have nothing else to do? Which again will result in more threads spawned on the threadpool, which again is no better than using synchronous methods inside a task?
My second option is to put all accepted sockets in one of several lists (one list per thread), and inside those threads run a loop, running await stream.ReceiveAsync for every socket. This way, whenever i run into await, stream.ReceiveAsync and start receiving from all other sockets.
I guess my real question is if this is in any way more effective than a threadpool, and in the first case, if it really will be worse than just using the APM methods.
I also know you can wrap APM methods into functions using await/async, but the way I see it, you still get the "disadvantage" of APM methods, with the extra overhead of state machines in async/await.
The async socket API is not based around Task[<T>], so it isn't directly usable from async/await - but you can bridge that fairly easily - for example (completely untested):
public class AsyncSocketWrapper : IDisposable
{
public void Dispose()
{
var tmp = socket;
socket = null;
if(tmp != null) tmp.Dispose();
}
public AsyncSocketWrapper(Socket socket)
{
this.socket = socket;
args = new SocketAsyncEventArgs();
args.Completed += args_Completed;
}
void args_Completed(object sender, SocketAsyncEventArgs e)
{
// might want to switch on e.LastOperation
var source = (TaskCompletionSource<int>)e.UserToken;
if (ShouldSetResult(source, args)) source.TrySetResult(args.BytesTransferred);
}
private Socket socket;
private readonly SocketAsyncEventArgs args;
public Task<int> ReceiveAsync(byte[] buffer, int offset, int count)
{
TaskCompletionSource<int> source = new TaskCompletionSource<int>();
try
{
args.SetBuffer(buffer, offset, count);
args.UserToken = source;
if (!socket.ReceiveAsync(args))
{
if (ShouldSetResult(source, args))
{
return Task.FromResult(args.BytesTransferred);
}
}
}
catch (Exception ex)
{
source.TrySetException(ex);
}
return source.Task;
}
static bool ShouldSetResult<T>(TaskCompletionSource<T> source, SocketAsyncEventArgs args)
{
if (args.SocketError == SocketError.Success) return true;
var ex = new InvalidOperationException(args.SocketError.ToString());
source.TrySetException(ex);
return false;
}
}
Note: you should probably avoid running the receives in a loop - I would advise making each socket responsible for pumping itself as it receives data. The only thing you need a loop for is to periodically sweep for zombies, since not all socket deaths are detectable.
Note also that the raw async socket API is perfectly usable without Task[<T>] - I use that extensively. While await may have uses here, it is not essential.
This is not that hard to understand as it's somewhat how Node.JS works, except Node uses alot of callbacks to make this happen. This is where I fail to understand the advantage however.
Node.js does use callbacks, but it has one other significant facet that really simplifies those callbacks: they are all serialized to the same thread. So when you're looking at asynchronous callbacks in .NET, you're usually dealing with multithreading as well as asynchronous programming (except for EAP-style callbacks).
Asynchronous programming using callbacks is called "continuation-passing style" (CPS). It's the only real option for Node.js but is one of many options on .NET. In particular, CPS code can get extremely complex and difficult to maintain, so the async/await compiler transform was introduced so you could write "normal-looking" code and the compiler would translate it to CPS for you.
In both cases I accept new sockets in an infinite loop on the main thread.
If you're writing a server, then yes, somewhere you will be repeatedly accepting new client connections. Also, you should be continuously reading from each connected socket, so each socket also has a loop.
In the first case I can start a new task for every socket that I accept, and run the stream.ReceiveAsync within that task.
You wouldn't need a new task. That's the whole point of asynchronous programming.
My second option is to put all accepted sockets in one of several lists (one list per thread), and inside those threads run a loop, running await stream.ReceiveAsync for every socket.
I'm not sure why you'd need multiple threads, or any dedicated threads at all.
You seem a bit confused on how async and await work. I recommend reading my own introduction, the MSDN overview, the Task-Based Asynchronous Pattern guidance, and the async FAQ, in that order.
I also know you can wrap APM methods into functions using await/async, but the way I see it, you still get the "disadvantage" of APM methods, with the extra overhead of state machines in async/await.
I'm not sure what disadvantage you're referring to. The overhead of state machines, while non-zero, is negligible in the face of socket I/O.
If you're looking to do socket I/O, you have several options. For reads, you can either do them in an "infinite" loop using APM or Task wrappers around the APM or Async methods. Alternatively, you could convert them into a stream-like abstraction using Rx or TPL Dataflow.
Another option is a library I wrote a few years ago called Nito.Async. It provides EAP-style (event-based) sockets that handle all the thread marshaling for you, so you end up with something simpler like Node.js. Of course, like Node.js, this simplicity means it won't scale as well as a more complex solution.
Ok I want to connect to a Socket and read a network stream using the System.Net.Sockets.NetworkStream class. This is what I have so far:
NetworkStream myNetworkStream;
Socket socket;
socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw,
ProtocolType.IPv4);
socket.Connect(IPAddress.Parse("8.8.8.8"), 8888);
myNetworkStream = new NetworkStream(socket);
byte[] buffer = new byte[1024];
int offset = 0;
int count = 1024;
myNetworkStream.BeginRead(buffer, offset, count, ??, ??);
Now I need an AsyncCallback and an Object state to complete my BeginRead method but I'm not even sure if this is going to work. I'm a bit lost at this point! Where do I need to go from here?
Basically, when you call the Begin* method on an asynchronous operation, there needs to be a call to a corresponding End* statement (for more detailed information, see the Asynchronous Programming Overview on MSDN, specifically the section titled "Ending an Asynchronous Operation").
That said, you generally want to pass a method/anonymous method/lambda expression which will do one or two things:
1) Call the corresponding End* method, in this case, Stream.EndRead. This call will not block when called because the callback will not be called until the operation is complete (note that if an exception occurred during the async call then this exception will be thrown when the End* method is called).
2) Possibly start a new asynchronous call. In this case, it's assumed you'll want to read more data, so you should start a new call to Stream.BeginRead
Assuming you want to do #2, you can do the following:
// Declare the callback. Need to do that so that
// the closure captures it.
AsyncCallback callback = null;
// Assign the callback.
callback = ar => {
// Call EndRead.
int bytesRead = myNetworkStream.EndRead(ar);
// Process the bytes here.
// Determine if you want to read again. If not, return.
if (!notMoreToRead) return;
// Read again. This callback will be called again.
myNetworkStream.BeginRead(buffer, offset, count, callback, null);
};
// Trigger the initial read.
myNetworkStream.BeginRead(buffer, offset, count, callback, null);
However, if you are using .NET 4.0, this becomes much easier using the FromAsync method on the TaskFactory class.