在本机命名管道和 System.IO 命名管道之间发送多条消息
我需要在本机命名管道和 System.IO 命名管道之间发送多条消息。我从 All-In-One Code Framework(IPC 和 RPC)中获取了此通信两端的代码。
服务器:
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);
} 捕获(异常前){ Console.WriteLine("服务器抛出错误:{0}", ex.Message); } 最后 { if (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;
}
}
}
正如您从上面“从客户端向服务器发送请求”部分的 for 循环中看到的,我正在尝试弄清楚如何向服务器发送多条消息。我看到服务器代码循环执行,直到 NativeMethod.ReadFile() 方法返回 true。我的问题是,它总是在读取第一条消息后返回 true,并忽略第二条消息所以我的问题,具体来说,是我需要在客户端代码中做什么,以便此方法返回 false,然后它会得到第二条消息。
I need to send multiple messages between a native named pipe and a System.IO named pipe. I got the code for both ends of this communication from the All-In-One Code Framework (IPC and RPC).
Server:
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);
}
catch (Exception ex) {
Console.WriteLine("The server throws the error: {0}", ex.Message);
}
finally
{
if (hNamedPipe != null)
{
hNamedPipe.Close();
hNamedPipe = null;
}
}
Client:
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;
}
}
}
As you can see from the for loop in the "Send a request from client to server" section above, I'm trying to figure out how to send multiple messages to the server. I see that the server code loops through until the NativeMethod.ReadFile() method returns true. My problem is that it is always returning true after the first message is read, and ignoring the second message So my question, specifically, is what do i need to do in the client code so that this method returns false so then it will go get the second message.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
除了在一次写入中将所有“消息”发送到管道之外,客户端无能为力。这是因为,在消息模式下,消息由发送方完成写入调用来分隔,并且您的服务器代码显式地仅读取一条消息(在管道消息模式意义上)。请参阅 CreateNamedPipe 和 ReadFile API 文档:
处理多个消息的可能方法是:
客户端可以判断的协议
服务器要读取多少条消息
在每次消息交换中。然后,客户端将发送一系列消息,例如 [framing header:count=3][message 1][message 2][message 3],或者 [message 1][message 2][message 3][framing Trailer:没有更多消息了];
是一个连续的专用线程
读取来自客户端的消息,
其他操作,例如写入
消息返回给客户端
在其他线程上完成;
There is nothing the client can do other than to send all its "messages" in a single write to the pipe. This is because, in message mode, the messages are delimited by the completion of write calls at the sender, and your server code explicitly reads just one message (in the pipe message mode sense). See CreateNamedPipe and ReadFile API documentation:
Possible approaches to work with multiple messages are:
protocol by which the client can tell
the server how many messages to read
in each message interchange. The client would then send a series of messages something like [framing header:count=3][message 1][message 2][message 3], or alternatively [message 1][message 2][message 3][framing trailer: no more messages];
is a dedicated thread continuously
reading messages from the client,
other operations like writing
messages back to the client being
done on other threads;
谢谢你,克里斯,给我指出了文档。我对你的答案投了赞成票,因为你引用的内容引导我找到了我正在寻找的答案。
事实证明,我只是对服务器代码的“接收来自客户端的请求”部分中的 do/while 循环感到困惑。也就是说,在我看来它正在从客户端检索多条消息。但事实上,它正在检索单个消息的连续部分。我更新了该代码部分,如下所示。
至于在客户端对服务器的请求中分隔多个“消息”,我可能只使用换行符。
Thank you, Chris, for pointing me to the documentation. I up-voted your answer since the quote you included led me to the answer I was looking for.
Turns out I was just confused by the do/while loop in the server code's "Receive a request from client" section. That is, it looked to me like it was retrieving multiple messages from the client. But in fact, it was retrieving consecutive parts of the single message. I updated that code section as follows.
As for delimiting the multiple "messages" within the client's request to the server, I'll probably just use newline characters.