C# 异步命名管道永远等待
C# async named pipes wait for ever
我正在使用异步管道,有时服务器和客户端都在等待对方,什么都不做。这是我的代码:
服务器:
var buffer = new byte[BufferSize];
using (var server = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
{
// Wait for client.
Logger.Trace("Waiting for connection ...");
var asyncResult = server.BeginWaitForConnection(a => { }, null);
while (true)
{
await Task.Delay(MillisecondsDelay);
if (asyncResult.IsCompleted) break;
}
server.EndWaitForConnection(asyncResult);
Logger.Trace("Connection established.");
using (var sr = new StreamReader(server))
using (var sw = new StreamWriter(server))
{
// Send work.
Logger.Trace("Sending operations...");
await sw.WriteAsync(JsonConvert.SerializeObject(data));
await sw.FlushAsync();
server.WaitForPipeDrain();
// Wait for response.
var bytesRead = await server.ReadAsync(buffer, 0, buffer.Length);
.....
客户:
// Read data from the pipe...
using (var client = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous))
{
Logger.Trace("Connecting to server...");
client.Connect();
Logger.Trace("Connected.");
using (var sr = new StreamReader(client))
using (var sw = new StreamWriter(client))
{
// Read operations.
Logger.Trace("Waiting operations...");
var text = await sr.ReadToEndAsync();
.....
我拍的日志是这些:
2016-10-04 16:09:51.5375 => (TRACE) | MyController.Execute : Waiting for connection ... |
2016-10-04 16:09:52.0706 => (TRACE) | MyController+<Execute>d__5.MoveNext : Connection established. |
2016-10-04 16:09:52.0706 => (TRACE) | MyController+<Execute>d__5.MoveNext : Sending operations... |
和:
2016-10-04 16:09:51.8486 => (TRACE) | EXE.Program.Process : Connecting to server... |
2016-10-04 16:09:51.8696 => (TRACE) | EXE.Program.Process : Connected. |
2016-10-04 16:09:51.8696 => (TRACE) | EXE.Program.Process : Waiting operations... |
然后什么都没有!
之后似乎陷入了僵局。
我想我应该在服务器或客户端每次写入后使用 WaitForPipeDrain()
,我这样做了,但这似乎没有帮助。
客户端读取操作从不returns。
有什么想法吗?
我认为问题出在 ReadToEndAsync
方法中。 StreamReader
无法判断传输结束。例如,它可能是一个慢速连接并且只发送了一半的数据。通常在这些情况下,您需要想出自己的 "protocol" 来发送数据。有多种方法,这里有几个:
等待终止符。很多次我看到 ASCII 字符 4 用于此,因为它表示 "EOT" (end of transmission)。但是,这是基于这样的假设,即您的消息不仅仅是可能包含该字符的二进制数据流。您可以将终止符设为一个序列,一些几乎从不的字符会出现在流中。
在消息前加上您要发送的数据的长度。例如,前4个字节总是的长度,抓住它之后,你现在知道要读多少了。
我正在使用异步管道,有时服务器和客户端都在等待对方,什么都不做。这是我的代码:
服务器:
var buffer = new byte[BufferSize];
using (var server = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
{
// Wait for client.
Logger.Trace("Waiting for connection ...");
var asyncResult = server.BeginWaitForConnection(a => { }, null);
while (true)
{
await Task.Delay(MillisecondsDelay);
if (asyncResult.IsCompleted) break;
}
server.EndWaitForConnection(asyncResult);
Logger.Trace("Connection established.");
using (var sr = new StreamReader(server))
using (var sw = new StreamWriter(server))
{
// Send work.
Logger.Trace("Sending operations...");
await sw.WriteAsync(JsonConvert.SerializeObject(data));
await sw.FlushAsync();
server.WaitForPipeDrain();
// Wait for response.
var bytesRead = await server.ReadAsync(buffer, 0, buffer.Length);
.....
客户:
// Read data from the pipe...
using (var client = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous))
{
Logger.Trace("Connecting to server...");
client.Connect();
Logger.Trace("Connected.");
using (var sr = new StreamReader(client))
using (var sw = new StreamWriter(client))
{
// Read operations.
Logger.Trace("Waiting operations...");
var text = await sr.ReadToEndAsync();
.....
我拍的日志是这些:
2016-10-04 16:09:51.5375 => (TRACE) | MyController.Execute : Waiting for connection ... |
2016-10-04 16:09:52.0706 => (TRACE) | MyController+<Execute>d__5.MoveNext : Connection established. |
2016-10-04 16:09:52.0706 => (TRACE) | MyController+<Execute>d__5.MoveNext : Sending operations... |
和:
2016-10-04 16:09:51.8486 => (TRACE) | EXE.Program.Process : Connecting to server... |
2016-10-04 16:09:51.8696 => (TRACE) | EXE.Program.Process : Connected. |
2016-10-04 16:09:51.8696 => (TRACE) | EXE.Program.Process : Waiting operations... |
然后什么都没有!
之后似乎陷入了僵局。
我想我应该在服务器或客户端每次写入后使用 WaitForPipeDrain()
,我这样做了,但这似乎没有帮助。
客户端读取操作从不returns。
有什么想法吗?
我认为问题出在 ReadToEndAsync
方法中。 StreamReader
无法判断传输结束。例如,它可能是一个慢速连接并且只发送了一半的数据。通常在这些情况下,您需要想出自己的 "protocol" 来发送数据。有多种方法,这里有几个:
等待终止符。很多次我看到 ASCII 字符 4 用于此,因为它表示 "EOT" (end of transmission)。但是,这是基于这样的假设,即您的消息不仅仅是可能包含该字符的二进制数据流。您可以将终止符设为一个序列,一些几乎从不的字符会出现在流中。
在消息前加上您要发送的数据的长度。例如,前4个字节总是的长度,抓住它之后,你现在知道要读多少了。