2008-09-15 23 views
14

Al usar Net.Sockets.TcpListener, ¿cuál es la mejor manera de manejar conexiones entrantes (.AcceptSocket) en hilos separados?¿Cómo propagar las conexiones entrantes de tcplistener a través de subprocesos en .NET?

La idea es iniciar un nuevo hilo cuando se acepta una nueva conexión entrante, mientras que el tcplistener permanece disponible para otras conexiones entrantes (y para cada nueva conexión entrante se crea un nuevo hilo). Toda la comunicación y la terminación con el cliente que originó la conexión se manejarán en el hilo.

Se agradece el ejemplo C# del código VB.NET.

Respuesta

15

El código que he estado utilizando el siguiente aspecto:

class Server 
{ 
    private AutoResetEvent connectionWaitHandle = new AutoResetEvent(false); 

    public void Start() 
    { 
    TcpListener listener = new TcpListener(IPAddress.Any, 5555); 
    listener.Start(); 

    while(true) 
    { 
     IAsyncResult result = listener.BeginAcceptTcpClient(HandleAsyncConnection, listener); 
     connectionWaitHandle.WaitOne(); // Wait until a client has begun handling an event 
     connectionWaitHandle.Reset(); // Reset wait handle or the loop goes as fast as it can (after first request) 
    } 
    } 


    private void HandleAsyncConnection(IAsyncResult result) 
    { 
    TcpListener listener = (TcpListener)result.AsyncState; 
    TcpClient client = listener.EndAcceptTcpClient(result); 
    connectionWaitHandle.Set(); //Inform the main thread this connection is now handled 

    //... Use your TcpClient here 

    client.Close(); 
    } 
} 
+0

Gracias por el código fuente, voy a codificarlo así. Los hilos nuevos pueden ser costosos, pero como no he escalado más de 5 o 6 conexiones entrantes concurrentes, esto estará bien por ahora. –

+1

Think listener y tcpListener se confundieron en el ejemplo, de lo contrario el código es bueno. Encontrado esto: http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.beginaccepttcpclient.aspx basado en lo que me he apoyado aquí. –

+0

El código actual es altamente peligroso en el contexto de rendimiento lo editaré ... – Beygi

0

Usaría un threadpool, de esta manera no tendrías que iniciar un nuevo hilo cada vez (ya que esto es un poco caro). Tampoco esperaría indefinidamente para más conexiones, ya que los clientes pueden no cerrar sus conexiones. ¿Cómo planea enrutar al cliente al mismo hilo cada vez?

Lo siento, no tengo muestra.

3

Creo que lo hace de la misma manera que cualquier otra operación asincrónica en .NET: llama a la versión BeginXxx del método, en este caso BeginAcceptSocket. Su devolución de llamada se ejecutará en el grupo de subprocesos.

Los subprocesos agrupados generalmente escalan mucho mejor que el subproceso por conexión: una vez que se superan unas pocas decenas de conexiones, el sistema trabaja mucho más duro al cambiar entre subprocesos que al realizar el trabajo real. Además, cada subproceso tiene su propia pila que suele tener un tamaño de 1 MB (aunque depende de los indicadores de enlace) que debe encontrarse en el espacio de direcciones virtuales de 2 GB (en sistemas de 32 bits); en la práctica, esto te limita a menos de 1000 hilos.

No estoy seguro de si el threadpool de .NET lo usa actualmente, pero Windows tiene un objeto kernel llamado I/O Completion Port que ayuda a E/S escalable. Puede asociar subprocesos con este objeto y las solicitudes de E/S (incluida la aceptación de conexiones entrantes) se pueden asociar a él. Cuando finaliza una E/S (por ejemplo, llega una conexión), Windows lanzará un hilo en espera, pero solo si el número de subprocesos actualmente ejecutables (no bloqueados por algún otro motivo) es inferior al límite de escalabilidad configurado para el puerto de finalización. Por lo general, establecería esto en un pequeño múltiplo de la cantidad de núcleos.

2

Me gustaría sugerir un enfoque diferente: Mi sugerencia utiliza solo dos hilos. * un hilo comprueba conexiones entrantes. * Cuando se abre una nueva conexión, esta información se escribe en una estructura de datos compartida que contiene todas las conexiones abiertas actuales. * El segundo subproceso enumera esa estructura de datos y para cada conexión abierta recibe los datos enviados y envía respuestas.

Esta solución es más escalable a nivel de hilo y si se implementa de forma correcta debería tener un mejor rendimiento que abrir un hilo nuevo por conexión abierta.

+0

Esta voy a recordar, aunque realmente me gustaría responder a cada conexión entrante inmediatamente. Gracias por la sugerencia. –

+0

hola! @Dror Helper, su sugerencia parece buena. Entonces, ¿cómo implementar una estrategia de eficiencia? ¿Puedes compartir, tienes algún fragmento de código? – bashkan

Cuestiones relacionadas