C#网络编程及资源使用

发布于 2024-07-13 05:05:01 字数 1146 浏览 5 评论 0原文

我一直在研究如何最好地用 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 怎么样?

我是否需要将所有 4 个语句包装在嵌套的 using 语句中?

如果是这样,当需要处理时会发生什么? StreamWriter 不会关闭流并因此关闭套接字吗? 那么当 StreamReader、NetworkStream、TcpClient 分别进行处理时会发生什么?

这就提出了另一个问题。 StreamReader 和 StreamWriter 都由同一个流组成,那么谁拥有它? 难道他们不都认为自己拥有它,因此都会试图摧毁它吗? 或者框架是否知道流已经被销毁并且只是默默地忽略它?

看起来似乎只有链中的最后一个语句才需要 using 语句,但是如果在 GetStream() 中抛出异常会发生什么? 我不认为它会正确地清理套接字,所以看来有必要进行冗余使用以确保这种情况不会发生。

有谁知道最近有哪些关于使用 .net 进行网络编程的好书,最好是 C#,其中包括有关异常处理和资源管理的章节? 或者网上有什么好的文章吗? 我能找到的所有书籍都来自 .NET 1.1 时代(Microsoft .NET Framework 的网络编程、.NET 中的网络编程等),因此这似乎是一个需要一些好的资源的主题。

编辑:

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

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

I've been doing a lot of research on how best to write "correct" network code in C#.

I've seen a number of examples using the "using" statement of C#, and I think this is a good approach, however i've seen inconsistent use of it with various expressions.

For instance, suppose I have some code like this:

TcpClient tcpClient = new TcpClient("url.com", 80);
NetworkStream tcpStream = tcpClient.GetStream();
StreamReader tcpReader = new StreamReader(tcpStream);
StreamWriter tcpWriter = new StreamWriter(tcpStream);

Obviously, this code is going to be very flaky. So, i've seen some code that puts the using on the tcpClient, which seems good. However, doesn't NetworkStream also have resources that need cleaning up? What about StreamReader/Writer?

Do I need to wrap all 4 statements in nested using statements?

And if so, what happens when the time has come to dispose? Won't StreamWriter close the stream and consequently the socket? Then what happens when StreamReader, then NetworkStream, then TcpClient each go through their disposals?

Which brings up another question. WIth both StreamReader and StreamWriter composed of the same stream, who owns it? Don't they both think they own it, and will thus both try to destroy it? Or does the framework know that the stream has already been destroyed and just silently ignore it?

It almost seems like the using statement is only necessary for the last statement in the chain, but then what happens if an exception is thrown in GetStream()? I don't think it would properly clean up the socket then, so it seems redundant usings are necessary to ensure this doesn't happen.

Does anyone know of any good, recent books on network programming with .net, and prefeably c# that include chapters on exception handling and resource management? Or maybe any good articles online? All the books I can find are from the .NET 1.1 era (Network Programming for the Microsoft .NET Framework, Network Programming in.NET, etc..), so this seems like a topic that needs some good resources.

EDIT:

Please, don't let Marc's very good comment stop anyone else from commenting on this :)

I'd like to hear anyone elses book recommendations or opinions on resource management, especially in regard to asynchronous usage.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

尝蛊 2024-07-20 05:05:01

一般来说,对象应该在内部处理多个 Dispose() 调用,并且只执行一次主要代码; 因此,多次使用 Dispose() 的流通常不会出现问题。 就我个人而言,我会在那里使用大量 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 套接字:程序员实用指南” (这里) - 足够,但不是很好。

Generally, objects should internally handle multiple Dispose() calls, and only do the main code once; so a stream getting Dispose()d multiple times is not usually a problem. Personally, I would use lots of using there; note that you don't need to indent/nest, though (unless different levels have different life-times):

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))
{
   ...
}

As you say, this ensures that if an error happens during initialization, everything is still cleaned up correctly. This also ensures that every level gets a chance (in the right order) to deal correctly with any buffered data, etc.

Re ownership; NetworkStream is actually an oddity in the first place... most streams are either input xor output. NetworkStream bends a few rules and shims two directions into one API; so this is an exception... normally the ownership would be clearer. Additionally, many wrappers have a flag to determine whether they should close the wrapped stream. StreamReader doesn't, but some do (such as GZipStream, which has a leaveOpen ctor option). If you don't want to flow ownership, this is an option - or use a non-closing stream intermediary - one is here (NonClosingStream or similar).

Re books; I picked up a copy of "TCP/IP Sockets in C#: Practical Guide for Programmers" (here) - adequate, but not great.

小…楫夜泊 2024-07-20 05:05:01

如果对象支持 IDisposable,最好将其放入 using {} 块中,因为会自动为您调用 dispose 方法。 这也可以减少您的代码。 重要的是要注意使用“using”不处理任何异常。 如果您想处理任何错误,您仍然必须这样做。 一旦 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
}

If an object supports IDisposable, it's best to put it in a using {} block because the dispose method gets called automatically for you. This also makes for less code on your part. It is important to note the using a 'using' doesn't handle any exceptions. YOu still have to do that if you want to handle any errors. Once the using block goes out of scope, so does your object.

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
}
花期渐远 2024-07-20 05:05:01

套接字呢?
可以这样做吗:

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)
{
.
.
.
}

What about sockets?
Is it OK to do:

serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Connect(serverEndPoint, m_NegotiationPort);
.
.
.
serverSocket.Close();

or better

using (Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
.
.
.
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文