gpt4 book ai didi

c# - 在 native 命名管道和 System.IO 命名管道之间发送多条消息

转载 作者:太空宇宙 更新时间:2023-11-03 14:24:18 26 4
gpt4 key购买 nike

我需要在 native 命名管道和 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);

} catch (异常前){ Console.WriteLine("服务器抛出错误:{0}", ex.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;
}
}
}

正如您从上面“从客户端向服务器发送请求”部分的 for 循环中看到的那样,我正在尝试弄清楚如何向服务器发送多条消息。我看到服务器代码循环执行,直到 NativeMethod.ReadFile() 方法返回 true。我的问题是它总是在读取第一条消息后返回 true,而忽略第二条消息 所以我的问题,具体来说,是我需要在客户端代码中做什么,以便此方法返回 false,然后它就会去获取第二条消息。

最佳答案

客户端除了将其所有“消息”一次写入管道外,无能为力。这是因为,在消息模式下,消息由发送方完成的写调用分隔,并且您的服务器代码明确地只读取一条消息(在管道消息模式意义上)。参见 CreateNamedPipeReadFile API文档:

Data is written to the pipe as a stream of messages. The pipe treats the bytes written during each write operation as a message unit.

If a named pipe is being read in message mode and the next message is longer than the nNumberOfBytesToRead parameter specifies, ReadFile returns FALSE and GetLastError returns ERROR_MORE_DATA. The remainder of the message can be read by a subsequent call to the ReadFile or PeekNamedPipefunction.

处理多条消息的可能方法是:

  • 定义一些更高级别的框架客户端可以告诉的协议(protocol)服务器要读取多少条消息在每个消息交换中。然后,客户端将发送一系列消息,例如 [framing header:count=3][message 1][message 2][message 3],或者 [message 1][message 2][message 3][framing trailer:没有更多消息];
  • 一个多线程服务器,其中有是连续的专用线程读取来自客户端的消息,其他操作,如写作消息返回给客户端在其他线程上完成;

关于c# - 在 native 命名管道和 System.IO 命名管道之间发送多条消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4480527/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com