7

我一直在研究如何最好地用 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 中的网络编程等),所以这似乎是一个需要一些好的资源的主题。

编辑:

请不要让马克的非常好的评论阻止其他人对此发表评论:)

我想听听其他人关于资源管理的书籍推荐或意见,尤其是在异步使用方面。

4

3 回答 3

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实际上首先是一个奇怪的东西......大多数流都是输入输出。NetworkStream弯曲一些规则并将两个方向填充到一个 API 中;所以这是一个例外......通常所有权会更清楚。此外,许多包装器都有一个标志来确定它们是否应该关闭包装的流。StreamReader没有,但有些有(例如GZipStream,它有一个leaveOpenctor 选项)。如果您不想流动所有权,这是一个选项 - 或使用非关闭流中介 -这里有一个(NonClosingStream或类似的)。

重新书籍;我拿起了一份“C# 中的 TCP/IP 套接字:程序员实用指南”(这里)——足够了,但不是很好。

于 2009-02-01T10:32:50.570 回答
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
}
于 2009-04-02T14:25:04.130 回答
-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)
{
.
.
.
}
于 2009-04-06T07:34:08.650 回答