I have a C++ and C# applications where I send command to each one other by using named pipes. It was working well until I noticied I couldn't cancel the Read() call, I was using a stop variable but didn't notice this wasn't all I need because it couldn't read the stop variable state until get off the Read() call. I found I would use PIPE_NOWAIT attribute in the CreateNamedPipe() call. When I added it the C# throw an System.NullReferenceException because the FileStream was null, it's created from new FileStream(clientHandle, FileAccess.ReadWrite, BUFFER_SIZE, true); where clientHandle is created as following:
private void Listen()
{
while (!exitLoop)
{
clientHandle = CreateNamedPipe(this.pipeName,
DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_NOWAIT,
255,
BUFFER_SIZE,
BUFFER_SIZE,
0,
IntPtr.Zero);
if (clientHandle.IsInvalid)
{
return;
}
int ok = ConnectNamedPipe(clientHandle, IntPtr.Zero);
//could not connect client
if (ok == 0) // here's the error, getLastError() = ERROR_PIPE_LISTENING
{
return;
}
stream = new FileStream(clientHandle, FileAccess.ReadWrite, BUFFER_SIZE, true);
// ....
}
If matter, in C++ the pipe is created like this:
hPipe1 = CreateFile(lpszPipename1,
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (!IsValidPipe(hPipe1))
{
openError();
return;
}
hPipe2 = CreateFile(lpszPipename2,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
So my question is: the error is ERROR_PIPE_LISTENING after ConnectNamedPipe() call, happend after I did add PIPE_NOWAIT. Why is that error? how do I fix this? and this the right way to add support to cancel a named-pipe operation? I would kill the theread where Listen() is running in but I read it isn't a good practive (it doesn't even work either).
NOTE: I'm working on existing code base and I would like to avoid rewrite everything using NamedPipeClientStream for time reasons.
In C++ you need to create the file with overlapped io, then WaitForMultipleObjects(..., INFINITE); for a stop event and the IO.
If you get the stop event, then you CancelIO();.
For C# msdn : Overlapped allows you to create an overlapped object (necessary for the read).
stackoverflow : pinvoke ReadFile. This shows how to natively call ReadFile with the overlapped option.
stackoverflow : waitformultipleobjects functionality Explains how to call WaitForMultipleObjects.
When solving this sort of problem I created a stand-alone function
ReadFileWithEvent( HANDLE file, VOID * pData, size_t data, HANDLE exitEvent, BOOL & signalled );
which packaged creating an overlapped object, waiting and explaining to the caller that the stop had occurred, and the Read had not completed. This simplified the code I needed.
I solved this with PeekNamedPipe(), I get the number total of bytes available and call ReadFile() only if it's > 0. This is a simple approach to emulate nonblocking mode and I can exit the loop running inside a thread just setting done to true.
Something like this:
while(!done) {
DWORD total_available_bytes = 0;
if(!PeekNamedPipe(hPipe2, NULL, 0, NULL, &total_available_bytes, NULL)) {
/* error handling goes here */
break;
}
// for avoid overuse of the CPU, sleep for a while until next check.
if(total_available_bytes == 0) {
Sleep(500);
continue;
}
if(ReadFile(hPipe2, ...)) {
// ...
}
}
Related
I'm using the asynchronous methos BeginSend and I need some sort of a timeout mechanism. What I've implemented works fine for connect and receive timeouts but I have a problem with the BeginSend callback. Even a timeout of 25 seconds is often not enough and gets exceeded. This seems very strange to me and points towards a different cause.
public void Send(String data)
{
if (client.Connected)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
client.NoDelay = true;
// Begin sending the data to the remote device.
IAsyncResult res = client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), client);
if (!res.IsCompleted)
{
sendTimer = new System.Threading.Timer(SendTimeoutCallback, null, 10000, Timeout.Infinite);
}
}
else MessageBox.Show("No connection to target! Send");
}
private void SendCallback(IAsyncResult ar)
{
if (Interlocked.CompareExchange(ref sendTimeoutflag, 1, 0) != 0)
{
// the flag was set elsewhere, so return immediately.
return;
}
sendTimeoutflag = 0; //needs to be reset back to 0 for next reception
// we set the flag to 1, indicating it was completed.
if (sendTimer != null)
{
// stop the timer from firing.
sendTimer.Dispose();
}
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
ef.updateUI("Sent " + bytesSent.ToString() + " bytes to server." + "\n");
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
private void SendTimeoutCallback(object obj)
{
if (Interlocked.CompareExchange(ref sendTimeoutflag, 2, 0) != 0)
{
// the flag was set elsewhere, so return immediately.
return;
}
// we set the flag to 2, indicating a timeout was hit.
sendTimer.Dispose();
client.Close(); // closing the Socket cancels the async operation.
MessageBox.Show("Connection to the target has been lost! SendTimeoutCallback");
}
I've tested timeout values up to 30 seconds. The value of 30 seconds has proved to be the only one never to time out. But that just seems like an overkill and I believe there's a different underlying cause.Any ideas as to why this could be happening?
Unfortunately, there's not enough code to completely diagnose this. You don't even show the declaration of sendTimeoutflag. The example isn't self-contained, so there's no way to test it. And you're not clear about exactly what happens (e.g. do you just get the timeout, do you complete a send and still get a timeout, does something else happen?).
That said, I see at least one serious bug in the code, which is your use of the sendTimeoutflag. The SendCallback() method sets this flag to 1, but it immediately sets it back to 0 again (this time without the protection of Interlocked.CompareExchange()). Only after it's set the value to 0 does it dispose the timer.
This means that even when you successfully complete the callback, the timeout timer is nearly guaranteed to have no idea and to close the client object anyway.
You can fix this specific issue by moving the assignment sendTimeoutflag = 0; to a point after you've actually completed the send operation, e.g. at the end of the callback method. And even then only if you take steps to ensure that the timer callback cannot execute past that point (e.g. wait for the timer's dispose to complete).
Note that even having fixed that specific issue, you may still have other bugs. Frankly, it's not clear why you want a timeout in the first place. Nor is it clear why you want to use lock-free code to implement your timeout logic. More conventional locking (i.e. Monitor-based with the lock statement) would be easier to implement correctly and would likely not impose a noticeable performance penalty.
And I agree with the suggestion that you would be better-served by using the async/await pattern instead of explicitly dealing with callback methods (but of course that would mean using a higher-level I/O object, since Socket doesn't suppose async/await).
I'm writing a C# application (limited to .NET framework 4.0 or lower (i.e. no Read/WriteAsync)) that is responsible for reading / writing files between a Windows (7 or later) machine and a NFS-mounted Unix-based server.
The client machines are mobile and are expected to be disconnected from the network periodically. Because of this, I wish to harden my application to gracefully handle disconnects in the middle of a read or write operation (hopefully by accident).
To keep track of whether a timeout has occurred, I asynchronously read (or write) and use the AsyncWaitHandle of the IAsyncResult returned by FileStream.BeginRead:
private int PerformRead (FileStream readStream,
byte [] buffer,
int nBytes)
{
IAsyncResult readResult = null;
try
{
readResult = readStream.BeginRead
(buffer, 0, nBytes, null, null);
// If the read was completed, return # of bytes read.
if (readResult.AsyncWaitHandle.WaitOne (1000))
{
return readStream.EndRead (readResult);
}
// Otherwise, the timeout has elapsed.
else
{
throw new TimeoutException ();
}
}
finally
{
if (null != readResult)
{
readResult.AsyncWaitHandle.Close ();
}
}
}
My issue arises with cleaning up my streams in the case of a time out. It appears that calling Dispose() or Close() on the stream hangs indefinitely while the connection is severed. To attempt to remedy this, I explicitly call Win32's CloseHandle() on the file handle on a timeout. This function appears to also block while the connection is severed. The following represents my treatment of the read stream.
private void ReadNewFile (string path,
byte [] buffer)
{
IntPtr readHandle = IntPtr.Zero;
FileStream readStream = null;
try
{
readHandle = CreateFile (path
0xc0000000,
0,
IntPtr.Zero,
3,
0x40000000,
IntPtr.Zero);
SafeFileHandle safeReadHandle = new SafeFileHandle (readHandle, true);
if (safeReadHandle.IsInvalid)
{
throw new Exception ();
}
readStream = new FileStream (safeReadHandle,
FileAccess.Read,
4092,
true);
while (true)
{
// Read part of the file into the buffer.
int bytesRead = PerformRead (readStream, buffer, buffer.Length);
// If EOF reached, break.
if (bytesRead == 0)
{
break;
}
}
}
catch (TimeoutException)
{
// NOTE: Hangs indefinitely if the network cable is unplugged.
CloseHandle (readHandle);
}
finally
{
if (null != readStream)
{
// NOTE: Hangs indefinitely if both of the following are true:
// - Network cable is unplugged (resulting in TimeoutException)
// - The body of the caught TimeoutException is commented out.
readStream.Close ();
}
}
}
Is there a recommended method of properly disposing of a FileStream for a file that is no longer available? Note that any call to BeginRead will also hang indefinitely if the connection has severed.
I'm working on a client/server relationship that is meant to push data back and forth for an indeterminate amount of time.
The problem I'm attempting to overcome is on the client side, being that I cannot manage to find a way to detect a disconnect.
I've taken a couple of passes at other peoples solutions, ranging from just catching IO Exceptions, to polling the socket on all three SelectModes. I've also tried using a combination of a poll, with a check on the 'Available' field of the socket.
// Something like this
Boolean IsConnected()
{
try
{
bool part1 = this.Connection.Client.Poll(1000, SelectMode.SelectRead);
bool part2 = (this.Connection.Client.Available == 0);
if (part1 & part2)
{
// Never Occurs
//connection is closed
return false;
}
return true;
}
catch( IOException e )
{
// Never Occurs Either
}
}
On the server side, an attempt to write an 'empty' character ( \0 ) to the client forces an IO Exception and the server can detect that the client has disconnected ( pretty easy gig ).
On the client side, the same operation yields no exception.
// Something like this
Boolean IsConnected( )
{
try
{
this.WriteHandle.WriteLine("\0");
this.WriteHandle.Flush();
return true;
}
catch( IOException e )
{
// Never occurs
this.OnClosed("Yo socket sux");
return false;
}
}
A problem that I believe I am having in detecting a disconnect via a poll, is that I can fairly easily encounter a false on a SelectRead, if my server hasn't yet written anything back to the client since the last check... Not sure what to do here, I've chased down every option to make this detection that I can find and nothing has been 100% for me, and ultimately my goal here is to detect a server (or connection) failure, inform the client, wait to reconnect, etc. So I am sure you can imagine that this is an integral piece.
Appreciate anyone's suggestions.
Thanks ahead of time.
EDIT: Anyone viewing this question should note the answer below, and my FINAL Comments on it. I've elaborated on how I overcame this problem, but have yet to make a 'Q&A' style post.
One option is to use TCP keep alive packets. You turn them on with a call to Socket.IOControl(). Only annoying bit is that it takes a byte array as input, so you have to convert your data to an array of bytes to pass in. Here's an example using a 10000ms keep alive with a 1000ms retry:
Socket socket; //Make a good socket before calling the rest of the code.
int size = sizeof(UInt32);
UInt32 on = 1;
UInt32 keepAliveInterval = 10000; //Send a packet once every 10 seconds.
UInt32 retryInterval = 1000; //If no response, resend every second.
byte[] inArray = new byte[size * 3];
Array.Copy(BitConverter.GetBytes(on), 0, inArray, 0, size);
Array.Copy(BitConverter.GetBytes(keepAliveInterval), 0, inArray, size, size);
Array.Copy(BitConverter.GetBytes(retryInterval), 0, inArray, size * 2, size);
socket.IOControl(IOControlCode.KeepAliveValues, inArray, null);
Keep alive packets are sent only when you aren't sending other data, so every time you send data, the 10000ms timer is reset.
I've written the following function to implement a timeout feature using NetworkStream's asynchronous read functions (BeginRead and EndRead). It works fine until I comment out the line Trace.WriteLine("bytesRead: " + bytesRead);. Why?
private int SynchronousRead(byte[] buffer, int count)
{
int bytesRead = 0;
bool success = false;
IAsyncResult result = null;
result = _stream.BeginRead(
buffer, 0, count,
delegate(IAsyncResult r)
{
bytesRead = _stream.EndRead(r);
},
null);
success = result.AsyncWaitHandle.WaitOne(_ioTmeoutInMilliseconds, false);
if (!success)
{
throw new TimeoutException("Could not read in the specfied timeout.");
}
//If I remove this line, bytesRead is always 0
Trace.WriteLine("bytesRead: " + bytesRead);
return bytesRead;
}
Just in case you're wondering, I have to do this because I will eventually need to target the .Net Compact Framework 3.5 and it doesn't support the NetworkStream.ReadTimeout and NetworkStream.WriteTimeout properties.
An interesting threading bug. The bytesRead variable is assigned after the wait handle is signaled. Two things can go wrong: the method returns before the assignment is made. Or the thread reads a stale value since their is no memory barrier past the WaitOne() call. The Trace statement fixes the problem because it delays the main thread long enough to allow the variable to be written. And it has an internal lock that ensures the cache is coherent.
You'll need an additional AutoResetEvent that signals that bytesRead variable was written.
Besides the memory barrier problem in you code (As Hans also pointed), If i were you i'd use Reactive Extension instead that would make this code segment in just three lines of code. If you have time, I'd strongly suggest you to use Rx instead.
Cheers
I am a beginner in C# and I want to do the following:
Thread t = new Thread(new ThreadStart(this.play));
t.Start();
This is the method play:
private void play()
{
playSong("path\\to\\song.mp3");
}
private static void playSong(String path)
{
mciSendString("open \"" + path + "\" type mpegvideo alias MediaFile", null, 0, IntPtr.Zero);
mciSendString("play MediaFile", null, 0, IntPtr.Zero);
}
[DllImport("winmm.dll")]
private static extern long mciSendString(string strCommand, StringBuilder strReturn, int iReturnLength, IntPtr hwndCallback);
When I execute the method just like this: play();, without using threading, the song plays perfectly, but it doesn't play if I do like in the first code excerpt.
I suspect that it happens because I need to call the mciSendString method in the main thread. If so, will someone tell me how can I do that? Or tell me how can I get it working using a thread?
I appreciate your help.
-- Edited from here --
I don't know if I should post the code, cause it is kind of large, but I will reduce it, to show what I want to do:
I have a windows forms application that starts a socket listening on a port when it begins, which works as a server. This server receives as requests paths to songs that it'll play. If I use the play method as shown below, the form crashes, but the application still listens to my requests. I understand that I have to do it in the background, so that the form controls won't crash, I just don't know the better way to do it.
//Constructor
public Main()
{
InitializeComponent();
play();
}
play() is something like this:
private void play()
{
//Does the socket initialization
do
{
//...
while (true)
{
//Reads text from client
//The text contains a string, indicating the path to the song.
byte[] bytesFrom = new byte[10025];
networkStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize);
string dataFromClient = System.Text.Encoding.Default.GetString(bytesFrom);
//Plays the song from the received path
playSong(dataFromClient);
//...Do other stuff
}
} while (_serverOn);
//Closes the socket connection
}
private static void playSong(String path)
{
mciSendString("open \"" + path + "\" type mpegvideo alias MediaFile", null, 0, IntPtr.Zero);
mciSendString("play MediaFile", null, 0, IntPtr.Zero);
}
I had similar problem a while back... Pain in the butt.
You are doing cross thread operations, that is not safe. That is the reason why it crashes. You are absolutely right about where you problem is.
Here is msdn documentation on this thread operations http://msdn.microsoft.com/en-us/library/ms171728.aspx
You need to add delegate definition for mciSendString => mciSendStringCallBack
delegate void mciSendStringCallBack(string strCommand, StringBuilder strReturn, int iReturnLength, IntPtr hwndCallback);
In private static void playSong(String path) you need to check if InvokeRequired, if it is you need to instantiate callback and invoke it.
mciSendStringCallBack method = new mciSendStringCallBack(....);
this.Invoke(method , new object[] { .....});
Look through the example on the msdn site, they do a good job demonstrating who it works.
--
You might want to try using background worker, it gives you multi threaded way of doing things, easier to work with.
I suspect that MCI functions may needs a Message Loop running. Besides, MCI requests are unblocking so your thread will die once you invoke the MCI operation. You need to keep running the message loop on that thread (using Application.Run) till MCI finishes (you will know that by requesting the callback by passing the window handle). See this article that illustrates how it is done.
Edit: Perhaps a hidden form launched over new thread can reduce the work do be done. But you still need to receive callback from MCI to terminate the thread.
The accepted answer above still runs mciSendString on the UI thread. I needed to move it off the UI thread because it was taking too long (>200ms to save a file), so I came up with this solution:
var t = new Thread(Dispatcher.Run);
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
var d = Dispatcher.FromThread(t)
d.InvokeAsync(() => mciSendString(command, null, 0, IntPtr.Zero));