C# 在本机命名管道和System.IO命名管道之间发送多条消息
我需要在本机命名管道和System.IO命名管道之间发送多条消息。我从一体式代码框架(IPC和RPC)中获得了通信两端的代码 服务器:C# 在本机命名管道和System.IO命名管道之间发送多条消息,c#,named-pipes,.net,native-methods,C#,Named Pipes,.net,Native Methods,我需要在本机命名管道和System.IO命名管道之间发送多条消息。我从一体式代码框架(IPC和RPC)中获得了通信两端的代码 服务器: SafePipeHandle hNamedPipe = null; try { SECURITY_ATTRIBUTES sa = null; sa = CreateNativePipeSecurity(); // Create the named pipe. hNamedPipe = NativeMethod.CreateNamedPipe( Con
SafePipeHandle hNamedPipe = null;
try { SECURITY_ATTRIBUTES sa = null;
sa = CreateNativePipeSecurity();
// Create the named pipe.
hNamedPipe = NativeMethod.CreateNamedPipe(
Constants.FullPipeName, // The unique pipe name.
PipeOpenMode.PIPE_ACCESS_DUPLEX, // The pipe is duplex
PipeMode.PIPE_TYPE_MESSAGE | // Message type pipe
PipeMode.PIPE_READMODE_MESSAGE | // Message-read mode
PipeMode.PIPE_WAIT, // Blocking mode is on
PIPE_UNLIMITED_INSTANCES, // Max server instances
1024, // Output buffer size
1024, // Input buffer size
NMPWAIT_USE_DEFAULT_WAIT, // Time-out interval
sa // Pipe security attributes
);
if (hNamedPipe.IsInvalid)
{
throw new Win32Exception();
}
Console.WriteLine("The named pipe ({0}) is created.", Constants.FullPipeName);
// Wait for the client to connect.
Console.WriteLine("Waiting for the client's connection...");
if (!NativeMethod.ConnectNamedPipe(hNamedPipe, IntPtr.Zero))
{
if (Marshal.GetLastWin32Error() != ERROR_PIPE_CONNECTED)
{
throw new Win32Exception();
}
}
Console.WriteLine("Client is connected.");
//
// Receive a request from client.
//
string message;
bool finishRead = false;
do
{
byte[] bRequest = new byte[1024];
int cbRequest = bRequest.Length, cbRead;
finishRead = NativeMethod.ReadFile(
hNamedPipe, // Handle of the pipe
bRequest, // Buffer to receive data
cbRequest, // Size of buffer in bytes
out cbRead, // Number of bytes read
IntPtr.Zero // Not overlapped
);
if (!finishRead &&
Marshal.GetLastWin32Error() != ERROR_MORE_DATA)
{
throw new Win32Exception();
}
// Unicode-encode the received byte array and trim all the
// '\0' characters at the end.
message = Encoding.Unicode.GetString(bRequest).TrimEnd('\0');
Console.WriteLine("Receive {0} bytes from client: \"{1}\"", cbRead, message);
}
while (!finishRead); // Repeat loop if ERROR_MORE_DATA
//
// Send a response from server to client.
//
message = "Goodbye\0";
byte[] bResponse = Encoding.Unicode.GetBytes(message);
int cbResponse = bResponse.Length, cbWritten;
if (!NativeMethod.WriteFile(
hNamedPipe, // Handle of the pipe
bResponse, // Message to be written
cbResponse, // Number of bytes to write
out cbWritten, // Number of bytes written
IntPtr.Zero // Not overlapped
))
{
throw new Win32Exception();
}
Console.WriteLine("Send {0} bytes to client: \"{1}\"",
cbWritten, message.TrimEnd('\0'));
// Flush the pipe to allow the client to read the pipe's contents
// before disconnecting. Then disconnect the client's connection.
NativeMethod.FlushFileBuffers(hNamedPipe);
NativeMethod.DisconnectNamedPipe(hNamedPipe);
}
捕获(例外情况除外){
WriteLine(“服务器抛出错误:{0}”,例如Message);
}
最后
{
如果(hNamedPipe!=null)
{
hNamedPipe.Close();
hNamedPipe=null;
}
}
客户:
NamedPipeClientStream pipeClient = null;
try
{
// Try to open the named pipe identified by the pipe name.
pipeClient = new NamedPipeClientStream(
".", // The server name
Constants.PipeName, // The unique pipe name
PipeDirection.InOut, // The pipe is duplex
PipeOptions.None // No additional parameters
);
pipeClient.Connect(5000);
MessageBox.Show(
string.Format( "The named pipe ({0}) is connected.", Constants.PipeName )
);
pipeClient.ReadMode = PipeTransmissionMode.Message;
//
// Send a request from client to server
//
for ( int i = 0; i < 2; i++ ) {
string message = "hello my pipe dream\0";
byte[] bRequest = Encoding.Unicode.GetBytes( message );
int cbRequest = bRequest.Length;
pipeClient.Write( bRequest, 0, cbRequest );
MessageBox.Show(
string.Format( "Send {0} bytes to server: \"{1}\"", cbRequest, message.TrimEnd( '\0' ) )
);
}
//
// Receive a response from server.
//
do
{
byte[] bResponse = new byte[1024];
int cbResponse = bResponse.Length, cbRead;
cbRead = pipeClient.Read(bResponse, 0, cbResponse);
// Unicode-encode the received byte array and trim all the
// '\0' characters at the end.
string message = Encoding.Unicode.GetString(bResponse).TrimEnd('\0');
Console.WriteLine("Receive {0} bytes from server: \"{1}\"",
cbRead, message);
}
while (!pipeClient.IsMessageComplete);
}
catch (Exception ex)
{
new ErrorDialog( ex ).ShowDialog();
}
finally
{
// Close the pipe.
if (pipeClient != null)
{
pipeClient.Close();
pipeClient = null;
}
}
}
NamedPipeClientStream pipeClient=null;
尝试
{
//尝试打开由管道名称标识的命名管道。
pipeClient=新名称PipeClientStream(
“,//服务器名称
Constants.PipeName,//唯一的管道名称
PipeDirection.InOut,//该管道是双工的
PipeOptions.None//无其他参数
);
pipeClient.Connect(5000);
MessageBox.Show(
Format(“已连接命名管道({0})”,Constants.PipeName)
);
pipeClient.ReadMode=PipeTransmissionMode.Message;
//
//从客户端向服务器发送请求
//
对于(int i=0;i<2;i++){
string message=“你好,我的白日梦\0”;
byte[]bRequest=Encoding.Unicode.GetBytes(消息);
int cbRequest=bRequest.Length;
pipeClient.Write(bRequest,0,cbRequest);
MessageBox.Show(
Format(“向服务器发送{0}字节:\“{1}\”,cbRequest,message.TrimEnd('\0'))
);
}
//
//从服务器接收响应。
//
做
{
字节[]b响应=新字节[1024];
int cbResponse=b响应长度,cbRead;
cbRead=pipeClient.Read(breresponse,0,cbResponse);
//Unicode编码接收到的字节数组并修剪所有
//结尾有“\0”个字符。
字符串消息=Encoding.Unicode.GetString(breresponse.TrimEnd('\0');
WriteLine(“从服务器接收{0}字节:\“{1}\”,
cbRead,message);
}
而(!pipeClient.IsMessageComplete);
}
捕获(例外情况除外)
{
新建ErrorDialog(ex.ShowDialog();
}
最后
{
//把管子关上。
if(pipeClient!=null)
{
pipeClient.Close();
pipeClient=null;
}
}
}
正如您在上面的“从客户机向服务器发送请求”部分的for循环中所看到的,我正在尝试找出如何向服务器发送多条消息。我看到服务器代码循环执行,直到NativeMethod.ReadFile()方法返回true。我的问题是,在读取第一条消息后,它总是返回true,而忽略第二条消息,因此我的问题是,具体来说,我需要在客户端代码中执行哪些操作,以便此方法返回false,然后它将获得第二条消息。客户端除了发送其所有“消息”之外,没有什么可以做的在一次写入管道中。这是因为,在消息模式下,消息由发送方的写调用完成来分隔,并且服务器代码只显式读取一条消息(在管道消息模式意义上)。见附件和文件: 数据将作为一个文件写入管道 消息流。烟斗处理 每次写入期间写入的字节数 作为消息单元的操作 如果正在读入命名管道 消息模式,下一条消息为 比nN字节存储区长 参数指定,ReadFile返回 FALSE和GetLastError返回 错误\u更多\u数据。剩余的 消息可由后续用户读取 调用ReadFile或 PeekNamedPipefunction 处理多条消息的可能方法有:
- 定义一些更高级别的框架 客户端可以通过它来判断的协议 服务器需要读取多少条消息 在每个消息交换中。然后,客户端将发送一系列消息,例如[帧头:计数=3][message 1][message 2][message 3],或者[message 1][message 2][message 3][framing trailer:不再发送消息]李>
- 一种多线程服务器,其中有
是一个持续的专用线程
从客户端读取消息,
其他操作,如书写
返回到正在处理的客户端的消息
在其他线程上完成李>
- 谢谢你,克里斯,帮我看一下文档。我对你的答案投了赞成票,因为你引用的话让我找到了我想要的答案
原来我只是被服务器代码的“从客户端接收请求”部分中的do/while循环弄糊涂了。也就是说,在我看来,它好像是在从客户端检索多条消息。但事实上,它是在检索单个消息的连续部分。我更新了代码部分如下
至于在客户端对服务器的请求中划分多个“消息”,我可能只使用换行符// Receive a request from client. string message = string.Empty; bool finishRead = false; do { byte[] bRequest = new byte[1024]; int cbRequest = bRequest.Length, cbRead; finishRead = NativeMethod.ReadFile( hNamedPipe, // Handle of the pipe bRequest, // Buffer to receive data cbRequest, // Size of buffer in bytes out cbRead, // Number of bytes read IntPtr.Zero // Not overlapped ); if (!finishRead && Marshal.GetLastWin32Error() != ERROR_MORE_DATA) { throw new Win32Exception(); } // Unicode-encode the received byte array and trim all the // '\0' characters at the end. message += Encoding.Unicode.GetString(bRequest).TrimEnd('\0'); } while (!finishRead); // Repeat loop if ERROR_MORE_DATA Console.WriteLine( "Message received from client: \"{0}\"", message );