我一直在研究如何最好地用C#编写"正确"的网络代码.
我已经看过使用C#的"using"语句的一些例子,我认为这是一个很好的方法,但是我已经看到它与各种表达式的不一致使用.
例如,假设我有一些这样的代码:
TcpClient tcpClient = new TcpClient("url.com", 80); NetworkStream tcpStream = tcpClient.GetStream(); StreamReader tcpReader = new StreamReader(tcpStream); StreamWriter tcpWriter = new StreamWriter(tcpStream);
显然,这段代码非常不稳定.所以,我已经看到一些代码将使用放在tcpClient上,这似乎很好.但是,NetworkStream是否还有需要清理的资源?那么StreamReader/Writer呢?
我是否需要在嵌套的using语句中包装所有4个语句?
如果是这样,当处理时间时会发生什么?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中; 所以这是一个例外...通常所有权会更清楚.此外,许多包装器都有一个标志来确定它们是否应该关闭包装的流.StreamReader
没有,但有些人(例如GZipStream
,有leaveOpen
ctor选项).如果您不想流所有权,这是一个选项 - 或使用非关闭流中介 - 一个在这里(NonClosingStream
或类似).
重新上书; 我拿了一份"C#中的TCP/IP套接字:程序员实用指南"(这里) - 足够,但不是很好.