I have gRPC service define like below
service ConsumerService
{
stream Message Consume(SubscriptionRequest);
}
Client looks like this:
var consumer = new ConsumerService.ConsumerServiceClient(<channel>);
AsyncServerStreamingCall<Message> proxy = consumer.ConsumeAsync(subRequest));
while (!gracefulShutdown)
await proxy.ResponseStream.MoveNext(cts.Token);
// todo: tell the server that client is not going to read responses anymore..
await proxy.ResponseStream.CompleteAsync(); // I would like to have method like this
I need client to gracefully stop reading responses when gracefulShutdown is set to true.
How do I do this?
If i just stop reading and close channel, server considers it is as abort.
As much as i checked on internet i didnt found any way to do it gracefully. I expected to use CancellationTokenSource. Just use try, catch. Looks like this is intended behaviour. Comment from grpc team
Cancellations are to be used for forcing termination
of outstanding calls due to unexpected circumstances, you shouldn't rely on
them for handling the basic workflow in your application
Use catch block like here to check exception
catch (RpcException e) when (e.Status.StatusCode == StatusCode.Cancelled)
{
Console.WriteLine("Streaming was cancelled from the client!");
}
More info on github C# Clean Cancellation
Related
I am using Google PubSub messaging service to pull published messages, using code sample from here (https://cloud.google.com/pubsub/docs/quickstart-client-libraries#receive_messages):
SubscriptionName subscriptionName = SubscriptionName.FromProjectSubscription(projectId, subscriptionId);
SubscriberClient subscriber = await SubscriberClient.CreateAsync(subscriptionName);
Task startTask = subscriber.StartAsync((PubsubMessage message, CancellationToken cancel) =>
{
//Do something
return Task.FromResult(SubscriberClient.Reply.Ack);
});
My question is - is it somehow possible to get notification that connection has been broken? Right now, if I disconnect internet, then reconnect again, my app simply stops receiving messages. It would be nice if some kind of exception would occur in such scenario. Any ideas on how to solve this would be highly appreciated.
StartAsync's returned Task will complete when an unrecoverable error occurs (docs). If your subscriber remains disconnected for an extended period of time, I would expect the Task to notify you.
I'm trying to educate myself on the intricacies of reading from a NetworkStream, and understanding the various ways in which problems can occur. I have the following code:
public async Task ReceiveAll()
{
var ns = this.tcp.GetStream();
var readBuffer = new byte[1000];
while (true)
{
int bytesRead;
try
{
bytesRead = await ns.ReadAsync(readBuffer, 0, readBuffer.Length);
if (bytesRead == 0)
{
// Remote disconnection A?
break;
}
}
catch (IOException)
{
// Remote disconnection B?
break;
}
catch (ObjectDisposedException)
{
// Local disconnection?
break;
}
/*Do something with readBuffer */
}
}
I've marked three points in the code where the program says 'something has gone awry, there is no point continuing'.
The 'Local disconnection' isn't exactly something wrong, it will happen when I locally close the socket which is the only way to exit the loop under normal circumstances. I don't think anything else can cause this, so I think I'm safe to just swallow the exception.
The two 'Remote disconnection' points are what I'm not sure about. I know ReadAsync will return 0 if the connection is terminated remotely (A), but the IOException also seems to fire in some circumstances. If my remote client is a C# console, then closing the socket seems to make 'A' happen, and closing the console window seems to be make 'B' happen. I'm not sure I understand what the difference is between these scenarios?
Finally, a bit of a general question, but is there anything glaringly wrong with this bit of code or my above assumptions?
Thanks.
EDIT: In response to my use of ObjectDisposedException to abort out of the loop:
This is what my 'Stop' method looks like (from the same class as above):
public void Stop()
{
this.tcp.Close();
}
This causes the pending 'ReadAsync' to except with ObjectDisposedException. AFAIK there isn't any other way to abort this. Changing this to:
public void Stop()
{
this.tcp.Client.Shutdown(SocketShutdown.Both);
}
Doesn't appear to actually do anything to the pending call, it just continues waiting.
When NetworkStream returns 0, this means that the socket has received a disconnect packet from the remote party. This is how network connections are supposed to end.
The correct way to shut down the connection (especially if you are in a full-duplex conversation) is to call socket.Shutdown(SocketShutdown.Send) and give the remote party some time to close their send channel. This ensures that you receive any pending data instead of slamming the connection shut. ObjectDisposedException should never be part of the normal application flow.
Any exceptions thrown indicate that something went wrong, and I think it's safe to say you can no longer rely on the current connection.
TL;DR
I don't see anything wrong with your code, but (especially in full-duplex communication) I'd shut down the send channel and wait for a 0-byte packet to prevent receiving ObjectDisposedExceptions by default:
use tcp.Shutdown(SocketShutdown.Send) to tell the remote party you want to disconnect
your loop may still receive data that the remote party was sending
your loop will, if everything went right, then receive a 0-byte packet, indicating that the remote party is disconnecting
loop terminates the right way
you may want to decide to dispose the socket after a certain amount of time, if you haven't received the 0-byte packet
I've tried checking the server:port with telnet and I'm getting the expected results. So either writer.Write() or reader.ReadLine() isn't working cause I get nothing from the server.
TcpClient socket = new TcpClient(hostname, port);
if (!socket.Connected) {
Console.WriteLine("Failed to connect!");
return;
}
TextReader reader = new StreamReader(socket.GetStream());
TextWriter writer = new StreamWriter(socket.GetStream());
writer.Write("PING");
writer.Flush();
String line = null;
while ((line = reader.ReadLine()) != null) {
Console.WriteLine(line);
}
Console.WriteLine("done");
EDIT: I might have found the issue. This code was based off examples I found on the web. I tried another irc server: open.ircnet.net:6669 and I got a response:
:openirc.snt.utwente.nl 020 * :Please wait while we process your connection.
It seems as if I probably need to run the reader in a Thread so it can just constantly wait for a response. However it does seem weird that the program got caught on the while loop without ever printing done to the console.
I think you need to provide further details. I'm just going to assume that because you can easily telnet to the server using the same port your problem lies in the evaluation of the Connected property...
if (!socket.Connected) {
Console.WriteLine("Failed to connect!");
return;
}
this is wrong because Microsoft clearly specifies in the documentation that the Connected property is not reliable
Because the Connected property only reflects the state of the connection as of the most recent operation, you should attempt to send or receive a message to determine the current state. After the message send fails, this property no longer returns true. Note that this behavior is by design. You cannot reliably test the state of the connection because, in the time between the test and a send/receive, the connection could have been lost. Your code should assume the socket is connected, and gracefully handle failed transmissions.
That said, you should not use this property to determine the state of the connection. Needless to say that using this property to control the flow of your console app will result in unexpected results.
Suggestion
Remove the evaluation of the Connected property
Wrap your GetStream and Write method calls in a try/catch block to handle network communication errors
reader.ReadLine() will just wait for any data to arrive. If no data arrive, it seems to hang. That's a feature of tcp (I don't like it either). You need to find out how the end of the message is defined and stop based on that end criterion. Be careful, the end of message identifier may be split into two or more lines...
RFC for ping says that the server may not respond to it & such connections has to be closed after a time. Please check the RFC: https://www.rfc-editor.org/rfc/rfc1459#section-4.6.2
So I've been getting this exception for about a week now, and I've finally managed to corner it into a code snippet that can be easily read.
As a background, I am programming an app for Windows RT and I am trying to use basic sockets.
For the sake of testing, I've created a local socket listener to act as a server. Both the server and client need to be able to read/write on the socket.
Neither the client nor the server can (or should) know how much data will come across the wire (if any). This is an absolute requirement. The server should be able to process an arbitrary amount of data on demand.
Here is an example. It is presented as a Unit Test, simply because that is where I consistently encounter the error. Removing any single line from this example causes the error to go away:
[TestMethod]
public async Task TestSomething()
{
// Setup local server
//
StreamSocketListener listener = new StreamSocketListener();
listener.ConnectionReceived += async (sender, args) =>
{
DataReader serverReader = new DataReader(args.Socket.InputStream);
await serverReader.LoadAsync(4096); // <-- Exception on this line
};
await listener.BindServiceNameAsync("10181");
// Setup client
//
using (StreamSocket socket = new StreamSocket())
{
await socket.ConnectAsync(new HostName("localhost"), "10181");
DataReader reader = new DataReader(socket.InputStream);
Task readTask = Listen(reader);
}
}
public async Task Listen(DataReader reader)
{
await reader.LoadAsync(4096);
}
The exception happens on the line where the server calls LoadAsync(...), and the exception is thrown when the unit test quits.
The exception is (seemingly) simple:
An existing connection was forcibly closed by the remote host.
(Exception from HRESULT: 0x80072746)
Any clues would be greatly appreciated.
With the new WinRT socket types, it's easier than ever to program sockets correctly, but make no mistake: they are still complex beasts.
The "forcibly closed" (WSAECONNRESET / 10054) error is when the remote side (in this case, the client) aborts its connection, which it does by disposing its StreamSocket. This is reported as an error but is not uncommon and should be handled gracefully. I.e., if the server has sent all its data and is just waiting to receive more (optional) data, then it should treat WSAECONNRESET as a regular close.
Tip: If you pass Exception.HResult to SocketError.GetStatus, you should see it's SocketErrorStatus.ConnectionResetByPeer. That way you can avoid magic values in your error handling code.
P.S. I have a blog post describing some of the more common socket errors and socket error handling in general.
I'm using Sockets in my Silverlight application to stream data from a server to a client.
However, I'm not quite sure how timeouts are handled in a Silverlight Socket.
In the documentation, I cannot see anything like ReceiveTimeout for Silverlight.
Are user-defined timeouts possible? How can I set them? How can I get notifications when a send / receive operation times out?
Are there default timeouts? How big are they?
If there are no timeouts: what's the easiest method to implement these timeouts manually?
I've checked the Socket class in Reflector and there's not a single relevant setsockopt call that deals with timeouts - except in the Dispose method. Looks like Silverlight simply relies on the default timeout of the WinSock API.
The Socket class also contains a "SetSocketOption" method which is private that you might be able to call via reflection - though it is very likely that you will run into a security exception.
Since I couldn't find any nice solution, I solved the problem manually by creating a System.Threading.Timer with code similar to the following:
System.Threading.Timer t;
bool timeout;
[...]
// Initialization
t = new Timer((s) => {
lock (this) {
timeout = true;
Disconnected();
}
});
[...]
// Before each asynchronous socket operation
t.Change(10000, System.Threading.Timeout.Infinite);
[...]
// In the callback of the asynchronous socket operations
lock (this) {
t.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
if (!timeout) {
// Perform work
}
}
This handles also cases where a timeout occurs which is produced by simple lag, and lets the callback return immediately if the operation took too much time.
I solved this issue for my project sharpLightFtp like:
Created a class which is injected in the UserToken-property of an instance of System.Net.Sockets.SocketAsyncEventArgs and has an System.Threading.AutoResetEvent, which is used to receive a signal after ConnectAsync, ReceiveAsync and SendAsync with a timeout (like here: line 22 for getting a custom enhanced SocketAsyncEventArgs-instance, line 270 for creating and enhancing the SocketEventArgs-instance, line 286 for sending the signal and line 30 for waiting)