Check if NamedPipeClientStream write is successful - c#

Basically the title... I'd like to have same feedback on weather NamedPipeServerStream object successfully received a value. This is the starting code:
static void Main(string[] args){
Console.WriteLine("Client running!");
NamedPipeClientStream npc = new NamedPipeClientStream("somename");
npc.Connect();
// npc.WriteTimeout = 1000; does not work, says it is not supported for this stream
byte[] message = Encoding.UTF8.GetBytes("Message");
npc.Write(message);
int response = npc.ReadByte();
Console.WriteLine("response; "+response);
}
I've implemented a small echo message from the NamedPipeServerStream on every read. I imagine I could add some async timeout to check if npc.ReadByte(); did return a value in lets say 200ms. Similar to how TCP packets are ACKed.
Is there a better way of inspecting if namedPipeClientStream.Write() was successful?

I'd like to have same feedback on weather NamedPipeServerStream object successfully received a value
The only way to know for sure that the data you sent was received and successfully processed by the client at the remote endpoint, is for your own application protocol to include such acknowledgements.
As a general rule, you can assume that if your send operations are completing successfully, the connection remains viable and the remote endpoint is getting the data. If something happens to the connection, you'll eventually get an error while sending data.
However, this assumption only goes so far. Network I/O is buffered, usually at several levels. Any of your send operations almost certainly involve doing nothing more than placing the data in a local buffer for the network layer. The method call for the operation will return as soon as the data has been buffered, without regard for whether the remote endpoint has received it (and in fact, almost never will have by the time your call returns).
So if and when such a call throws an exception or otherwise reports an error, it's entirely possible that some of the previously sent data has also been lost in transit.
How best to address this possibility depends on what you're trying to do. But in general, you should not worry about it at all. It will typically not matter if a specific transmission has been received. As long as you can continue transmitting without error, the connection is fine, and asking for acknowledgement is just unnecessary overhead.
If you want to handle the case where an error occurs, invalidating the connection, forcing you to retry, and you want to make the broader operation resumable (e.g. you're streaming some data to the remote endpoint and want to ensure all of the data has been received, without having to resend data that has already been received), then you should build into your application protocol the ability to resume, where on reconnecting the remote endpoint reports the number of bytes it's received so far, or the most recent message ID, or whatever it is your application protocol would need to understand where it needs to start sending again.
See also this very closely-related question (arguably maybe even an actual duplicate…though it doesn't mention named pipes specifically, pretty much all network I/O will involve similar issues):
Does TcpClient write method guarantees the data are delivered to server?
There's a good answer there, as well as links to even more useful Q&A in that answer.

Related

Multiple client with async TCP listener in C#

I have a problem with async TCP listener in C#. The main problem is I want to create async TCP listener in order to handle multiple connections. I have tons of requests from devices and webpages. Also I have to use database to write specific information from these connections (read/write to/from SQL Server).
The scenario of our task is this: One REST request will post from a webpage with a unique identifier to our Web API. Then our Web API makes a TCP connection to our listener, so we must halt this connection until we get another connection from a device with that unique identifier. Then we send data which we got it before (webpage connection) to this connected device and again we must halt this connection too. After processing this data in the device it will send us some other data again, and we must send this data to webpage which we halted it before.
How can I find halted connection in our listener?
Is there a better solution for us? (except using async TCP listener)
Because of some customer reasons we are unable to use signalR or self-hosted Web API in C#.
Regards,
Sara
'Halt' isn't the best word to describe what you need. If you need two-way communication with a web page over a REST request, you simply need to keep that request pending until the response is ready (not recommended, it could take really long and the connection could be dropped due to network conditions). Do reconsider your choice of avoiding SignalR. However, if need be, you can keep the request thread waiting. To do that, you'd need either a TaskCompletionSource (if you're processing the request within a Task) or a synchronization primitive such as a ManualResetEvent. I can't really give you more details without knowing the conditions your code will run under.
On the device side of things, again you need two way communication. You could implement this in one of two ways:
The device opens a TCP connection and keeps it open. The server receives the ID, and then sends the data back over the connection. The device then processes this data in some way and sends its response back to the server over the same connection and terminates the connection.
The device makes the equivalent of a REST GET request to the server to grab the data from the web page. It then processes the data and makes the equivalent of a POST request to send its own data back to the server.
After this is done, you still have the connection from the web page waiting for a response. Simply let it know the transaction has completed, using TaskCompletionSource.SetResult or ManualResetEvent.Signal. The server can then write whatever data it needs in the response to the web page's request and close that connection too.
Also note that there is no such thing as a halted connection. You just intentionally delay writing a response.
EDIT: You can't really hold the connection (not with the normal execution flow of most web servers at least), but you can stop the thread processing that connection. This is a heavily simplified (and completely inappropriate for any real system) example:
// ConnectionManager.cs
public static Dictionary<Guid, TaskCompletionSource<DataToSendToWebPage>> connectionTCSs;
// WebPageRequestHandler.cs
async Task HandleClientRequest() {
// do some stuff
var tcs = new TaskCompletionSource<DataToSendToWebPage>();
ConnectionManager.connectionTCSs[deviceID] = tcs;
var result = await tcs.Task; // This is where you wait for the other flow to complete
// Write response to connection
}
// DeviceRequestHandler.cs
void HandleRequest() {
// do stuff
ConnectionManager.connectionTCSs[clientID].SetResult(result);
}
The general idea is that you keep the thread (or task) processing the web page request waiting, and then signal it to continue from the other thread when the device's connection is handled and data is received.

Self-healing SslStream

I'm writing a service that needs to maintain a long running SSL connection to a remote server. I need this server to be self-healing, that is if it's disconnected for any reason then the next time it's written to it will reconnect. I've tried this:
bool isConnected = client.Connected && client.Client.Poll(0, SelectMode.SelectWrite) && stream.CanWrite;
if (!isConnected )
{
this.connected = false;
GetConnection();
}
stream.Write(bytes, 0, bytes.Length);
stream.Flush();
But I find it doesn't act as I would expect it. If I simulate a network outage by disabling my wifi, I'm still able to write to the stream with stream.Write() for approximately 20 seconds. Then next time I try to write to it, none of client.Connected, client.Client.Poll(), or stream.CanWrite() return false, but when I go to write to the stream I get a socket exception. Finally, if I try to recreate the connection, I get this exception: An existing connection was forcibly closed by the remote host.
I would appreciate any help create a long running SslStream that can withstand network failure. Thanks!
From a 10.000 feet point of view:
The reason you can still write to the stream after shutting down your wifi is because there is a network buffer that is holding the data for transmission, stream.Write/stream.Flush success means the network interface (TCP/IP stack) has accepted the data and has been buffered for transmission, not that the data has reach its target.
It takes time to the TCP/IP Stack to notice a full media disconnection, (connection lost/reset) because even if there is no physical link TCP/IP will see this as a temporary issue in the network and will keep retrying for a while (the network could be dropping packets at some point and the stack will keep retrying)
If you think about this in the reverse way, you won't like all your programs to fail if there is a network hiccup (this happen too often on internet), so TCP/IP takes its time to notify to the app layer that the connection has become invalid (after retry several times and wait a reasonable amount of time)
You can always reconnect to the server when the SslStream fails and continue sending data, although you will find is not as easy as this because there are several scenarios where you send and data is not received by server and others where server receive the data and you do not receive any ACK from server at all... So depending on your needs, self-healing alone could be not enough.
Self-Healing is simple to implement, data consistency and reliability is harder and usually requires the server to be ready to support some kind of reliable messaging mechanism to ensure all data has been sent and received.
The underlying protocol for SSL is TCP. TCP will usually only send data if the application wants it to deliver data, or if it needs to reply to data received from the other side by sending an ACK. This means, that a broken connection like a lost link will not be noticed until you are trying to send any data. But you will not notice immediatly, because:
A write to the socket will only deliver the data to the OS kernel and return success if this delivery was successful.
The kernel will then try to deliver the data to the peer and will wait for the ACK from the client.
If it does not get any ACK it will retry again to deliver the data and only after some unsuccessful retries the kernel will declare the connection broken.
Only after the connection is marked broken by the kernel the next write or read will return the error from kernel to user space, like with returning EPIPE when doing a write.
This means, if you want to know up-front if the connection is still alive you have to make sure that you get a regular data exchange on the connection. At the TCP level you might set TCP_KEEPALIVE, but this might use an interval of some hours between exchanges packets. At the SSL layer you might try to use the infamous heartbeat extension, but most peers will not understand it. The last choice is to implement some kind of heartbeat in your own application.
As for the self healing: When reconnecting you get a new TCP connection and you also need to do a full SSL handshake, because the last SSL connection was not cleanly closed and thus cannot be resumed. The server has no idea that this new connection is just a continuation of the old one so you have to implement some kind of meta-connection spanning multiple TCP connections inside your application layer on both client and server. Inside this meta-connection you need to have your own data tracking to detect, which data are really accepted from the peer and which were only send but never explicitly accepted because the connection broke. Sound like a kind of TCP on top of TCP.

How do I reply asynchronously to a client using sockets in C#?

I have basically implemented this asynchronous server socket example (and the corresponding client). Using it, I can respond to the client if I follow the example exactly, i.e., if the call to Send() the response is in the ReadCallback() method.
If, however, I try and send a response outside of here, i.e., in a callback that I've attached to my message processing routine (running in a different thread), I get this error, saying the Socket is not connected. If I try and send a response somewhere else in the Server code, say in the while(true) loop that's listening to incoming connections, I get the same error.
Am I missing something fundamental here?
Edit:
Ok, so I read Two-way communication in socket programming using C, and I now think, according to that answer, that I have to modify the example I linked to so that I reply to the server on the socket returned by the accept process. My goal is to be able to call Send() outside of the receive callback, say from Main(), after the client and server are connected.
Please can someone suggest how I modify the example to achieve what I want? I'm getting thoroughly confused about this, and don't want to create a separate stream if I don't need to (which according to the question I posted, I don't need to...).
If you want to keep the connection open then would need to persist the handler variable as that is the open socket connection. Then whenever you want to send that connection a message you retrieve its socket and send.
Also, you obviously wouldn't call Shutdown() and Close() on the handler variable.

How do you know if a Socket.Send() has worked?

Quite a simple question - I've been having some TCP packets go missing (they aren't received by the remote socket), so I'm considering resending any packets that don't get received.
However I need to know when send doesn't work in order to do this! I know Send() returns an integer containing the 'The number of bytes sent to the Socket', but even when the other computer receives nothing, this is always the length of the entire buffer, indicating that everything was (theoretically) sent. I also know there's a Socket.Connected property, but that is false even when that data is received, and sometimes true even when it isn't, so that doesn't help either.
So how do I know if Send() has worked?
Send() simply places the data in a buffer for the network adapter to process. When Send() returns, you have no guarantee that a single byte has "left" your computer, even when the socket is in blocking mode.
TCP ensures though that within a connection all data is received in the order it was sent. It never "forgets" a packet in the middle of a conversation, and automatically retransmits data when needed.
To determine whether retransmission is required, the protocol sends acknowledgement messages, but:
you can't access them from the Socket class
hosts may postpone sending this ACK message
The easiest way to ensure your message has arrived is to let the other party respond to them yourself. If you don't receive a response within a reasonable amount of time, you could treat that connection as broken.
About the whole discussion between Sriram Sakthivel and "the others" - I've had similar problems of receiving duplicate messages and missing others, but in my personal case this was caused by:
using BeginReceive() (the async receive method),
reusing the same buffer on each BeginReceive() call, and
calling BeginReceive() before processing that buffer, causing the buffer to be filled with new data before having read the old message.
The ideal way of doing this is to check if the bufferedAmount is zero after you've sent a message. The trick is, you'll have to let your application know you are in fact sending a message.

TcpClient.BeginRead/TcpClient.EndRead doesn't throw exception when internet disconnected

I'm using TcpListener to accept & read from TcpClient.
The problem is that when reading from a TcpClient, TcpClient.BeginRead / TcpClient.EndRead doesn't throw exception when the internet is disconnected. It throws exception only if client's process is ended or connection is closed by server or client.
The system generally has no chance to know that connection is broken. The only reliable way to know this is to attempt to send something. When you do this, the packet is sent, then lost or bounced and your system knows that connection is no longer available, and reports the problem back to you by error code or exception (depending on environment). Reading is usually not enough cause reading only checks the state of input buffer, and doesn't send the packet to the remote side.
As far as I know, low level sockets doesn't notify you in such cases. You should provide your own time out implementation or ping the server periodically.
If you want to know about when the network status changes you can subscribe to the System.Net.NetworkInformation.NetworkChange.NetworkAvailabilityChanged event. This is not specific to the internet, just the local network.
EDIT
Sorry, I misunderstood. The concept of "connected" really doesn't exist the more you think about it. This post does a great job of going into more details about that. There is a Connected property on the TcpClient but MSDN says (emphasis mine):
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.
Basically the only way to check for a client connection it to try to send data. If it goes through, you're connected. If it fails, you're not.
I don't think you'd want BeginRead and EndRead throwing exceptions as these should be use in multi threaded scenarios.
You probably need to implement some other mechanism to respond to the dropping of a connection.

Categories