By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,827 Members | 2,195 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,827 IT Pros & Developers. It's quick & easy.

Fast Multiple Application Comunication

P: n/a
This post is realy to get some opinions on the best way of getting fast
comunication between multiple applications. I have scowered the web for
imformation on this subject and have just found conflicting views and
far from ideal solutions.

My application has to send small amounts of data about 50bytes to
multiple client applications. The catch is that this has to happen
about 1000 times a second.

My first attempt was .net remotting which I have to say worked very
well. After I developed a host of helper classes to get around such
problems as events it works fine and seems to work. However it is no
where near fast enough and as you start to reach the desired refresh
rate the CPU races the memory usage goes through the roof and the
entire system keels over.

So I have reached the conclusion that remoting is not going to provide
me with the answer. That leaves me with a question, what else? Here is
a list of the candidates I have found to date:

1. Named Pipes
2. Custom Remotting Sink
3. Mutex
4. TCP Socket

Unfortunatly all these solutions seem to have problems. A named pipe is
not part of the .net framework and does not seem to support message
notification very well. I am not even sure if a custom romting Sink
will actually improve things. Again Mutex's are not inherant in the
..net framework; they are not object orientated and are highly
discouraged by Microsoft. A TCP Socket would require allot of work to
construct wrappers and comunications layers, I want an easy life.

So I would apreciate comments on the best method to achieve high
performance and fast inter application comunication. I should say that
primarily I am concerned with applications running on the same machine
and idealy it would be asynchronous.

May 12 '06 #1
Share this Question
Share on Google+
11 Replies


P: n/a
1000 times per second? Easy life? I don't think they're compatible!

Named pipes are best and you'll almost certainly find a wrapper for them at
pinvoke.net. Failing that, I would look at UDP rather than TCP. It's very
easy to do using System.Net.Sockets and UdpClient object.

Steve
May 12 '06 #2

P: n/a
You seem to have left out shared memory which would be the fastest solution
if you are running on the same machine. Here is a simple wrapper that may
help you out a bit http://addressof.com/blog/archive/2003/05/01/164.aspx

Another solution that you have left out is using a shared file for
communications which can also be extremely fast (I had no issue pushing
10k/second through this mechanism). Generally the way to do this is to use a
checkpointing mechanism, then just seek within the filestream. I have an old
example I could probably pull out if you are interested in going this route
....

I am not sure what you are talking about in dealign with the mutex below,
mutexes are implemented in the .net framework but they are not used for
pushing data from one app to another, they are used for synchronization?
Also there is nothing that says they are bad to use; they are quite often
used to synchronize processes, they are just not generally used within the
same process space as Monitor provides the same functionality with better
performance and without the overhead of the OS resource.

Cheers,

Greg Young
MVP - C#
"Olie" <ow****@gmail.com> wrote in message
news:11*********************@g10g2000cwb.googlegro ups.com...
This post is realy to get some opinions on the best way of getting fast
comunication between multiple applications. I have scowered the web for
imformation on this subject and have just found conflicting views and
far from ideal solutions.

My application has to send small amounts of data about 50bytes to
multiple client applications. The catch is that this has to happen
about 1000 times a second.

My first attempt was .net remotting which I have to say worked very
well. After I developed a host of helper classes to get around such
problems as events it works fine and seems to work. However it is no
where near fast enough and as you start to reach the desired refresh
rate the CPU races the memory usage goes through the roof and the
entire system keels over.

So I have reached the conclusion that remoting is not going to provide
me with the answer. That leaves me with a question, what else? Here is
a list of the candidates I have found to date:

1. Named Pipes
2. Custom Remotting Sink
3. Mutex
4. TCP Socket

Unfortunatly all these solutions seem to have problems. A named pipe is
not part of the .net framework and does not seem to support message
notification very well. I am not even sure if a custom romting Sink
will actually improve things. Again Mutex's are not inherant in the
.net framework; they are not object orientated and are highly
discouraged by Microsoft. A TCP Socket would require allot of work to
construct wrappers and comunications layers, I want an easy life.

So I would apreciate comments on the best method to achieve high
performance and fast inter application comunication. I should say that
primarily I am concerned with applications running on the same machine
and idealy it would be asynchronous.

May 12 '06 #3

P: n/a
Mind to add the number of client applications to your requirements, this
figure is important has I guess whatever IPC mechanims you use, you will peg
the CPU, unless you are willing to invest into multi-cpu boxes. Anothor
question is; are you pushing 1000 * 50 byte messages to each separate
client, or are you simply broadcasting?

Willy.
"Olie" <ow****@gmail.com> wrote in message
news:11*********************@g10g2000cwb.googlegro ups.com...
| This post is realy to get some opinions on the best way of getting fast
| comunication between multiple applications. I have scowered the web for
| imformation on this subject and have just found conflicting views and
| far from ideal solutions.
|
| My application has to send small amounts of data about 50bytes to
| multiple client applications. The catch is that this has to happen
| about 1000 times a second.
|
| My first attempt was .net remotting which I have to say worked very
| well. After I developed a host of helper classes to get around such
| problems as events it works fine and seems to work. However it is no
| where near fast enough and as you start to reach the desired refresh
| rate the CPU races the memory usage goes through the roof and the
| entire system keels over.
|
| So I have reached the conclusion that remoting is not going to provide
| me with the answer. That leaves me with a question, what else? Here is
| a list of the candidates I have found to date:
|
| 1. Named Pipes
| 2. Custom Remotting Sink
| 3. Mutex
| 4. TCP Socket
|
| Unfortunatly all these solutions seem to have problems. A named pipe is
| not part of the .net framework and does not seem to support message
| notification very well. I am not even sure if a custom romting Sink
| will actually improve things. Again Mutex's are not inherant in the
| .net framework; they are not object orientated and are highly
| discouraged by Microsoft. A TCP Socket would require allot of work to
| construct wrappers and comunications layers, I want an easy life.
|
| So I would apreciate comments on the best method to achieve high
| performance and fast inter application comunication. I should say that
| primarily I am concerned with applications running on the same machine
| and idealy it would be asynchronous.
|
May 12 '06 #4

P: n/a
Yes that is a good point about the number of clients. The requirement
is for up to 20 clients which is relatively small. A broadcast method
would be fine but I do need to ensure that any message gets to all the
clients.

Correct me if I am wrong Greg but I do not believe that I did leave out
Shared Memory or Shared Files as I think Shared Mutex is a lower level
abstraction on Shared Memory and Pipes is an implementation of Shared
Files. I should have maybe elaborated on the Mutex a bit more (cause of
much confusion and I do not profess to have got it correct). Yes .net
does support mutex's for thread synchronisation but this is a different
kind of implementation I believe it only allows access within the
application domain. Another kind of mutex can be used to access the
same object from many applications but I have not found a way to do
this in the .net framework. This is how Shared Memory works it creates
a named mutex of memory that can be accessed from many applications. I
think the reason that shared mutexs are not generally recomended is
that there is no guarantee that the mutex you are connecting has the
same structure.

Thanks Steve, I was definately leaning towards Named Pipes I just
wanted to see if there was a solution to be found that is built into
the .net framework. I am slightly confused that Micrsoft did not think
of the need for fast comunication when developing the framework.

May 12 '06 #5

P: n/a
Yes .net
does support mutex's for thread synchronisation but this is a different
kind of implementation I believe it only allows access within the
application domain. Another kind of mutex can be used to access the
same object from many applications but I have not found a way to do
this in the .net framework. This is how Shared Memory works it creates
a named mutex of memory that can be accessed from many applications. I
think the reason that shared mutexs are not generally recomended is
that there is no guarantee that the mutex you are connecting has the
same structure.
Your assumptions on mutex are incorrect.

A mutex is an OS level locking mechanism ... nothing more ... It is
generally used to synchronize seperate processes. Think of it like a Monitor
(i.e. lock() { }) that can be used through multiple applications.

A mutex is used to synchronize access to global resources (like a shared
file or shared memory). It does not contain any real storage itself.

As for not having the "same sata structure", a mutex will always be a mutex,
this issue may apply to the shared resource but the same issue would apply
to any shared resource (I can easily connect a mail client to a server it
doesn't understand how to deal with and it will not work very well).

Cheers,

Greg Young
MVP - C#
"Olie" <ow****@gmail.com> wrote in message
news:11**********************@i39g2000cwa.googlegr oups.com... Yes that is a good point about the number of clients. The requirement
is for up to 20 clients which is relatively small. A broadcast method
would be fine but I do need to ensure that any message gets to all the
clients.

Correct me if I am wrong Greg but I do not believe that I did leave out
Shared Memory or Shared Files as I think Shared Mutex is a lower level
abstraction on Shared Memory and Pipes is an implementation of Shared
Files. I should have maybe elaborated on the Mutex a bit more (cause of
much confusion and I do not profess to have got it correct). Yes .net
does support mutex's for thread synchronisation but this is a different
kind of implementation I believe it only allows access within the
application domain. Another kind of mutex can be used to access the
same object from many applications but I have not found a way to do
this in the .net framework. This is how Shared Memory works it creates
a named mutex of memory that can be accessed from many applications. I
think the reason that shared mutexs are not generally recomended is
that there is no guarantee that the mutex you are connecting has the
same structure.

Thanks Steve, I was definately leaning towards Named Pipes I just
wanted to see if there was a solution to be found that is built into
the .net framework. I am slightly confused that Micrsoft did not think
of the need for fast comunication when developing the framework.

May 12 '06 #6

P: n/a
I should add that shared resources such as shared memory and files while
fast are best used on the same machine .. if there are machine boundaries
then you are better off with something like UDP and MSNs (message sequence
numbers)
"Olie" <ow****@gmail.com> wrote in message
news:11**********************@i39g2000cwa.googlegr oups.com...
Yes that is a good point about the number of clients. The requirement
is for up to 20 clients which is relatively small. A broadcast method
would be fine but I do need to ensure that any message gets to all the
clients.

Correct me if I am wrong Greg but I do not believe that I did leave out
Shared Memory or Shared Files as I think Shared Mutex is a lower level
abstraction on Shared Memory and Pipes is an implementation of Shared
Files. I should have maybe elaborated on the Mutex a bit more (cause of
much confusion and I do not profess to have got it correct). Yes .net
does support mutex's for thread synchronisation but this is a different
kind of implementation I believe it only allows access within the
application domain. Another kind of mutex can be used to access the
same object from many applications but I have not found a way to do
this in the .net framework. This is how Shared Memory works it creates
a named mutex of memory that can be accessed from many applications. I
think the reason that shared mutexs are not generally recomended is
that there is no guarantee that the mutex you are connecting has the
same structure.

Thanks Steve, I was definately leaning towards Named Pipes I just
wanted to see if there was a solution to be found that is built into
the .net framework. I am slightly confused that Micrsoft did not think
of the need for fast comunication when developing the framework.

May 12 '06 #7

P: n/a
"Olie" <ow****@gmail.com> wrote:
Another kind of mutex can be used to access the
same object from many applications but I have not found a way to do
this in the .net framework. This is how Shared Memory works it creates
a named mutex of memory that can be accessed from many applications.


A named mutex is still exactly that, a synchronization object for
ensuring MUTual EXclusion. Named mutexes are used for inter-process
synchronization. To use shared memory or shared files for inter-process
communication requires synchronization, so that other applications know
when the memory has been updated, and when it is being modified so that
they will not attempt concurrent updates. Mutexes can fill this role,
but mutexes do not represent shared memory.

-- Barry
May 12 '06 #8

P: n/a
I just wanted to correct myself as I have discovered that there is a
way in the .net framework to use named pipes although this is new to
version 2. If you use an IpcChannel then it will use named pipes as the
method of transfering the serialized objects. This does give you a huge
performance benefit over Tcp channels but will obviously work only on
the local machine.

May 15 '06 #9

P: n/a

"Olie" <ow****@gmail.com> wrote in message
news:11**********************@i40g2000cwc.googlegr oups.com...
|I just wanted to correct myself as I have discovered that there is a
| way in the .net framework to use named pipes although this is new to
| version 2. If you use an IpcChannel then it will use named pipes as the
| method of transfering the serialized objects. This does give you a huge
| performance benefit over Tcp channels but will obviously work only on
| the local machine.
|

Be carefull, I would not call it a 'huge' performance benefit, the benefit
depends largely on the size of the messages passed.
There is a clear benefit over tcp when dealing with small messages, when
passing large messages though, tcp is the clear winner.

Willy.

May 15 '06 #10

P: n/a
We used shared memory in our applications to accomplish this. We also
used NT events for event sending. In our case many types of applications
interfaced to the shared memory. We had applications written in C, C++,
VB4, C#,VB.Net, Labview, Java. This is the nice thing of shared memory
many different language systems can access the data. With .Net 2.0 you
have the ability to create a C++ assembly that can very easily interface
with the unmanaged C++ data structures you must put into the shared
memory. No need to use pInvoke anymore.

Having said this it is very difficult to create a multiprocess shared
memory pool with event handling and garbage collection unless you are an
expert on concurrency. So expect to spend a lot of time on this but once
you have it you will be surprised how it applies to many different
problems. In our case it also can be used remotely on other computers by
having a process that replicates the repository on other computers and
has a priority based updating mechanism. This typical would be lower
data rate items like summary data. Remote computers cannot be expected
to get real-time data at super fast data rates.

Hope this helps
Leon Lambert

Olie wrote:
This post is realy to get some opinions on the best way of getting fast
comunication between multiple applications. I have scowered the web for
imformation on this subject and have just found conflicting views and
far from ideal solutions.

My application has to send small amounts of data about 50bytes to
multiple client applications. The catch is that this has to happen
about 1000 times a second.

My first attempt was .net remotting which I have to say worked very
well. After I developed a host of helper classes to get around such
problems as events it works fine and seems to work. However it is no
where near fast enough and as you start to reach the desired refresh
rate the CPU races the memory usage goes through the roof and the
entire system keels over.

So I have reached the conclusion that remoting is not going to provide
me with the answer. That leaves me with a question, what else? Here is
a list of the candidates I have found to date:

1. Named Pipes
2. Custom Remotting Sink
3. Mutex
4. TCP Socket

Unfortunatly all these solutions seem to have problems. A named pipe is
not part of the .net framework and does not seem to support message
notification very well. I am not even sure if a custom romting Sink
will actually improve things. Again Mutex's are not inherant in the
.net framework; they are not object orientated and are highly
discouraged by Microsoft. A TCP Socket would require allot of work to
construct wrappers and comunications layers, I want an easy life.

So I would apreciate comments on the best method to achieve high
performance and fast inter application comunication. I should say that
primarily I am concerned with applications running on the same machine
and idealy it would be asynchronous.

May 15 '06 #11

P: n/a
les
Having just completed a comprehensive and tedious struggle with getting
a Named Pipes wrapper working in C#, I've posted my code below for the
next poor soul. This solution may not fit the O/P problem exactly, but
it does work for both client and server ends of the pipe.

Naturally, it can be improved.

Steve Foster wrote:
1000 times per second? Easy life? I don't think they're compatible!

Named pipes are best and you'll almost certainly find a wrapper for them at
pinvoke.net. Failing that, I would look at UDP rather than TCP. It's very
easy to do using System.Net.Sockets and UdpClient object.

Steve


/* Code for NamedPipeStream */
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Text;

namespace NamedPipeUtil
{
/// <summary>
/// NamedPipeStream is an odd little hybrid between the client and
server ends of a NamedPipe,
/// and a System.IO.Stream subclass. Basically, it simplifies the
unnecessarily horrific process
/// of implementing named pipe support in .Net. (If you doubt
this, try it the hard way... we'll wait.)
///
/// Usage idiom:
///
/// Server side
/// -----------
/// 1. Call NamedPipeStream.Create, specify inbound,
outbound, or both
/// 2. Call Listen(). This will block until a client
connects. Sorry, the alternatives
/// are ugly. Use a thread.
/// 3. Call DataAvailable() in a loop with Read(),
Write, ReadLine(), etc. until IsConnected turns false.
/// 4. Call Listen() again to wait for the next client.
///
/// Client side
/// -----------
/// 1. Call Open()
/// 2. Call DataAvailable(), Read(), Write(), etc.
until you're done,
/// then call Close();
///
/// And yes, you can attach TextReader and TextWriter instances
to this stream.
///
/// Server side caveat:
///
/// The idiom described above only supports a single
client at a time. If you need
/// to support multiple clients, multiple calls to
Create()/Listen() in separate threads is the
/// recommended approach.
///
/// There is a test driver class at the end of this file which
can be cannibalized for sample usage code.
///
/// </summary>
public class NamedPipeStream : Stream
{
[DllImport("kernel32.dll", EntryPoint = "CreateFile",
SetLastError = true)]
private static extern IntPtr CreateFile(String lpFileName,
UInt32 dwDesiredAccess, UInt32 dwShareMode,
IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition,
UInt32 dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateNamedPipe(
String lpName, // pipe name
uint dwOpenMode, // pipe open mode
uint dwPipeMode, // pipe-specific modes
uint nMaxInstances, // maximum number of instances
uint nOutBufferSize, // output buffer size
uint nInBufferSize, // input buffer size
uint nDefaultTimeOut, // time-out interval
IntPtr pipeSecurityDescriptor // SD
);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool DisconnectNamedPipe(
IntPtr hHandle);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool ConnectNamedPipe(
IntPtr hHandle, // handle to named pipe
IntPtr lpOverlapped // overlapped structure
);
[DllImport("kernel32.dll", EntryPoint = "PeekNamedPipe",
SetLastError = true)]
private static extern bool PeekNamedPipe(IntPtr handle,
byte[] buffer, uint nBufferSize, ref uint bytesRead,
ref uint bytesAvail, ref uint BytesLeftThisMessage);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool ReadFile(IntPtr handle,
byte[] buffer, uint toRead, ref uint read, IntPtr
lpOverLapped);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool WriteFile(IntPtr handle,
byte[] buffer, uint count, ref uint written, IntPtr
lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr handle);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FlushFileBuffers(IntPtr handle);
/*[DllImport("kernel32.dll", SetLastError = true)]
private static extern uint GetLastError();*/
//Constants for dwDesiredAccess:
private const UInt32 GENERIC_READ = 0x80000000;
private const UInt32 GENERIC_WRITE = 0x40000000;

//Constants for return value:
private const Int32 INVALID_HANDLE_VALUE = -1;

//Constants for dwFlagsAndAttributes:
private const UInt32 FILE_FLAG_OVERLAPPED = 0x40000000;
private const UInt32 FILE_FLAG_NO_BUFFERING = 0x20000000;

//Constants for dwCreationDisposition:
private const UInt32 OPEN_EXISTING = 3;
#region Comments
/// <summary>
/// Outbound pipe access.
/// </summary>
#endregion
private const uint PIPE_ACCESS_OUTBOUND = 0x00000002;
#region Comments
/// <summary>
/// Duplex pipe access.
/// </summary>
#endregion
private const uint PIPE_ACCESS_DUPLEX = 0x00000003;
#region Comments
/// <summary>
/// Inbound pipe access.
/// </summary>
#endregion
private const uint PIPE_ACCESS_INBOUND = 0x00000001;
#region Comments
/// <summary>
/// Pipe blocking mode.
/// </summary>
#endregion
private const uint PIPE_WAIT = 0x00000000;
#region Comments
/// <summary>
/// Pipe non-blocking mode.
/// </summary>
#endregion
private const uint PIPE_NOWAIT = 0x00000001;
#region Comments
/// <summary>
/// Pipe read mode of type Byte.
/// </summary>
#endregion
private const uint PIPE_READMODE_BYTE = 0x00000000;
#region Comments
/// <summary>
/// Pipe read mode of type Message.
/// </summary>
#endregion
private const uint PIPE_READMODE_MESSAGE = 0x00000002;
#region Comments
/// <summary>
/// Byte pipe type.
/// </summary>
#endregion
private const uint PIPE_TYPE_BYTE = 0x00000000;
#region Comments
/// <summary>
/// Message pipe type.
/// </summary>
#endregion
private const uint PIPE_TYPE_MESSAGE = 0x00000004;
#region Comments
/// <summary>
/// Pipe client end.
/// </summary>
#endregion
private const uint PIPE_CLIENT_END = 0x00000000;
#region Comments
/// <summary>
/// Pipe server end.
/// </summary>
#endregion
private const uint PIPE_SERVER_END = 0x00000001;
#region Comments
/// <summary>
/// Unlimited server pipe instances.
/// </summary>
#endregion
private const uint PIPE_UNLIMITED_INSTANCES = 255;
#region Comments
/// <summary>
/// Waits indefinitely when connecting to a pipe.
/// </summary>
#endregion
private const uint NMPWAIT_WAIT_FOREVER = 0xffffffff;
#region Comments
/// <summary>
/// Does not wait for the named pipe.
/// </summary>
#endregion
private const uint NMPWAIT_NOWAIT = 0x00000001;
#region Comments
/// <summary>
/// Uses the default time-out specified in a call to the
CreateNamedPipe method.
/// </summary>
#endregion
private const uint NMPWAIT_USE_DEFAULT_WAIT = 0x00000000;

private const ulong ERROR_PIPE_CONNECTED = 535;

/// <summary>
/// Server side creation option:
/// </summary>
public enum ServerMode
{
InboundOnly = (int)PIPE_ACCESS_INBOUND,
OutboundOnly = (int)PIPE_ACCESS_OUTBOUND,
Bidirectional =
(int)(PIPE_ACCESS_INBOUND+PIPE_ACCESS_OUTBOUND)
};

public enum PeerType
{
Client = 0,
Server = 1
};

IntPtr _handle;
FileAccess _mode;
PeerType _peerType;

protected NamedPipeStream()
{
_handle = IntPtr.Zero;
_mode = (FileAccess)0;
_peerType = PeerType.Server;
}

public NamedPipeStream(string pipename, FileAccess mode)
{
_handle = IntPtr.Zero;
_peerType = PeerType.Client;
Open(pipename, mode);
}
public NamedPipeStream(IntPtr handle, FileAccess mode)
{
_handle = handle;
_mode = mode;
_peerType = PeerType.Client;
}

/// <summary>
/// Opens the client side of a pipe.
/// </summary>
/// <param name="pipe">Full path to the pipe, e.g.
'\\.\pipe\mypipe'</param>
/// <param name="mode">Read,Write, or ReadWrite - must be
compatible with server-side creation mode</param>
public void Open(string pipename, FileAccess mode)
{

uint pipemode = 0;

if ((mode & FileAccess.Read) > 0)
pipemode |= GENERIC_READ;
if ((mode & FileAccess.Write) > 0)
pipemode |= GENERIC_WRITE;
IntPtr handle = CreateFile(pipename, pipemode,
0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);

if (handle.ToInt32() == INVALID_HANDLE_VALUE)
{
int err = Marshal.GetLastWin32Error();
throw new Win32Exception(err,
string.Format("NamedPipeStream.Open failed, win32
error code {0}, pipename '{1}' ",err,pipename));
}

_mode = mode;
_handle = handle;

}
/// <summary>
/// Create a named pipe instance.
/// </summary>
/// <param name="pipeName">Local name (the part after
\\.\pipe\)</param>
public static NamedPipeStream Create(string pipeName,
ServerMode mode)
{
IntPtr handle = IntPtr.Zero;
string name = @"\\.\pipe\" + pipeName;

handle = CreateNamedPipe(
name,
(uint)mode,
PIPE_TYPE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
0, // outBuffer,
1024, // inBuffer,
NMPWAIT_WAIT_FOREVER,
IntPtr.Zero);
if (handle.ToInt32() == INVALID_HANDLE_VALUE)
{
throw new Win32Exception("Error creating named pipe " +
name + " . Internal error: " + Marshal.GetLastWin32Error().ToString());
}
// Set members persistently...
NamedPipeStream self = new NamedPipeStream();
self._handle = handle;
switch (mode)
{
case ServerMode.InboundOnly:
self._mode = FileAccess.Read;
break;
case ServerMode.OutboundOnly:
self._mode = FileAccess.Write;
break;
case ServerMode.Bidirectional:
self._mode = FileAccess.ReadWrite;
break;
}
return self;
}
/// <summary>
/// Server only: block until client connects
/// </summary>
/// <returns></returns>
public bool Listen()
{
if (_peerType != PeerType.Server)
throw new Exception("Listen() is only for server-side
streams");
DisconnectNamedPipe(_handle);
if (ConnectNamedPipe(_handle, IntPtr.Zero) == true)
{
uint lastErr = (uint)Marshal.GetLastWin32Error();
if (lastErr == ERROR_PIPE_CONNECTED)
return true;
return false;
}
return true;
}
/// <summary>
/// Server only: disconnect the pipe. For most applications,
you should just call Listen()
/// instead, which automatically does a disconnect of any old
connection.
/// </summary>
public void Disconnect()
{
if (_peerType != PeerType.Server)
throw new Exception("Disconnect() is only for
server-side streams");
DisconnectNamedPipe(_handle);
}
/// <summary>
/// Returns true if client is connected. Should only be called
after Listen() succeeds.
/// </summary>
/// <returns></returns>
public bool IsConnected
{
get
{
if (_peerType != PeerType.Server)
throw new Exception("IsConnected() is only for
server-side streams");

if (ConnectNamedPipe(_handle, IntPtr.Zero) == false)
{
if ((uint)Marshal.GetLastWin32Error() ==
ERROR_PIPE_CONNECTED)
return true;
}
return false;
}
}
public bool DataAvailable
{
get
{
uint bytesRead = 0, avail = 0, thismsg = 0;

bool result = PeekNamedPipe(_handle,
null, 0, ref bytesRead, ref avail, ref thismsg);
return (result == true && avail > 0);
}
}

public override bool CanRead
{
get { return (_mode & FileAccess.Read) > 0; }
}

public override bool CanWrite
{
get { return (_mode & FileAccess.Write) > 0; }
}

public override bool CanSeek
{
get { return false; }
}

public override long Length
{
get { throw new NotSupportedException("NamedPipeStream does
not support seeking"); }
}

public override long Position
{
get { throw new NotSupportedException("NamedPipeStream does
not support seeking"); }
set { }
}

public override void Flush()
{
if (_handle == IntPtr.Zero)
throw new ObjectDisposedException("NamedPipeStream",
"The stream has already been closed");
FlushFileBuffers(_handle);
}

public override int Read(byte[] buffer, int offset, int count)
{
if (buffer == null)
throw new ArgumentNullException("buffer", "The buffer
to read into cannot be null");
if (buffer.Length < (offset + count))
throw new ArgumentException("Buffer is not large enough
to hold requested data", "buffer");
if (offset < 0)
throw new ArgumentOutOfRangeException("offset", offset,
"Offset cannot be negative");
if (count < 0)
throw new ArgumentOutOfRangeException("count", count,
"Count cannot be negative");
if (!CanRead)
throw new NotSupportedException("The stream does not
support reading");
if (_handle == IntPtr.Zero)
throw new ObjectDisposedException("NamedPipeStream",
"The stream has already been closed");

// first read the data into an internal buffer since
ReadFile cannot read into a buf at
// a specified offset
uint read = 0;

byte[] buf = buffer;
if (offset != 0)
{
buf = new byte[count];
}
bool f = ReadFile(_handle, buf, (uint)count, ref read,
IntPtr.Zero);
if (!f)
{
throw new Win32Exception(Marshal.GetLastWin32Error(),
"ReadFile failed");
}
if (offset != 0)
{
for (int x = 0; x < read; x++)
{
buffer[offset + x] = buf[x];
}

}
return (int)read;
}

public override void Close()
{
CloseHandle(_handle);
_handle = IntPtr.Zero;
}

public override void SetLength(long length)
{
throw new NotSupportedException("NamedPipeStream doesn't
support SetLength");
}

public override void Write(byte[] buffer, int offset, int
count)
{
if (buffer == null)
throw new ArgumentNullException("buffer", "The buffer
to write into cannot be null");
if (buffer.Length < (offset + count))
throw new ArgumentException("Buffer does not contain
amount of requested data", "buffer");
if (offset < 0)
throw new ArgumentOutOfRangeException("offset", offset,
"Offset cannot be negative");
if (count < 0)
throw new ArgumentOutOfRangeException("count", count,
"Count cannot be negative");
if (!CanWrite)
throw new NotSupportedException("The stream does not
support writing");
if (_handle == IntPtr.Zero)
throw new ObjectDisposedException("NamedPipeStream",
"The stream has already been closed");

// copy data to internal buffer to allow writing from a
specified offset
if (offset != 0)
{
byte[] buf = new Byte[count];
for (int x = 0; x < count; x++)
{
buf[x] = buffer[offset + x];
}
buffer = buf;
}
uint written = 0;
bool result = WriteFile(_handle, buffer, (uint)count, ref
written, IntPtr.Zero);

if (!result)
{
int err = (int)Marshal.GetLastWin32Error();
throw new Win32Exception(err,"Writing to the stream
failed");
}
if (written < count)
throw new IOException("Unable to write entire buffer to
stream");
}

public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException("NamedPipeStream doesn't
support seeking");
}
}

public class NamedPipeTest
{
/// <summary>
/// Test / demo code:
/// </summary>
/// <param name="args"></param>
public static void Main(string[] args)
{
if (args.Length == 0)
{
/*
* Server-side sample code:

*/

NamedPipeStream stream =
NamedPipeStream.Create("testpipe",
NamedPipeStream.ServerMode.Bidirectional);
StreamReader sr = new
StreamReader(stream,Encoding.Unicode);
Console.WriteLine("Listening...");
do
{
stream.Listen();
do
{
bool dataRead = false;
while (stream.DataAvailable)
{
try
{
string s = sr.ReadLine();
if (s != null && s.Length > 0)
{
StreamWriter sw = new
StreamWriter(stream, Encoding.Unicode);
sw.WriteLine(s);
sw.Flush();
Console.WriteLine(s);
dataRead = true;
}
}
catch { }
}
System.Threading.Thread.Sleep(dataRead ? 50 :
1000);

} while (stream.IsConnected);

} while (true);

}
else
{
/*
// Client side sample code:
*/
NamedPipeStream stream = new
NamedPipeStream(@"\\.\pipe\testpipe", FileAccess.ReadWrite);

StreamWriter sw = new StreamWriter(stream,
Encoding.Unicode);

sw.AutoFlush = true;

for (int i = 0; i < 500; i++)
{
sw.WriteLine("Hello world {0}", i);
System.Threading.Thread.Sleep(1000);
if (stream.DataAvailable)
{
StreamReader sr = new StreamReader(stream);
Console.WriteLine(sr.ReadLine());
}
}

sw.Write("Final line");

sw.Close();
}
}
}

}

May 19 '06 #12

This discussion thread is closed

Replies have been disabled for this discussion.