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.
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 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.
Windows store applications are frustrating to say the least; just close enough to regular .net to get into trouble.
My issue with working in Tasks, await, and Socket.ConnectAsync.
I've got the following code:
public async Task<string> Connect(string hostName, int portNumber)
{
string result = string.Empty;
// Create DnsEndPoint. The hostName and port are passed in to this method.
DnsEndPoint hostEntry = new DnsEndPoint(hostName, portNumber);
// Create a stream-based, TCP socket using the InterNetwork Address Family.
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Create a SocketAsyncEventArgs object to be used in the connection request
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = hostEntry;
// Inline event handler for the Completed event.
// Note: This event handler was implemented inline in order to make this method self-contained.
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate (object s, SocketAsyncEventArgs e)
{
// Retrieve the result of this request
result = e.SocketError.ToString();
// Signal that the request is complete, unblocking the UI thread
_clientDone.Set();
});
// Sets the state of the event to nonsignaled, causing threads to block
_clientDone.Reset();
// Make an asynchronous Connect request over the socket
await _socket.ConnectAsync(socketEventArg);
// Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
// If no response comes back within this time then proceed
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
return result;
}
And I started added in Async / await to the app to prevent UI issues. But when I went into this function and added the Await to
await _socket.ConnectAsync(socketEventArg);
I get the error:
Error CS1929 'bool' does not contain a definition for 'GetAwaiter' and the best extension method overload 'WindowsRuntimeSystemExtensions.GetAwaiter(IAsyncAction)' requires a receiver of type 'IAsyncAction'
In looking at the docs for ConnectAsync it looks like ConnectAsync is supposed to support await...
Does it not support await?
No, ConnectAsync is not a TAP method, and thus cannot be used with await.
My #1 recommendation for anyone using raw sockets is "don't". If you can, use a REST API (with HttpClient) or a SignalR API. Raw sockets have tons of pitfalls.
If you must use raw sockets (i.e., the other side is using a custom TCP/IP protocol and you don't have the power to fix the situation), then the first thing to note is that the Socket class has three complete APIs all in one class.
The first is the deceptively simple-looking synchronous API (Connect), which I do not recommend for any production code. The second is the standard APM pattern (BeginConnect/EndConnect). The third is a specialized asynchronous pattern that is specific to the Socket class (ConnectAsync); this specialized API is much more complex to use than the standard asynchronous API, and is only necessary when you have chatty socket communication in a constrained environment, and need to reduce the object churn through the garbage collector.
Note that there is no await-compatible API. I haven't spoken to anyone at Microsoft about this, but my strong suspicion is that they simply thought the Socket class had too many members already (3 complete APIs; adding an await-compatible one would add a fourth complete API), and that's why it was skipped over when they added TAP-pattern (await-compatible) members to other types in the BCL.
The correct API to use - easily 99.999% of the time - is the APM one. You can create your own TAP wrappers (which work with await) by using TaskFactory.FromAsync. I like to do this with extension methods, like this:
public static Task ConnectTaskAsync(this Socket socket, EndPoint remoteEP)
{
return Task.Factory.FromAsync(socket.BeginConnect, socket.EndConnect, remoteEP, null);
}
You can then invoke it anywhere on a Socket, as such:
await _socket.ConnectTaskAsync(hostEntry);
I currently have a background thread. In this thread is a infinite loop.
This loop once in a while updates some values in a database, and then listens 1 second on the MessageQueue (with queue.Receive(TimeSpan.FromSeconds(1)) ).
As long as no message comes in, this call then internally throws a MessageQueueException (Timeout) which is caught and then the loop continues. If there is a message the call normally returns and the message is processed, after which the loop continues.
This leads to a lot of First chance exceptions (every second, except there is a message to process) and this spams the debug output and also breaks in the debugger when I forgot to exclude MessageQueueExceptions.
So how is the async handling of the MessageQueue meant to be done correctly, while still ensuring that, as long as my application runs, the queue is monitored and the database is updated too once in a while. Of course the thread here should not use up 100% CPU.
I just need the big picture or a hint to some correctly done async processing.
Rather than looping in a thread, I would recommend registering a delegate for the ReceiveCompleted event of your MessageQueue, as described here:
using System;
using System.Messaging;
namespace MyProject
{
///
/// Provides a container class for the example.
///
public class MyNewQueue
{
//**************************************************
// Provides an entry point into the application.
//
// This example performs asynchronous receive operation
// processing.
//**************************************************
public static void Main()
{
// Create an instance of MessageQueue. Set its formatter.
MessageQueue myQueue = new MessageQueue(".\\myQueue");
myQueue.Formatter = new XmlMessageFormatter(new Type[]
{typeof(String)});
// Add an event handler for the ReceiveCompleted event.
myQueue.ReceiveCompleted += new
ReceiveCompletedEventHandler(MyReceiveCompleted);
// Begin the asynchronous receive operation.
myQueue.BeginReceive();
// Do other work on the current thread.
return;
}
//**************************************************
// Provides an event handler for the ReceiveCompleted
// event.
//**************************************************
private static void MyReceiveCompleted(Object source,
ReceiveCompletedEventArgs asyncResult)
{
// Connect to the queue.
MessageQueue mq = (MessageQueue)source;
// End the asynchronous Receive operation.
Message m = mq.EndReceive(asyncResult.AsyncResult);
// Display message information on the screen.
Console.WriteLine("Message: " + (string)m.Body);
// Restart the asynchronous Receive operation.
mq.BeginReceive();
return;
}
}
}
Source: https://learn.microsoft.com/en-us/dotnet/api/system.messaging.messagequeue.receivecompleted?view=netframework-4.7.2
Have you considered a MessageEnumerator which is returned from the MessageQueue.GetMessageEnumerator2 ?
You get a dynamic content of the queue to examine and remove messages from a queue during the iteration.
If there are no messages then MoveNext() will return false and you don't need to catch first-chance exceptions
If there are new messages after you started iteration then they will be iterated over (if they are put after a cursor).
If there are new messages before a cursor then you can just reset an iterator or continue (if you don't need messages with lower priority at the moment).
Contrary to the comment by Jamie Dixon, the scenario IS exceptional. Note the naming of the method and its parameters: BeginReceive(TimeSpan timeout)
Had the method been named BeginTryReceive, it would've been perfectly normal if no message was received. Naming it BeginReceive (or Receive, for the sync version) implies that a message is expected to enter the queue. That the TimeSpan parameter is named timeout is also significant, because a timeout IS exceptional. A timeout means that a response was expected, but none was given, and the caller chooses to stop waiting and assumes that an error has occured. When you call BeginReceive/Receive with a 1 second timeout, you are stating that if no message has entered the queue by that time, something must have gone wrong and we need to handle it.
The way I would implement this, if I understand what you want to do correctly, is this:
Call BeginReceive either with a very large timeout, or even without a timeout if I don't see an empty queue as an error.
Attach an event handler to the ReceiveCompleted event, which 1) processes the message, and 2) calls BeginReceive again.
I would NOT use an infinite loop. This is both bad practice and completely redundant when using asynchronous methods like BeginReceive.
edit: To abandon a queue which isn't being read by any client, have the queue writers peek into the queue to determine if it is 'dead'.
edit: I have another suggestion. Since I don't know the details of your application I have no idea if it is either feasible or appropriate. It seems to me that you're basically establishing a connection between client and server, with the message queue as the communication channel. Why is this a 'connection'? Because the queue won't be written to if no one is listening. That's pretty much what a connection is, I think. Wouldn't it be more appropriate to use sockets or named pipes to transfer the messages? That way, the clients simply close the Stream objects when they are done reading, and the servers are immediately notified. As I said, I don't know if it can work for what you're doing, but it feels like a more appropriate communication channel.
While attempting to send a message for a queue through the BeginSend call seem te behave as a blocking call.
Specificly I have:
public void Send(MyMessage message)
{
lock(SEND_LOCK){
var state = ...
try {
log.Info("Begin Sending...");
socket.BeginSend(message.AsBytes(),0, message.ByteLength, SocketFlags.None,
(r) => EndSend(r), state);
log.Info("Begin Send Complete.");
}
catch (SocketException e) {
...
}
}
}
The callback would be something like this:
private void EndSend(IAsyncResult result) {
log.Info("EndSend: Ending send.");
var state = (MySendState) result.AsyncState;
...
state.Socket.EndSend(result, out code);
log.Info("EndSend: Send ended.");
WaitUntilNewMessageInQueue();
SendNextMessage();
}
Most of the time this works fine, but sometimes it hangs. Logging indicates this happens when BeginSend en EndSend are excecuted on the same Thread. The WaitUntilNewMessageInQueue blocks until there is a new message in the queue, so when there is no new message it can wait quit a while.
As far as I can tell this should not really be a problem, but in the some cases BeginSend blocks causing a deadlock situation where EndSend is blocking on WaitUntilNewMessageInQueue (expected), but Send is blocking on BeginSend in return as it seems te be waiting for the EndSend callback te return (not expected).
This behaviour was not what I was expecting. Why does BeginSend sometimes block if the callback does not return in timely fashion?
First of all, why are you locking in your Send method? The lock will be released before the send is complete since you are using BeginSend. The result is that multiple sends can be executing at the same time.
Secondly, do not write (r) => EndSend(r), just write EndSend (without any parameters).
Thrid: You do not need to include the socket in your state. Your EndSend method is working like any other instance method. You can therefore access the socket field directly.
As for your deadlocks, it's hard to tell. You delegate may have something to do with it (optimizations by the compiler / runner). But I have no knowledge in that area.
Need more help? Post more code. but I suggest that you fix the issues above (all four of them) and try again first.
Which operating system are you running on?
Are you sure you're seeing what you think you're seeing?
The notes on the MSDN page say that Send() CAN block if there's no OS buffer space to initiate your async send unless you have put the socket in non blocking mode. Could that be the case? Are you potentially sending data very quickly and filling the TCP window to the peer? If you break into the debugger what does the call stack show?
The rest is speculation based on my understanding of the underlying native technologies involved...
The notes for Send() are likely wrong about I/O being cancelled if the thread exits, this almost certainly depends on the underlying OS as it's a low level IO Completion Port/overlapped I/O issue that changed with Windows Vista (see here: http://www.lenholgate.com/blog/2008/02/major-vista-overlapped-io-change.html) and given that they're wrong about that then they could be wrong about how the completions (calls to EndSend() are dispatched on later operating systems). From Vista onwards it's possible that the completions could be dispatched on the issuing thread if the .Net sockets wrapper is enabling the correct options on the socket (see here where I talk about FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)... However, if this were the case then it's likely that you'd see this behaviour a lot as initially most sends are likely to complete 'in line' and so you'd see most completions happening on the same thread - I'm pretty sure that this is NOT the case and that .Net does NOT enable this option without asking...
This is how you check if it completed synchronously so you avoid the callback on another thread.
For a single send:
var result = socket.BeginSend(...);
if (result.CompletedSynchronously)
{
socket.EndSend(result);
}
For a queue of multiple sends, you can just loop and finalize all synchronous sends:
while (true)
{
var result = socket.BeginSend(...);
if (!result.CompletedSynchronously)
{
break;
}
socket.EndSend(result);
}