Named pipes are failing when clients does nothing but quickly connect-disconnect - c#

I'm building an application that uses Named Pipes for IPC.
When started writing a stress test, I found an issue related to when a client does quickly connect-disconnect.
Server code:
static void ServerThread()
{
var serverPipe = new NamedPipeServerStream("myipc", PipeDirection.InOut, -1, PipeTransmissionMode.Message, PipeOptions.Asynchronous | PipeOptions.WriteThrough);
serverPipe.BeginWaitForConnection(
ar =>
{
var thisPipe = (NamedPipeServerStream)ar.AsyncState;
thisPipe.EndWaitForConnection(ar);
Task.Factory.StartNew(ServerThread);
thisPipe.Dispose();
},
serverPipe);
}
Client does nothing but connect-disconnect as follow:
static void RunClients()
{
for (int i = 0; i < 100; i++)
{
var clientPipe = new NamedPipeClientStream(".", "myipc", PipeDirection.InOut, PipeOptions.Asynchronous | PipeOptions.WriteThrough);
clientPipe.Connect(1000);
clientPipe.Dispose();
}
}
When this runs, one of the clients is failing in Connect() while the server fails in BeginWaitForConnection - saying Pipe is being closed.
If I add at least Thread.Sleep(100) before each client disposes - everything works just fine.
I'm sure what I'm doing is a corner case, but I believe the pipes should be able to handle this in greaceful way.
Any ideas on what could be wrong?
Thanks!

one of the clients is failing in Connect()
Because the server immediately disposes the pipe after connecting.
the server fails in BeginWaitForConnection
Because the client immediately disposes the pipe after connecting.
I believe the pipes should be able to handle this in greaceful way.
It does, it gracefully throws an exception to let your code know that something exceptional happened. You seem to assume it is normal that code closes a pipe without doing anything to let the other end know that the pipe is about to disappear. That is not normal, it is exceptional. So you get an exceptional notification for it.
You catch exceptions with try/catch. There are two things you can do in your catch handler. You can assume that it is okay for code to close a pipe willy-nilly, in which case you do nothing beyond closing your end of the pipe and get out. Or you can assume that something Really Bad happened because the other end of the pipe didn't say goodbye nicely. Which is rather important to distinguish the oh-crap kind of mishaps, like a pipe client or the server crashing. It is up to you to choose your preferred way, but I strongly recommend to not ignore the oh-crap scenarios, it does and will happen. You just created a good simulation of such a mishap.

Related

After using the InternetConnect() API in wininet how can I tell if I'm still connected?

I use the InternetConnect() method from the WinINet APIs. I connect to my FTP server just fine with no issues. After I connect, I wait about 1 min and the server disconnects me because of no activity as expected. I then try to send a file but I'm not connected.
Is there a way to "check" the FTP connection to see if I'm still connected? Or is there some type of way for me to attach an event to tell me when I get disconnected?
I haven't used wininet for FTP, and I use the classes, not the global functions directly. But I suspect that CFtpConnection behaves the same way as CHttpConnection in this respect. Anyway, you might learn something from what I have discovered about the latter.
CHttpConnection seems to be a high and abstract level of connection. When I started out I expected its member functions to throw exceptions once the server closed the underlying socket (for timeout). I now know better or at least believe otherwise. NORMAL closing of the socket does NOT cause exceptions to be thrown at this high level of classy wininet. You might suspect as much from inspecting the wininet error codes: There is no code corresponding to the server having closed the connection.
I experimented with this and found: The server closing the socket (for timeout) is considered normal and does not cause an exception to be thrown. You can go ahead and use CHttpConnection without worrying about this. It will simply reconnect if needed without alerting you. So once you have called GetHttpConnection and got your CHttpConnection object, it will normally last forever!
The exceptions that might be thrown, ERROR_INTERNET_CONNECTION_ABORTED and ERROR_INTERNET_CONNECTION_RESET, are caused by abnormal conditions, f.ex. a proxy server crashing or somebody accidentally pulling the power plug to your modem. The server closing the socket for timeout is considered NORMAL and is transparent to the user of wininet classes.
So the tentative conclusion is that you don't have to worry about the connection being closed by the server. If that happens, CHttpConnection will reconnect backstage and you won't be bothered. You can pretend that the connection always stays open - it seems so to the user of wininet classes.
Consider the following experiment. A connection is opened and then a request is sent once a minute. The function returns once an exception is thrown. But if not, then it loops forever. I tried it on two different web sites: An exception is NEVER thrown! Despite a whole minute of inactivity between requests.
int httpclient::test(string host)
{
int flags = INTERNET_FLAG_RELOAD;
int port = INTERNET_DEFAULT_HTTP_PORT;
CHttpConnection *connection = session.GetHttpConnection(host.cstring(),flags,port);
int secs = 0;
while (true)
{
CHttpFile *fil;
try
{
fil = connection->OpenRequest(CHttpConnection::HTTP_VERB_HEAD, "index.htm",
0,1,0, "HTTP/1.1", flags);
}
catch (CInternetException *exc)
{
connection->Close();
int feil = exc->m_dwError;
exc->Delete();
return -feil;
}
fil->AddRequestHeaders("Connection: Keep-Alive");
try
{
fil->SendRequest();
}
catch (CInternetException *exc)
{
connection->Close();
int feil = exc->m_dwError;
exc->Delete();
return feil;
}
fil->Close();
Sleep(60 * 1000);
secs += 60;
printf("%u seconds passed\n", secs);
}
return 0;
}
Take all this with a grain of salt. wininet is poorly documented and all I know is what experiments have taught me.

NetworkStream exceptions and return codes

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

Is it good practice to put try-catch in a loop until all statements in the try block is executed without any exceptions?

I was trying to develop a multicast receiver program and socket initialization was done as shown below:
public void initializeThread()
{
statuscheckthread = new Thread(SetSocketOptions);
statuscheckthread.IsBackground = true;
}
private void Form1_Load(object sender, EventArgs e)
{
rxsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
iep = new IPEndPoint(IPAddress.Any, 9191);
rxsock.Bind(iep);
ep = (EndPoint)iep;
initializeThread();
statuscheckthread.Start();
}
public void SetSocketOptions()
{
initializeThread(); //re-initializes thread thus making it not alive
while (true)
{
if (NetworkInterface.GetIsNetworkAvailable())
{
bool sockOptnSet = false;
while (!sockOptnSet)
{
try
{
rxsock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("224.50.50.50")));
rxsock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 64);
sockOptnSet = true;
}
catch
{
//Catch exception here
}
}
}
break; // Break out from loop once socket options are set
}
}
When my PC is not connected to a network, SetSocketOption method was throwing exception and even after network is connected,
I was unable to receive data because socket options are not set.
To avoid this I used a thread which runs in the background checking
for network availability and once network is available, it sets the socket options.
It works properly in some PC's but in some others, NetworkInterface.GetIsNetworkAvailable()
returned true before network got connected
(while network was being identified) .
So, to make sure Socket options are set, I used a bool variable sockOptnSet
which is set as
true if all the statements in the try block is executed as shown inside the method public void SetSocketOptions()
This program works fine in all PC's I tried, but I am doubtful about how much I can rely on this to work.
My questions are:
1) Is this good practice?
2) If not, what are the possible errors or problems it may cause? And how can I implement it in a better way?
Is this a good practice?
No, not a good practice. The vast majority of exceptions, including your first one, fall in the category of vexing exceptions. Software is supposed to work, worked well when you tested it, but doesn't on the user's machine. Something went wrong but you do not know what and there isn't anything meaningful that you can do about it. Trying to keep your program going is not useful, it cannot do the job it is supposed to do. In your case, there's no hope that the socket is ever going to receive data when there is no network. And, as you found out, trying to work around the problem just begets more problems. That's normal.
If this is bad practice, how can I implement it in a better way?
You need help from a human. The user is going to have to setup the machine to provide a working network connection. This requires a user interface, you must have a way to tell a human what he needs to do to solve your problem. You can make that as intricate or as simple as you desire. Just an error message, a verbatim copy of the Exception.Message can be enough. Writing an event handler for the AppDomain.CurrentDomain.UnhandledException event is a very good (and required) strategy. Microsoft spent an enormous amount of effort to make exception messages as clear and helpful as possible, even localizing them for you in the user's native language, you want to take advantage of that. Even if the exception message is mystifying, a quick Google query on the message text returns hundreds of hits. With this event handler in place, you don't have to do anything special. Your program automatically terminates and your user knows what to do about it.
You can certainly make it more intricate, you discovered that SetSocketOption() is liable to fail right after the network becomes available but works when you wait long enough. So this is actually an error condition that you can work around, just by waiting long enough. Whether you should write the code to handle this is something that you have to decide for yourself. It is something you write when you have enough experience with the way your program behaves, you never write it up front. Usually as a result from feedback from the users of your program.
Some good advice in the comments, lets' expand on it.
Firstly, I would put all this socket code in to its' own class, outside of the form. This makes it its' own entity and semantically easier to understand. This class could have a property Initialised, which is initially set to false. The first thing you do in your form is call an Initialise method on this class which attempts to set socket options and catches the relevant exceptions if the network is not available. If it is available, we set our Initialised property to true.
If not available, we set a single timeout (see System.Threading.Timer) that calls this same function (potentially with a retry count) after 'x' seconds. Once again we'll find ourselves back in this Initialise function, perhaps with a retry count mentioned at the beginning. Once again, if it is available, we're good - if not, set the timer again. Eventually, after 'x' retries if we're not initialised we can throw an exception or set some other failure property to indicate that we can't proceed.
Your Form class can periodically check (or hook in to an event) to determine whether the socket is now ready for communication. In case of failure you can gracefully quit out, or because our class is nice and abstracted, attempt to start the whole process again.

C# Java Named pipe stability

I am having stability issues using a named pipe for communication between a C# and Java app.
Here is the code that sets up the named pipe in C# and reads lines of XML strings.
try
{
NamedPipeServerStream inStream = new NamedPipeServerStream(inName, PipeDirection.In);
inStream.WaitForConnection();
reader = new StreamReader(inStream);
while (!Stopped && !reader.EndOfStream)
{
string xml = reader.ReadLine();
processXml(xml);
}
}
catch (Exception e)
{
log.Error("Error in receiver", e);
}
finally
{
log.Info("Receiver ended");
}
And here is the connection and write code in Java
public void connect() throws TransportUnavailableException
{
try
{
File inPipe = new File(inName);
os = new FileOutputStream(inPipe);
// Uses JAXB for XML serialization
marshaller = context.createMarshaller();
}
catch (FileNotFoundException e)
{
throw new TransportUnavailableException("Named pipe not found: " + inName);
}
}
public void send(Message message)
{
marshaller.marshal(message, os);
os.write('\n');
os.flush();
}
Everything works fine normally. But many users are reporting crashes. I don't see any exceptions in logs that suggest a reason for the pipe dying. I just see that the receiving thread in C# ends (i.e. 'Receiver ended' in the logs) and after this I get an IO exception on the next attempted send from Java with a message 'The handle is invalid'. This seems to happen randomly, but usually within the 1st minute or 2 after the connection was established. The pipe ending message also happens when the application is not doing anything, it could have been minutes since the last user operation. Then it could be a few more minutes before the next write is attempted from Java.
All reasons for my app to bring down the pipe on purpose (e.g. a crash elsewhere in system) are logged and I never see that as a reason for the pipe ended, I just get the message that the reader has given up reading.
Could there be any external reason for the pipe being killed, anti-virus, firewall etc?
I noticed I didn't use a RandomAccessFile from Java like most examples seem to use. Could this be a reason?
Any help/suggestion appreciated
Thanks!
Your server side code only processes one connection, then it exits when it reads to EOS. You need to create the named pipe, loop accepting connections, and spin up a new thread to handle each connection. You also need to close each connection when you're finished with it.
However I would use TCP rather than named pipes for this, for several reasons.

C#: Asynchronous NamedPipeServerStream understanding

I was trying to find any good and clear example of asynchronous NamedPipeServerStream and couldn't find any suitable for me.
I want to have NamedPipe Server which is asynchronously accept messages from clients. The client is simple and it's fine for me. But I can't find examples of server, or can't understand how it works.
Now as I understand I need to create NamedPipeServerStream object. Let's do this:
namedPipeServerStream = new NamedPipeServerStream(PIPENAME, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, BUFFERSIZE, BUFFERSIZE);
Seems to work. But I don't know, do I have to use PipeSecurity or PipeAccessRule at all? Do I? My server will work as a windows service in a local system.
What next? I'm thinking I need to use BeginWaitForConnection for async connections. Let's see:
namedPipeServerStream.BeginWaitForConnection(WaitForConnectionAsyncCallback, <some strange thing>);
Question 1: What is this "some strange thing"? How to use it?
Question 2: Should I do
while(true)
{
namedPipeServerStream.BeginWaitForConnection(WaitForConnectionAsyncCallback, <some strange thing>);
}
To make my server always wait for connections? Or I need to do it somehow else?
And then... Let's take a look into WaitForConnectionAsyncCallback function:
private void WaitForConnectionAsyncCallback(IAsyncResult result)
{
Console.WriteLine("Client connected.");
byte[] buff = new byte[BUFFERSIZE];
namedPipeServerStream.Read(buff, 0, namedPipeServerStream.InBufferSize);
string recStr = General.Iso88591Encoding.GetString(buff, 0, namedPipeServerStream.InBufferSize);
Console.WriteLine(" " + recStr);
namedPipeServerStream.EndWaitForConnection(result);
}
..This doesn't work of course. Because I don't know how exactly to receive string from stream. How? Now it raises an InvalidOperationException:
Pipe hasn't been connected yet.
So how to organize asynchronous work with NamedPipeServerStream?
You tinker with the PipeSecurity to restrict access to the pipe, allowing only blessed programs to connect to your service. Put that on the back-burner until you've got this working and have performed a security analysis that shows that this kind of restriction is warranted.
The "some strange thing" is simply an arbitrary object that you can pass to the callback method. You don't often need it but it can be helpful if you write your callback so it serves multiple connections. In which case you need to know more about the specific pipe that got connected, the state argument allows you to pass that info. In your callback method, the result.AsyncState property gives you the reference back to that object. Only worry about that later, you'll find a use for it when you need it. Just pass null until then.
That's a bug. You must call EndWaitForConnection() first, before doing anything else with the pipe. Simply move it to the top of the method. You typically want to write it inside a try/catch so you can catch ObjectDisposedException, the exception that will be raised when you close the pipe before exiting your program.

Categories

Resources