【发布时间】:2016-09-25 14:54:27
【问题描述】:
我有一个使用命名管道的简单服务器-客户端应用程序。我在服务器中使用 StreamWriter,在客户端中使用 StreamReader。只要客户端进程不从管道读取(即不从 StreamReader 读取,包装管道),StreamWriter 就不会被释放。我想知道为什么。
详情如下:
这是服务器:
using System;
using System.IO;
using System.IO.Pipes;
class PipeServer
{
static void Main()
{
using (NamedPipeServerStream pipeServer =
new NamedPipeServerStream("testpipe"))
{
Console.Write("Waiting for client connection...");
pipeServer.WaitForConnection();
Console.WriteLine("Client connected.");
try
{
StreamWriter sw = new StreamWriter(pipeServer);
try
{
sw.WriteLine("hello client!");
}
finally
{
sw.Dispose();
}
// Would print only after the client finished sleeping
// and reading from its StreamReader
Console.WriteLine("StreamWriter is now closed");
}
catch (IOException e)
{
Console.WriteLine("ERROR: {0}", e.Message);
}
}
}
}
这是客户:
using System;
using System.IO;
using System.IO.Pipes;
using System.Threading;
class PipeClient
{
static void Main(string[] args)
{
using (NamedPipeClientStream pipeClient =
new NamedPipeClientStream(".", "testpipe"))
{
Console.Write("Attempting to connect to pipe...");
pipeClient.Connect();
Console.WriteLine("Connected to pipe.");
using (StreamReader sr = new StreamReader(pipeClient))
{
Thread.Sleep(100000);
string temp = sr.ReadLine();
if (temp != null)
{
Console.WriteLine("Received from server: {0}", temp);
}
}
}
}
}
注意客户端中的Thread.Sleep(100000);:我添加它是为了确保只要客户端进程处于休眠状态,StreamWriter 就不会被释放到服务器中,并且服务器不会执行Console.WriteLine("StreamWriter is now closed");。为什么?
编辑:
我切断了之前的信息,我认为这些信息可能无关紧要。 我还想补充一点——多亏了 cmets 中的 Scott——我观察到这种行为发生了相反的情况:如果服务器写入,然后休眠,客户端(尝试)使用它的 StreamReader 读取——读取是'在服务器唤醒之前不会发生。
第二次编辑:
我在第一次编辑中谈到的其他方式的行为无关紧要,这是一个flush 问题。
我试着给它更多的试验,并得出结论斯科特是对的——如果不排干管道就不能处理。那为什么?这似乎也与 StreamWriter 假定它拥有流的事实相矛盾,除非另有说明(参见 here)。
以下是上面代码中添加的细节:
在服务器程序中,try-finally 现在看起来像这样:
try
{
sw.AutoFlush = true;
sw.WriteLine("hello client!");
Thread.Sleep(10000);
sw.WriteLine("hello again, client!");
}
finally
{
sw.Dispose(); // awaits while client is sleeping
}
Console.WriteLine("StreamWriter is now closed");
在客户端程序中,using 块现在如下所示:
using (StreamReader sr = new StreamReader(pipeClient))
{
string temp = sr.ReadLine();
Console.WriteLine("blah"); // prints while server sleeps
Console.WriteLine("Received from server: {0}", temp); // prints while server is sleeping
Thread.Sleep(10000);
temp = sr.ReadLine();
Console.WriteLine("Received from server: {0}", temp);
}
【问题讨论】:
-
如果将服务器更改为
new NamedPipeServerStream("testpipe", PipeDirection.Out),将客户端更改为new NamedPipeClientStream(".", "testpipe", PipeDirection.In),行为是否会发生变化?另外,如果你在读取之后放置了一个Thread.Sleep(100000);,但仍然在客户端的using内,会发生什么情况,流在退出使用之前是否仍然在服务器上保持打开状态? -
@ScottChamberlain,完全没有变化,而改变
Sleep的位置是我所期望的:服务器进程继续,打印"StreamWriter is now closed"并返回,而客户端休眠。跨度> -
也许在缓冲区耗尽之前它不会让你关闭。如果你这样做
Server write -> Client read -> Server write -> Server dispose -> Client read会发生什么? -
您的期望是什么?它工作得很好,不是吗?我确实发现了另一件事:我尝试了
Server write -> Server long sleeping -> Client read- 但客户端直到服务器醒来才读取。 -
我认为它会一直挂到客户端的第二次读取,这表明它会阻止 dispose 直到缓冲区为空。老实说,你不是我的专业知识,我不知道是什么原因造成的,也不知道如何预防。