我一直在研究如何最好地用 C# 编写“正确”的网络代码。
我见过许多使用 C# 的“using”语句的示例,我认为这是一种很好的方法,但是我发现它与各种表达式的用法不一致。
例如,假设我有这样的代码:
TcpClient tcpClient = new TcpClient("url.com", 80);
NetworkStream tcpStream = tcpClient.GetStream();
StreamReader tcpReader = new StreamReader(tcpStream);
StreamWriter tcpWriter = new StreamWriter(tcpStream);
显然,这段代码会非常不稳定。所以,我看到了一些将 using 放在 tcpClient 上的代码,这看起来不错。但是,NetworkStream 不是也有需要清理的资源吗? StreamReader/Writer 呢?
我是否需要将所有 4 个语句包装在嵌套的 using 语句中?
如果是这样,当到了处置的时候会发生什么? StreamWriter 不会关闭流并因此关闭套接字吗?那么,当 StreamReader、NetworkStream、TcpClient 各自完成它们的处置时会发生什么?
这又引出了另一个问题。 StreamReader 和 StreamWriter 由同一个流组成,谁拥有它?难道他们不都认为自己拥有它,因此都会试图摧毁它吗?还是框架知道流已经被销毁而只是静静地忽略它?
似乎 using 语句只对链中的最后一个语句是必需的,但是如果在 GetStream() 中抛出异常会发生什么?我不认为它会在那时正确清理套接字,因此似乎有必要进行冗余使用以确保不会发生这种情况。
有谁知道最近有什么关于使用 .net 进行网络编程的好书,最好是 c#,其中包括关于异常处理和资源管理的章节?或者网上有什么好的文章?我能找到的所有书籍都是 .NET 1.1 时代的(Microsoft .NET Framework 的网络编程、.NET 中的网络编程等),因此这似乎是一个需要一些好的资源的主题。
编辑:
请不要让 Marc 的非常好的评论阻止其他人对此发表评论:)
我想听听其他人对资源管理的书籍推荐或意见,尤其是在异步使用方面。
最佳答案
通常,对象应该在内部处理多个Dispose()
调用,并且只执行一次主要代码;所以流多次获取 Dispose()
d 通常不是问题。就个人而言,我会在那里使用大量的 using
;请注意,您不需要缩进/嵌套(除非不同级别具有不同的生命周期):
using(TcpClient tcpClient = new TcpClient("url.com", 80))
using(NetworkStream tcpStream = tcpClient.GetStream())
using(StreamReader tcpReader = new StreamReader(tcpStream))
using(StreamWriter tcpWriter = new StreamWriter(tcpStream))
{
...
}
如您所说,这可确保如果在初始化期间发生错误,所有内容仍会正确清理。这也确保每个级别都有机会(以正确的顺序)正确处理任何缓冲数据等。
重新拥有; NetworkStream
实际上首先是一个奇怪的地方......大多数流都是或者 输入xor 输出。 NetworkStream
改变了一些规则并将两个方向填充到一个 API 中;所以这是一个异常(exception)......通常所有权会更清楚。此外,许多包装器都有一个标志来确定它们是否应该关闭包装的流。 StreamReader
没有,但有些有(例如 GZipStream
,它有一个 leaveOpen
ctor 选项)。如果您不想流动所有权,这是一个选项 - 或者使用非关闭流中介 - 一个是 here (NonClosingStream
或类似的)。
再读;我拿起了一份“C# 中的 TCP/IP 套接字:程序员实用指南”( here ) - 足够,但不是很好。
关于C#网络编程与资源使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/500551/