C # сетевое программирование и использование ресурсов - PullRequest
7 голосов
/ 01 февраля 2009

Я провел много исследований о том, как лучше написать "правильный" сетевой код на C #.

Я видел несколько примеров, использующих оператор using в C #, и я думаю, что это хороший подход, однако я видел его непоследовательное использование с различными выражениями.

Например, предположим, у меня есть такой код:

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 оператора во вложенные операторы?

И если так, что происходит, когда пришло время распоряжаться? Не закроет ли StreamWriter поток и, следовательно, сокет? Что происходит, когда StreamReader, затем NetworkStream, затем TcpClient каждый проходит свою утилизацию?

Что поднимает другой вопрос. Имеет ли StreamReader и StreamWriter один и тот же поток, кому он принадлежит? Разве они оба не думают, что владеют им, и, таким образом, оба попытаются уничтожить его? Или фреймворк знает, что поток уже уничтожен, и просто молча игнорирует его?

Кажется, что оператор using необходим только для последнего оператора в цепочке, но что произойдет, если в GetStream () будет сгенерировано исключение? Я не думаю, что тогда он будет должным образом очищать сокет, так что кажется, что избыточное использование необходимо, чтобы этого не произошло.

Кто-нибудь знает о каких-нибудь хороших, недавних книгах по сетевому программированию с использованием .net и предпочтительно c #, которые включают главы по обработке исключений и управлению ресурсами? Или, может быть, какие-нибудь хорошие статьи онлайн? Все книги, которые я могу найти, относятся к эпохе .NET 1.1 (Сетевое программирование для Microsoft .NET Framework, Сетевое программирование на .NET и т. Д.), Поэтому эта тема, похоже, требует хороших ресурсов.

EDIT:

Пожалуйста, не позволяйте очень хорошим комментариям Марка помешать кому-либо еще комментировать это:)

Я хотел бы услышать, как кто-нибудь еще издает рекомендации или мнения по управлению ресурсами, особенно в отношении асинхронного использования.

Ответы [ 3 ]

14 голосов
/ 01 февраля 2009

Обычно объекты должны обрабатывать несколько вызовов 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))
{
   ...
}

Как вы говорите, это гарантирует, что если во время инициализации произойдет ошибка, все будет по-прежнему корректно очищено. Это также гарантирует, что каждый уровень получает возможность (в правильном порядке) правильно обрабатывать любые буферизованные данные и т. Д.

Re владение; Во-первых, NetworkStream на самом деле странность ... большинство потоков либо input xor output. NetworkStream сгибает несколько правил и объединяет два направления в один API; так что это исключение ... обычно владение было бы яснее. Кроме того, у многих упаковщиков есть флаг, чтобы определить, должны ли они закрыть упакованный поток. StreamReader нет, но некоторые делают (например, GZipStream, который имеет опцию leaveOpen ctor). Если вы не хотите владеть потоком, это вариант - или использовать посредник без закрытия потока - один из них здесь (NonClosingStream или аналогичный).

Re книги; Я взял копию «Сокеты TCP / IP в C #: Практическое руководство для программистов» ( здесь ) - адекватно, но не отлично.

0 голосов
/ 06 апреля 2009

А как насчет сокетов? Можно ли это сделать:

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)
{
.
.
.
}
0 голосов
/ 02 апреля 2009

Если объект поддерживает IDisposable, лучше всего поместить его в блок using {}, потому что метод dispose автоматически вызывается для вас. Это также делает меньше кода с вашей стороны. Важно отметить, что использование «использование» не обрабатывает никаких исключений. Вы все равно должны это сделать, если хотите устранить ошибки. Как только блок использования выходит из области видимости, ваш объект тоже.

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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...