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);

明らかに、このコードは非常に不安定になります。それで、tcpClient を使用するコードを見てきましたが、これは良さそうです。しかし、NetworkStream にもクリーンアップが必要なリソースはありませんか? StreamReader/Writer はどうですか?

ネストされた using ステートメントで 4 つのステートメントすべてをラップする必要がありますか?

もしそうなら、処分する時が来たらどうなりますか?StreamWriter はストリームを閉じず、その結果ソケットを閉じませんか? では、StreamReader、NetworkStream、TcpClient がそれぞれ破棄されるとどうなるでしょうか?

これは別の質問を引き起こします。StreamReader と StreamWriter の両方が同じストリームで構成されている場合、誰がそれを所有しますか? 二人とも自分が所有していると思って、破壊しようとしているのではありませんか? それとも、フレームワークはストリームが既に破棄されていることを認識しており、黙って無視しているのでしょうか?

using ステートメントはチェーンの最後のステートメントにのみ必要なように思えますが、GetStream() で例外がスローされた場合はどうなるでしょうか? その場合、ソケットが適切にクリーンアップされるとは思わないので、これが起こらないようにするために冗長な使用が必要なようです。

例外処理とリソース管理に関する章を含む、.net とできれば c# を使用したネットワーク プログラミングに関する優れた最近の本を知っている人はいますか? または、オンラインの良い記事はありますか?私が見つけることができるすべての本は .NET 1.1 時代 (Microsoft .NET Framework のネットワーク プログラミング、.NET でのネットワーク プログラミングなど) のものであるため、これは適切なリソースが必要なトピックのようです。

編集:

マークの非常に良いコメントが、他の誰かがこれについてコメントするのを止めさせないでください:)

特に非同期の使用に関して、リソース管理に関する本の推奨事項や意見を誰か他の人に聞いてみたいです。

4

3 に答える 3

14

通常、オブジェクトは内部で複数のDispose()呼び出しを処理し、メイン コードを 1 回だけ実行する必要があります。そのため、ストリームが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出力のいずれかです。いくつかのルールを曲げて、2 つの方向性を 1 つの API にシムします。したがって、これは例外です...通常、所有権はより明確になります。さらに、多くのラッパーには、ラップされたストリームを閉じる必要があるかどうかを判断するためのフラグがあります。しませんが、そうするものもあります ( ctor オプションを持つなど)。所有権をフローしたくない場合は、これがオプションです-または非終了ストリーム仲介を使用します-1つはhere(または同様のもの)です。NetworkStreamStreamReaderGZipStreamleaveOpenNonClosingStream

再本; 「C# での TCP/IP ソケット: プログラマー向けの実践ガイド」(こちら) のコピーを入手しました。

于 2009-02-01T10:32:50.570 に答える
0

オブジェクトが IDisposable をサポートしている場合は、dispose メソッドが自動的に呼び出されるため、それを using {} ブロックに配置することをお勧めします。これにより、ユーザー側のコードも少なくなります。「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
}
于 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 に答える