2009-02-01 8 views
7

Я проводил много исследований о том, как лучше всего писать «правильный» сетевой код на C#.Сетевое программирование на 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 оператора в вложенных операциях using?

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

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

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

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

EDIT:

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

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

ответ

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 (или аналогичный).

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

+0

Спасибо за обратную связь. Это во многом то, что я подозревал. Согласен, NetworkStream - это странность. Я не уверен, было бы менее проблематично создавать отдельные потоки чтения и записи, но это то, что есть. Спасибо за рекомендацию книги. –

+0

Кроме того, я не видел реализацию NonClosingStream на указанном вами сайте. –

+0

Он есть - MiscUtil.IO.NonClosingStreamWrapper –

0

Если объект поддерживает IDisposable, лучше всего разместить его в блоке {}, потому что метод 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 
} 
-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) 
{ 
. 
. 
. 
} 
Смежные вопросы