2009-02-01 17 views
7

He estado investigando mucho sobre la mejor manera de escribir el código de red "correcto" en C#.C# programación de red y uso de recursos

He visto una serie de ejemplos usando la instrucción "using" de C#, y creo que este es un buen enfoque, sin embargo he visto un uso inconsistente de él con varias expresiones.

Por ejemplo, supongamos que tengo un poco de código como este:

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

Obviamente, este código va a ser muy escamosa. Entonces, he visto un código que pone el uso en el tcpClient, lo cual parece bueno. Sin embargo, ¿NetworkStream tampoco tiene recursos que necesiten limpiarse? ¿Qué pasa con StreamReader/Writer?

¿Debo completar las 4 instrucciones en declaraciones anidadas usando?

Y en caso afirmativo, ¿qué sucede cuando ha llegado el momento de desechar? ¿StreamWriter no cerrará la transmisión y, en consecuencia, el socket? Entonces, ¿qué sucede cuando StreamReader, luego NetworkStream, luego TcpClient cada uno pasa por sus disposiciones?

Lo que plantea otra pregunta. Con StreamReader y StreamWriter compuestos de la misma secuencia, ¿a quién pertenece? ¿No creen los dos que son los dueños y, por lo tanto, tratarán de destruirlo? ¿O el marco sabe que la secuencia ya ha sido destruida y simplemente la ignora silenciosamente?

Parece que la instrucción using solo es necesaria para la última instrucción de la cadena, pero ¿qué ocurre si se lanza una excepción en GetStream()? No creo que limpiaría adecuadamente el socket entonces, por lo que parece redundante, los usos son necesarios para garantizar que esto no suceda.

¿Alguien sabe de algunos buenos libros recientes sobre programación de redes con .net y, preferiblemente, C# que incluyen capítulos sobre manejo de excepciones y gestión de recursos? O tal vez algunos buenos artículos en línea? Todos los libros que puedo encontrar pertenecen a la era .NET 1.1 (Programación de redes para Microsoft .NET Framework, Programación de redes en .NET, etc.), por lo que parece un tema que necesita algunos buenos recursos.

EDIT:

Por favor, no deje muy buen comentario de Marc detener cualquier otra persona de hacer comentarios sobre esto :)

me gustaría oír a nadie vigilara recomendaciones de libros u opiniones sobre la gestión de recursos, especialmente con respecto al uso asincrónico.

Respuesta

14

En general, los objetos deben manejar internamente múltiples llamadas Dispose(), y solo hacer el código principal una vez; por lo que una secuencia de obtención de Dispose() d varias veces no suele ser un problema. Personalmente, usaría un montón de using allí; tenga en cuenta que no es necesario para sangrar/nido, aunque (a menos diferentes niveles tienen diferentes tiempos de vida):

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

Como usted dice, esto garantiza que si ocurre un error durante la inicialización, todo está siendo limpiado correctamente. Esto también garantiza que cada nivel tenga la oportunidad (en el orden correcto) de manejar correctamente cualquier información almacenada en el búfer, etc.

Re ownership; NetworkStream es realmente una rareza en el primer lugar ... la mayoría de las secuencias son entrada xor salida.NetworkStream dobla algunas reglas y calza dos direcciones en una API; entonces esta es una excepción ... normalmente la propiedad sería más clara. Además, muchos contenedores tienen un indicador para determinar si deben cerrar el flujo envuelto. StreamReader no, pero algunos sí (como GZipStream, que tiene una opción de ctor leaveOpen). Si no desea transferir la propiedad, esta es una opción, o utilice un intermediario de flujo no cerrado, uno es here (NonClosingStream o similar).

Re books; Recogí una copia de "Sockets TCP/IP en C#: Guía práctica para programadores" (here) - adecuada, pero no excelente.

+0

Gracias por los comentarios. Esto es en gran medida lo que sospechaba. Estoy de acuerdo, NetworkStream es una rareza. No estoy seguro de si hubiera sido menos problemático crear secuencias de lectura y escritura separadas, pero es lo que es. Gracias por la recomendación del libro. –

+0

Además, no vi una implementación NonClosingStream en el sitio que mencionaste. –

+0

Está allí - MiscUtil.IO.NonClosingStreamWrapper –

0

Si un objeto admite IDisposable, lo mejor es ponerlo en un bloque {} usando porque el método de eliminación se llama automáticamente. Esto también hace que haya menos código de su parte. Es importante tener en cuenta que usar 'usar' no maneja ninguna excepción. Aún debes hacer eso si quieres manejar cualquier error. Una vez que el bloque de uso está fuera del alcance, también lo hace su objeto.

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

¿Qué pasa con sockets? ¿Está bien hacer:

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

o mejores

using (Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) 
{ 
. 
. 
. 
} 
Cuestiones relacionadas