C# 具有命名管道的异步服务器和客户端
我想出了以下代码:C# 具有命名管道的异步服务器和客户端,c#,.net,asynchronous,ipc,pipe,C#,.net,Asynchronous,Ipc,Pipe,我想出了以下代码: class IPCServer { private Thread ipcServerThread; private NamedPipeServerStream pipeServer; public IPCServer() { pipeServer = new NamedPipeServerStream("iMedCallInfoPipe", PipeDirection.Out, 1, PipeTransmissionMode.
class IPCServer
{
private Thread ipcServerThread;
private NamedPipeServerStream pipeServer;
public IPCServer()
{
pipeServer = new NamedPipeServerStream("iMedCallInfoPipe", PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
}
public void SendMessage (String message) {
ThreadStart ipcServerThreadInfo = () => WriteToPipe(message);
ipcServerThread = new Thread(ipcServerThreadInfo);
ipcServerThread.Start();
}
private void WriteToPipe(String message)
{
if (pipeServer.IsConnected)
{
byte[] bytes = Encoding.UTF8.GetBytes(message);
pipeServer.Write(bytes, 0, bytes.Length);
pipeServer.WaitForPipeDrain();
pipeServer.Flush();
}
}
}
class ICPClient
{
public void Read(int TimeOut = 1000)
{
try
{
NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", "iMedCallInfoPipe", PipeDirection.In, PipeOptions.None);
pipeStream.Connect(TimeOut);
using (StreamReader sr = new StreamReader(pipeStream))
{
string _buffer;
while ((_buffer = sr.ReadLine()) != null)
{
Console.WriteLine("Received from server: {0}", _buffer);
}
}
}
catch (TimeoutException)
{
}
}
}
这是管道通信解决方案的客户机服务器。但是我需要服务器异步地写消息,而客户端在消息弹出时也异步地读取它们。我怎样才能做到这一点?虽然有很多样本,但大多数都考虑客户端写入服务器,我不知道如何实现我的目标,尤其是我已经编写的代码… 异步模式下应该使用以下函数:
NamedPipeClientStream.BeginRead
NamedPipeClientStream.EndRead
及
此外,我确信在写入缓冲区之前,总是使用WaitForPipeDrain()的正确实现,因为如果您以前写入过缓冲区,则需要检查之前写入缓冲区的内容是否已被读取。如果您先编写,然后使用WaitForPipeDrain(),那么对写入函数的后续调用(甚至错误地)将首先覆盖,然后检查。我没有尝试过,但从逻辑上讲,可以这样认为。在异步模式下,您应该使用以下功能:
NamedPipeClientStream.BeginRead
NamedPipeClientStream.EndRead
及
此外,我确信在写入缓冲区之前,总是使用WaitForPipeDrain()的正确实现,因为如果您以前写入过缓冲区,则需要检查之前写入缓冲区的内容是否已被读取。如果您先编写,然后使用WaitForPipeDrain(),那么对写入函数的后续调用(甚至错误地)将首先覆盖,然后检查。我没有试过,但从逻辑上讲,可以这样认为。首先,你不需要两个管道。。您可以在一个命名管道的两端进行写/读操作,这样它就不会得到消息或顺序了。它也不会被卡住。只要你遵守基本的管道规则,双方都可以随心所欲地快速书写,也可以随时阅读 其次,您应该使用消息模式,而不是字节模式,否则它可能会将发送或读取的消息合并到一个缓冲区中 第三,我非常确定,如果使用基于消息的管道,而不是字节,则不需要调用WaitForPipeDrain或Flush。我想这只会让你不必要地慢下来。如果我错了,有人在下面纠正我吗 最后,您可以通过以下方式“随时”在客户机上获取读取:始终保持异步读取。也就是说,一旦客户机连接到服务器,立即对给定的缓冲区执行异步读取,您知道该缓冲区“足够大”,可以容纳您可能得到的任何内容。当您的异步读取回调被调用(您提供给异步读取方法的回调)时,您将被告知缓冲区已被填充了多少。然后,您可以向客户机类的用户引发事件(您定义的事件),或者调用回调,或者执行一些操作。完成事件回调后,立即执行另一个异步读取。如果没有什么可读的,那没关系,它会在那里等着有东西进来。请注意,如果异步读取始终挂起,当远程管道关闭时,异步读取将以“管道关闭”和“0字节读取”返回给您。这是正常的 下面是我的read方法的一个片段,在我的客户端类中:
public void StartReadingAsync()
{
// Debug.WriteLine("Pipe " + FullPipeNameDebug() + " calling ReadAsync");
// okay we're connected, now immediately listen for incoming buffers
//
byte[] pBuffer = new byte[MaxLen];
m_pPipeStream.ReadAsync(pBuffer, 0, MaxLen).ContinueWith(t =>
{
// Debug.WriteLine("Pipe " + FullPipeNameDebug() + " finished a read request");
// before we call the user back, start reading ANOTHER buffer, so the network stack
// will have something to deliver into and we don't keep it waiting.
// We're called on the "anonymous task" thread. if we queue another call to
// the pipe's read, that request goes down into the kernel, onto a different thread
// and this will be called back again, later. it's not recursive, and perfectly legal.
int ReadLen = t.Result;
if (ReadLen == 0)
{
Debug.WriteLine("Got a null read length, remote pipe was closed");
if (PipeClosedEvent != null)
{
PipeClosedEvent(this, new EventArgs());
}
return;
}
// lodge ANOTHER read request BEFORE calling the user back. Doing this ensures
// the read is ready before we call the user back, which may cause a write request to happen,
// which will zip over to the other end of the pipe, cause a write to happen THERE, and we won't be ready to receive it
// (perhaps it will stay stuck in a kernel queue, and it's not necessary to do this)
//
StartReadingAsync();
if (PipeReadDataEvent != null)
{
PipeReadDataEvent(this, new PipeReadEventArgs(pBuffer, ReadLen));
}
else
{
Debug.Assert(false, "something happened");
}
});
}
首先,你不需要两根管子。。您可以在一个命名管道的两端进行写/读操作,这样它就不会得到消息或顺序了。它也不会被卡住。只要你遵守基本的管道规则,双方都可以随心所欲地快速书写,也可以随时阅读 其次,您应该使用消息模式,而不是字节模式,否则它可能会将发送或读取的消息合并到一个缓冲区中 第三,我非常确定,如果使用基于消息的管道,而不是字节,则不需要调用WaitForPipeDrain或Flush。我想这只会让你不必要地慢下来。如果我错了,有人在下面纠正我吗 最后,您可以通过以下方式“随时”在客户机上获取读取:始终保持异步读取。也就是说,一旦客户机连接到服务器,立即对给定的缓冲区执行异步读取,您知道该缓冲区“足够大”,可以容纳您可能得到的任何内容。当您的异步读取回调被调用(您提供给异步读取方法的回调)时,您将被告知缓冲区已被填充了多少。然后,您可以向客户机类的用户引发事件(您定义的事件),或者调用回调,或者执行一些操作。完成事件回调后,立即执行另一个异步读取。如果没有什么可读的,那没关系,它会在那里等着有东西进来。请注意,如果异步读取始终挂起,当远程管道关闭时,异步读取将以“管道关闭”和“0字节读取”返回给您。这是正常的 下面是我的read方法的一个片段,在我的客户端类中:
public void StartReadingAsync()
{
// Debug.WriteLine("Pipe " + FullPipeNameDebug() + " calling ReadAsync");
// okay we're connected, now immediately listen for incoming buffers
//
byte[] pBuffer = new byte[MaxLen];
m_pPipeStream.ReadAsync(pBuffer, 0, MaxLen).ContinueWith(t =>
{
// Debug.WriteLine("Pipe " + FullPipeNameDebug() + " finished a read request");
// before we call the user back, start reading ANOTHER buffer, so the network stack
// will have something to deliver into and we don't keep it waiting.
// We're called on the "anonymous task" thread. if we queue another call to
// the pipe's read, that request goes down into the kernel, onto a different thread
// and this will be called back again, later. it's not recursive, and perfectly legal.
int ReadLen = t.Result;
if (ReadLen == 0)
{
Debug.WriteLine("Got a null read length, remote pipe was closed");
if (PipeClosedEvent != null)
{
PipeClosedEvent(this, new EventArgs());
}
return;
}
// lodge ANOTHER read request BEFORE calling the user back. Doing this ensures
// the read is ready before we call the user back, which may cause a write request to happen,
// which will zip over to the other end of the pipe, cause a write to happen THERE, and we won't be ready to receive it
// (perhaps it will stay stuck in a kernel queue, and it's not necessary to do this)
//
StartReadingAsync();
if (PipeReadDataEvent != null)
{
PipeReadDataEvent(this, new PipeReadEventArgs(pBuffer, ReadLen));
}
else
{
Debug.Assert(false, "something happened");
}
});
}
听起来你需要两个客户端和两个服务器。你为什么这么认为?我只需要服务器写入管道,客户端读取管道,但我不想让它循环,所以异步方法听起来是个更好的主意。但我不确定如何在服务器中实现BeginWrite和在客户端实现BeginRead。您不使用WCF有什么特殊原因吗?在我看来,客户端和服务器角色可能会颠倒:通常服务器角色会响应来自客户端角色的事件。也许客户端(如图所示)应该使用PipeDirection打开一个管道。在和中,服务器(如图所示)应该在服务器生成事件时打开并写入管道。听起来您需要两个客户端和两个服务器。为什么这样认为?我只需要服务器写入管道,客户端读取管道,但我不想让它循环,所以异步方法听起来是个更好的主意。但我不确定如何在服务器中实现BeginWrite和在客户端实现BeginRead。您不使用WCF有什么特殊原因吗?在我看来,客户端和服务器角色可能会颠倒:通常服务器角色会响应来自客户端角色的事件。也许客户端(如图所示)应该使用PipeDirection.In打开一个管道,而服务器(如图所示)应该使用sh