我一直在研究如何最好地用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非常好的评论阻止其他人对此发表评论:)
我想听听任何人在资源管理方面的建议或意见,特别是在异步使用方面。
答案 0 :(得分:14)
通常,对象应在内部处理多个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选项)。如果您不想流转所有权,这是一个选项 - 或者使用非关闭流中介 - 一个是here(NonClosingStream
或类似的)。
重新预订;我拿了一份“C#中的TCP / IP套接字:程序员实用指南”(here) - 足够但不是很好。
答案 1 :(得分:0)
如果一个对象支持IDisposable,最好将它放在using {}块中,因为dispose方法会自动为你调用。这也减少了您的代码。重要的是要注意使用'using'不处理任何异常。如果你想处理任何错误,你仍然必须这样做。一旦使用块超出范围,您的对象也是如此。
Old Style Code
object obj;
try
{
obj= new object();
//Do something with the object
}
catch
{
//Handle Exception
}
finally
{
if (obj != null)
{
obj.Dispose();
}
}
Newer Style Code
try
{
using (object obj = new object())
{
//Do something with the object
}
catch
{
//Handle Exception
}
答案 2 :(得分:-1)
套接字怎么样? 可以这样做:
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Connect(serverEndPoint, m_NegotiationPort);
.
.
.
serverSocket.Close();
或更好
using (Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
.
.
.
}