命名管道服务器读取超时
使用 C# NamedPipeServerStream 时,如果客户端不发送任何消息结束模式(例如服务器使用 ReadLine() 读取时的 \r\n),NamedPipeServerStream Read 方法将永远等待,并且不会出现 Abort() 或 Interupt() 方法在该线程上工作。
自:
1) NamedPipeServerStream 不支持 Stream.ReadTimeout
2) Abort() 或 Interupt() 在线程上不起作用
3) NamedPipeServerStream.Disconnect() 下线工作
目前尚不清楚,如何设置 NamedPipeServerStream 读取操作的超时?
让我介绍一个例子。我们的 IPC 规范要求交换以 \0 结尾的字符串。客户端发送消息,服务器处理该消息并“必须”发送响应。 如果客户端最终没有发送 \0 (客户端不是我们的,所以我们不能保证其工作的正确性),Read 方法将永远等待,客户端(因为我们不控制它)可能会永远等待也有回应。
接下来是一个简化的实现示例:
public void RestartServer()
{
_pipeServerThread.Interrupt(); //doesn't affect Read wait
_pipeServerThread.Abort(); //doesn't affect Read wait
}
private void PipeServerRun(object o) //runs on _pipeServerThread
{
_pipeServer = new NamedPipeServerStream(_pipeName, InOut, 100,
PipeTransmissionMode.Message, PipeOptions.WriteThrough);
//_pipeServer.ReadTimeout = 100; //System.InvalidOperationException: Timeouts are not supporte d on this stream.
// Wait for a client to connect
while (true)
{
_pipeServer.WaitForConnection();
string request = ReadPipeString();
//... process request, send response and disconnect
}
}
/// <summary>
/// Read a \0 terminated string from the pipe
/// </summary>
private string ReadPipeString()
{
StringBuilder builder = new StringBuilder();
var streamReader = new StreamReader(_pipeServer);
while (true)
{
//read next byte
char[] chars = new char[1];
streamReader.Read(chars, 0, 1); // <- This will wait forever if no \0 and no more data from client
if (chars[0] == '\0') return builder.ToString();
builder.Append(chars[0]);
}
}
那么如何设置NamedPipeServerStream读取操作的超时呢?
When using C# NamedPipeServerStream, in case a client doesn't send any message-end-pattern (like \r\n when server reads with ReadLine()) NamedPipeServerStream Read methods will wait forever and no Abort() or Interupt() methods will work on that thread.
Since:
1) Stream.ReadTimeout not supported for NamedPipeServerStream
2) Abort() or Interupt() doesn't work on thread
3) NamedPipeServerStream.Disconnect() nether work
It is unclear, how to setup timeout on NamedPipeServerStream read operations?
Let me introduce an example. The specification of IPC we have require an exchange of \0-terminated strings. A client sends message, the server processes the message and as 'a must' sends a response.
If the client doesn't send \0 in the end (client is not ours so we can't guarantee correctness of its working), the Read method will wait forever and client (since we don't control it) may wait forever for a response too.
Next is a simplified example of an implementation:
public void RestartServer()
{
_pipeServerThread.Interrupt(); //doesn't affect Read wait
_pipeServerThread.Abort(); //doesn't affect Read wait
}
private void PipeServerRun(object o) //runs on _pipeServerThread
{
_pipeServer = new NamedPipeServerStream(_pipeName, InOut, 100,
PipeTransmissionMode.Message, PipeOptions.WriteThrough);
//_pipeServer.ReadTimeout = 100; //System.InvalidOperationException: Timeouts are not supporte d on this stream.
// Wait for a client to connect
while (true)
{
_pipeServer.WaitForConnection();
string request = ReadPipeString();
//... process request, send response and disconnect
}
}
/// <summary>
/// Read a \0 terminated string from the pipe
/// </summary>
private string ReadPipeString()
{
StringBuilder builder = new StringBuilder();
var streamReader = new StreamReader(_pipeServer);
while (true)
{
//read next byte
char[] chars = new char[1];
streamReader.Read(chars, 0, 1); // <- This will wait forever if no \0 and no more data from client
if (chars[0] == '\0') return builder.ToString();
builder.Append(chars[0]);
}
}
So how to set timeout on NamedPipeServerStream read operations?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
由于您在消息模式下运行管道,因此您应该首先将整个消息读入
byte[]
缓冲区或内存流,然后决定它是否有效并对其进行解码。管道消息有一定的长度。它无法显式检索,但当您从消息模式管道读取时它会显示。如果消息中仍有未读字节,则 Win32ReadFile
失败并返回ERROR_MORE_DATA
,然后返回TRUE
以指示消息已结束。此后,对 ReadFile 的调用将阻塞,直到有新消息可用。 StreamReader 自然不知道这些并且会阻塞您的线程。更新:要实现超时,请使用异步 I/O (
Stream.BeginRead
)。 StreamReader 不直接支持此功能。如果您绝对必须使用它,请编写一个包装器流,它将根据底层流上的BeginRead
实现Read
并支持超时、取消等。Since you are running the pipe in message mode, you should first read the whole message into a
byte[]
buffer or a memory stream and then decide whether it's valid and decode it. Pipe messages have a definite length. It cannot be retrieved explicitly, but it shows up when you are reading from a message-mode pipe. Win32ReadFile
fails withERROR_MORE_DATA
if there still are unread bytes in the message, then it returnsTRUE
to indicate that the message is over. After this, a call toReadFile
will block until a new message is available.StreamReader
naturally doesn't know any of this and blocks your thread.Update: to implement timeouts, use asynchronous I/O (
Stream.BeginRead
).StreamReader
does not support this directly. If you absolutely must use it, write a wrapper stream which will implementRead
in terms ofBeginRead
on the underlying stream and support timeouts, cancellation etc.尝试将 NamedPipeServerStream.ReadMode 和/或 .TransmissionMode 设置为 Byte。
无论这些如何,您都应该将可用的 BeginRead / EndRead 方法与 NamedPipeServerStream 一起使用。
这样你就可以自己实现超时逻辑了。
Try setting NamedPipeServerStream.ReadMode and/or .TransmissionMode to Byte.
Regardless of these you should use the available BeginRead / EndRead methods with NamedPipeServerStream.
This way you can implement the timeout logic yourself.