TcpClient.Connect dice "Un intento de conexión falló porque la parte conectada..."

Tengo una aplicación Visual Studio 2008 C# .NET 3.5 ejecutándose en Windows XP SP3 x86. En mi aplicación, tengo un controlador de eventos. OnSendTask que puede ser llamado por múltiples subprocesos simultáneamente. Abre una conexión TCP a un host remoto y envía/recibe datos.

Por ejemplo:

/// <summary>
/// prevent us from exceeding the maximum number of half-open TCP 
/// connections in Windows XP.
/// </summary>
private System.Threading.Semaphore tcp_connection_lock_ = 
    new System.Threading.Semaphore(10, 10);

public event EventHandler<SendTaskEventArgs> SendTask;

private void OnSendTask(object sender, SendTaskEventArgs args)
{
    try
    {
        tcp_connection_lock_.WaitOne();
        using (TcpClient recipient = new TcpClient())
        {
            // error here!
            recipient.Connect(args.IPAddress, args.Port);
            using (NetworkStream stream = recipient.GetStream())
            {
                // read/write data
            }
    }
    catch
    {
        // write exceptions to the logfile
    }
    finally
    {
        tcp_connection_lock_.Release();
    }
}

void SendTasks(int tasks_to_send)
{
    using (ManualResetEvent done_event = new ManualResetEvent(false))
    {
        int countdown = tasks_to_send;
        for (int i = 0; i < tasks_to_send; ++i)
        {
            ThreadPool.QueueUserWorkItem((o) =>
            {
                SendTaskEventArgs args = new SendTaskEventArgs(/*...*/);

                EventHandler<SendTaskEventArgs> evt = SendTask;
                if (evt != null)
                    evt(this, e);

                if (Interlocked.Decrement(ref countdown) == 0)
                    done_event.Set();
            }, i);
        }
        done_event.WaitOne();
    }
}

Desafortunadamente, ocasionalmente veo este error:

System.Net.Sockets.SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 192.168.0.16:59596
at System.Net.Sockets.TcpClient.Connect(String hostname, Int32 port)

Algunos puntos de información:

  • Si envío una tarea a 40 controles remotos, veré esta respuesta de alrededor de 6.
  • Un seguimiento de Wireshark no muestra ningún intento de iniciar una conexión TCP desde la PC al control remoto.
  • Puedo hacer ping al control remoto desde la PC y obtener buenas respuestas consistentes.
  • Los controles remotos están todos en el mismo conmutador y subred que la PC que ejecuta esta aplicación. No hay redes sofisticadas en el camino.

¿Alguien puede sugerir qué puede estar causando este error o cómo puedo solucionarlo?

Muchas Gracias

preguntado el 22 de mayo de 12 a las 15:05

Si envía una tarea a 1 remoto, ¿siempre tiene éxito? El mensaje de error hace que parezca que la ubicación remota está causando el problema. -

Nunca lo he visto fallar al enviar a 1 control remoto. Estoy de acuerdo con la forma en que suena el mensaje de error, pero el punto 2 sugiere que la PC ni siquiera está intentando establecer la conexión. -

Es posible que deba proporcionar más código. ¿Cómo se llama OnSendTask? ¿Dónde llamas a tcp_connection_lock_.Release()? -

@EricDahlvang - Ups. ver actualización. OnSendTask se llama a través de un delegado de eventos que puede ser invocado por muchos subprocesos simultáneamente. Si 40 controles remotos reciben la tarea, 40 subprocesos simultáneos pueden alcanzar ese evento. Pero solo 10 pueden golpear el TcpClient.Connect llamada debido al semáforo. -

¿Sigue recibiendo este error si ejecuta la aplicación en una máquina que no sea Windows XP SP3 x86? -

1 Respuestas

No estoy seguro de todos los detalles detrás de las conexiones TCP semiabiertas máximas, pero creo que NO es específico de las conexiones de la aplicación, sino de todo el sistema. ¿Está seguro de que cuando ocurre este error no hay otras aplicaciones en el sistema que estén creando conexiones TCP?

Configuraría un reintento cada vez que ocurra un error. Algo como:

private const int MaxRetries = 10;
private void OnSendTask(object sender, SendTaskEventArgs args)
{
    bool retry = false;
    try
    {
        tcp_connection_lock_.WaitOne();
        using (TcpClient recipient = new TcpClient())
        {
            // error here!
            recipient.Connect(args.IPAddress, args.Port);
            using (NetworkStream stream = recipient.GetStream())
            {
                // read/write data
            }
        }
    }
    catch (SocketException ex)
    {
        if(args.RetryCount < MaxRetries)
        {
            retry = true;
            args.RetryCount++;
        }
        else
        {
            // write exceptions to the logfile
        }
    }
    finally
    {
        tcp_connection_lock_.Release();
    }

    if(retry)
    {
        Thread.Sleep(1);
        OnSendTask(sender, args);
    }
}

contestado el 22 de mayo de 12 a las 22:05

Hice un poco más de análisis y resultó que el problema era que los controles remotos no siempre respondían a la solicitud ARP enviada antes que TCP SYN. (¿pila de TCP con errores?) Su solución soluciona el problema de manera efectiva porque ahora estamos enviando más solicitudes ARP, por lo que obtiene el punto de respuesta. :) - PaulH

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.