M
Matt Kellner _MSFT_
Guest
Hi there. I'm trying to write a C# wrapper around a named pipe so I can create an event-driven "Pipe Server" in my application. The idea is that I can create a pool of pipes that'll sit in the background and service any number of clients, raising events when messages come in and also supporting pushing data down to the clients at will. True bi-directional piping.
The one question I can't seem to answer through MSDN is how, on the server end, I can detect that a client has disconnected from the server. All I see is that if I attempt to run a command on a pipe that has been broken, closed or disconnected, it'll throw an exception then. But is there any async command or event I can tap into that will tell me when a client disconnects? (Aside from making the client send a message to the server saying it's disconnecting.)
Right now, the basic theory of operation here is to create a PipeServer class that contains a NamedPipeServerStream object, defines some events that the class can raise when a client connects or a message is received, etc. Here's a rough sketch of how this works right now - since I'm totally new to this, I don't really know what I'm doing so much.
public class PipeServer
{
public NamedPipeServerStream oPipe;
IAsyncResult ConnectRequest;
private byte[] oBuffer;
public PipeServer()
{
oPipe = new NamedPipeServerStream("pipetest", PipeDirection.InOut);
oBuffer = new byte[4096];
ConnectRequest = oPipe.BeginWaitForConnection(ClientConnected, null);
}
private void ClientConnected()
{
if( ConnectRequest != null )
{
oPipe.EndWaitForConnection(ConnectRequest);
ConnectRequest = null;
// raise connect event
ConnectRequest = oPipe.BeginRead(oBuffer, 0, 4096, ClientMessage, null);
}
}
private void ClientMessage()
{
if( ConnectRequest != null )
{
oPipe.EndRead(ConnectRequest);
string message = oBuffer.ToString();
// Do something with "message".
ConnectRequest = oPipe.BeginRead(oBuffer, 0, 4096, ClientMessage, null);
}
}
public void SendMessageToClient(string message)
{
if( ConnectRequest != null )
{
oPipe.EndRead(ConnectRequest);
ConnectRequest = null;
}
using( StreamWriter sw = new StreamWriter(oPipe) )
{
sw.AutoFlush = true;
sw.WriteLine(message);
oPipe.WaitForPipeDrain();
}
ConnectRequest = oPipe.BeginRead(oBuffer, 0, 4096, ClientMessage, null);
}
}
With this model, the class object will be sitting idle for the vast majority of the time, and is only meant to execute code when something happens. Something outside the class can call "SendMessageToClient(message)" to have it stop listening and transmit, but otherwise, it's pretty much a read-only object.
As I mentioned, though, there doesn't appear to be a way for me to tell when a disconnect occurs - only that I'll get an exception if one does. And since there's no execution loop within this object, there's no place for me to catch an exception if it does get thrown - I imagine the exception would be sent to the thread that created the object, which means I'd have to wrap pretty much all of my code in a try/catch block and do quite a bit of work to track which of the PipeServer objects threw the exception. Is there a simpler way?
All I really want this for is to enable my client application to request data from the server app, and for the server app to send a message spontaneously saying "Stop what you're doing right now". Currently, the client app has to poll a database every so often to detect an abort condition - I want to make it so the server app can directly control this event. Named pipes seemed to be the most sensible way to do this. (Also, I will have multiple instances of the client app running, so the server needs to be able to control them all dynamically.)
Thanks for any help you can provide. Matt Kellner - SDET, Windows XP Embedded Team
Continue reading...
The one question I can't seem to answer through MSDN is how, on the server end, I can detect that a client has disconnected from the server. All I see is that if I attempt to run a command on a pipe that has been broken, closed or disconnected, it'll throw an exception then. But is there any async command or event I can tap into that will tell me when a client disconnects? (Aside from making the client send a message to the server saying it's disconnecting.)
Right now, the basic theory of operation here is to create a PipeServer class that contains a NamedPipeServerStream object, defines some events that the class can raise when a client connects or a message is received, etc. Here's a rough sketch of how this works right now - since I'm totally new to this, I don't really know what I'm doing so much.
public class PipeServer
{
public NamedPipeServerStream oPipe;
IAsyncResult ConnectRequest;
private byte[] oBuffer;
public PipeServer()
{
oPipe = new NamedPipeServerStream("pipetest", PipeDirection.InOut);
oBuffer = new byte[4096];
ConnectRequest = oPipe.BeginWaitForConnection(ClientConnected, null);
}
private void ClientConnected()
{
if( ConnectRequest != null )
{
oPipe.EndWaitForConnection(ConnectRequest);
ConnectRequest = null;
// raise connect event
ConnectRequest = oPipe.BeginRead(oBuffer, 0, 4096, ClientMessage, null);
}
}
private void ClientMessage()
{
if( ConnectRequest != null )
{
oPipe.EndRead(ConnectRequest);
string message = oBuffer.ToString();
// Do something with "message".
ConnectRequest = oPipe.BeginRead(oBuffer, 0, 4096, ClientMessage, null);
}
}
public void SendMessageToClient(string message)
{
if( ConnectRequest != null )
{
oPipe.EndRead(ConnectRequest);
ConnectRequest = null;
}
using( StreamWriter sw = new StreamWriter(oPipe) )
{
sw.AutoFlush = true;
sw.WriteLine(message);
oPipe.WaitForPipeDrain();
}
ConnectRequest = oPipe.BeginRead(oBuffer, 0, 4096, ClientMessage, null);
}
}
With this model, the class object will be sitting idle for the vast majority of the time, and is only meant to execute code when something happens. Something outside the class can call "SendMessageToClient(message)" to have it stop listening and transmit, but otherwise, it's pretty much a read-only object.
As I mentioned, though, there doesn't appear to be a way for me to tell when a disconnect occurs - only that I'll get an exception if one does. And since there's no execution loop within this object, there's no place for me to catch an exception if it does get thrown - I imagine the exception would be sent to the thread that created the object, which means I'd have to wrap pretty much all of my code in a try/catch block and do quite a bit of work to track which of the PipeServer objects threw the exception. Is there a simpler way?
All I really want this for is to enable my client application to request data from the server app, and for the server app to send a message spontaneously saying "Stop what you're doing right now". Currently, the client app has to poll a database every so often to detect an abort condition - I want to make it so the server app can directly control this event. Named pipes seemed to be the most sensible way to do this. (Also, I will have multiple instances of the client app running, so the server needs to be able to control them all dynamically.)
Thanks for any help you can provide. Matt Kellner - SDET, Windows XP Embedded Team
Continue reading...