2012-07-05 7 views
5

Nuestra aplicación utiliza un uso de socket sin bloqueo con operaciones de conexión y selección (código c). El código pusedo es la siguiente:tcp connect falla al azar bajo alta carga

unsigned int ConnectToServer(struct sockaddr_in *pSelfAddr,struct sockaddr_in *pDestAddr) 
    { 
     int sktConnect = -1; 
     sktConnect = socket(AF_INET,SOCK_STREAM,0); 
     if(sktConnect == INVALID_SOCKET) 
      return -1; 
     fcntl(sktConnect,F_SETFL,fcntl(sktConnect,F_GETFL) | O_NONBLOCK); 
     if(pSelfAddr != 0) 
     { 
      if(bind(sktConnect,(const struct sockaddr*)(void *)pSelfAddr,sizeof(*pSelfAddr)) != 0) 
      { 
       closesocket(sktConnect); 
       return -1; 
      } 
     } 
     errno = 0; 
     int nRc = connect(sktConnect,(const struct sockaddr*)(void *)pDestAddr, sizeof(*pDestAddr)); 
     if(nrC != -1) 
     { 
      return sktConnect; 
     } 
     if(errno != EINPROGRESS) 
     { 
      int savedError = errno; 
      closesocket(sktConnect); 
      return -1; 
     } 
     fd_set scanSet; 
     FD_ZERO(&scanSet); 
     FD_SET(sktConnect,&scanSet); 
     struct timeval waitTime; 
     waitTime.tv_sec = 2; 
     waitTime.tv_usec = 0; 
     int tmp; 
     tmp = select(sktConnect +1, (fd_set*)0, &scanSet, (fd_set*)0,&waitTime); 
     if(tmp == -1 || !FD_ISSET(sktConnect,&scanSet)) 
     { 
      int savedErrorNo = errno; 
      writeLog("Connect %s failed after select, cause %d, error %s",inet_ntoa(pDestAddr->sin_addr),savedErrorNo,strerror(savedErrorNo)); 
      closesocket(sktConnect); 
      return -1; 
     } 
    .  .  .  .  .} 

hay 80 tales nodos y la aplicación se conecta a todos su par en la moda round-robin. En esta fase, algunos de los nodos no son capaces de conectarse (API - conectar + seleccione) con el número de error 115.

En los siguientes registros (de la salida de tcpdump) para el escenario de éxito, podemos ver (SYN, SYN + ACK, ACK), pero no hay ninguna entrada de incluso SYN para el nodo con errores en los registros de tcpdump.

Los registros tcpdump son:

387937 2012-07-05 07:45:30.646514 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [SYN] Seq=0 Ack=0 Win=5792 Len=0 MSS=1460 TSV=1414450402 TSER=912308224 WS=8 
387947 2012-07-05 07:45:30.780762 10.137.165.136  10.18.92.173   TCP  8441 > 33728 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=912309754 TSER=1414450402 WS=8 
387948 2012-07-05 07:45:30.780773 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [ACK] Seq=1 Ack=1 Win=5888 Len=0 TSV=1414450435 TSER=912309754 
All the above three events indicate the success information. 
387949 2012-07-05 07:45:30.782652 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [PSH, ACK] Seq=1 Ack=1 Win=5888 Len=320 TSV=1414450436 TSER=912309754 
387967 2012-07-05 07:45:30.915615 10.137.165.136  10.18.92.173   TCP  8441 > 33728 [ACK] Seq=1 Ack=321 Win=6912 Len=0 TSV=912309788 TSER=1414450436 
388011 2012-07-05 07:45:31.362712 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [PSH, ACK] Seq=321 Ack=1 Win=5888 Len=320 TSV=1414450581 TSER=912309788 
388055 2012-07-05 07:45:31.495558 10.137.165.136  10.18.92.173   TCP  8441 > 33728 [ACK] Seq=1 Ack=641 Win=7936 Len=0 TSV=912309933 TSER=1414450581 
388080 2012-07-05 07:45:31.702336 10.137.165.136  10.18.92.173   TCP  8441 > 33728 [PSH, ACK] Seq=1 Ack=641 Win=7936 Len=712 TSV=912309985 TSER=1414450581 
388081 2012-07-05 07:45:31.702350 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [ACK] Seq=641 Ack=713 Win=7424 Len=0 TSV=1414450666 TSER=912309985 
388142 2012-07-05 07:45:32.185612 10.137.165.136  10.18.92.173   TCP  8441 > 33728 [PSH, ACK] Seq=713 Ack=641 Win=7936 Len=320 TSV=912310106 TSER=1414450666 
388143 2012-07-05 07:45:32.185629 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [ACK] Seq=641 Ack=1033 Win=8704 Len=0 TSV=1414450786 TSER=912310106 
388169 2012-07-05 07:45:32.362622 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [PSH, ACK] Seq=641 Ack=1033 Win=8704 Len=320 TSV=1414450831 TSER=912310106 
388212 2012-07-05 07:45:32.494833 10.137.165.136  10.18.92.173   TCP  8441 > 33728 [ACK] Seq=1033 Ack=961 Win=9216 Len=0 TSV=912310183 TSER=1414450831 
388219 2012-07-05 07:45:32.501613 10.137.165.136  10.18.92.173   TCP  8441 > 33728 [PSH, ACK] Seq=1033 Ack=961 Win=9216 Len=356 TSV=912310185 TSER=1414450831 
388220 2012-07-05 07:45:32.501624 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [ACK] Seq=961 Ack=1389 Win=10240 Len=0 TSV=1414450865 TSER=912310185 

registros de la aplicación error informando sobre connect (es decir api - Conectar + seleccione)

[5258: 2012-07-05 07:45:30]Connect [10.137.165.136 <- 10.18.92.173] success. 
[5258: 2012-07-05 07:45:32]Connect 10.137.165.137 fail after select, cause:115, error Operation now in progress. Check whether remote machine exist and the network is normal or not. 
[5258: 2012-07-05 07:45:32]Connect to server([10.137.165.137 <- 10.18.92.173], port=8441) Failed! 

registros de éxito que corresponden a primeras 3 entradas de tcpdump. Y el fracaso de registro donde no hay ningún evento en el tcpdump

Mi pregunta es: Cuando el cliente inicia “conectar” api para el caso fallido, no soy capaz de ver cualquier evento en el tcpdump en el lado del cliente (incluso SYN inicial). ¿Cuál puede ser la razón de esta aleatoriedad?

+0

cuando sale 'tcpdump' ¿ve algún valor distinto de cero para' paquetes abandonados por kernel' o 'paquetes eliminados por la interfaz'? –

Respuesta

2

Usted ha golpeado EINPROGRESS. De la página del manual connect:

El zócalo no se bloquea y la conexión no puede completarse inmediatamente. Es posible seleccionar (2) o sondear (2) para completarlo seleccionando el zócalo para escribir. Después de seleccionar (2) indica capacidad de escritura, use getsockopt (2) para leer la opción SO_ERROR en el nivel SOL_SOCKET para determinar si connect() se completó correctamente (SO_ERROR es cero) o sin éxito (SO_ERROR es uno de los códigos de error habituales enumerados aquí, explicando el motivo de la falla).

Esto es decir que EINPROGRESS es un indicador de que el núcleo no es capaz de completar la conexión ahora, a pesar de que hay puertos locales disponibles y las entradas de la caché de enrutamiento. Parece que esto ocurre cuando el estado del socket aún no ha cambiado a "ESTABLISHED". Simplemente espere nuevamente en el socket en select, pero luego llame al getsockopt para ver si su connect se ha completado.

En cuanto a por qué, el socket pasa al estado SYN_SENT durante la conexión, pero el paquete aún puede estar en la cola de salida y aún no ha llegado al búfer del dispositivo de red.

+0

¿Hay algún parámetro de kernel (es decir, la capa de pila TCP/IP) que, cuando esté sintonizado, pueda manejar este tipo de incoherencias aportando más solidez en el sistema. Básicamente, ¿cómo podemos garantizar la estabilidad sobre el rendimiento en tales casos? –

+1

@kumar_m_kiran: No si quiere conectarse de forma asíncrona. Cada dispositivo llegará a un límite en cuanto a la cantidad de operaciones que puede hacer por segundo. Si no quiere lidiar con esta condición, 'connect' en modo de bloqueo, y luego haga que el socket no sea bloqueante después del éxito. – jxh

0

Después de select() devuelve, en realidad no está obteniendo el estado actual del socket: está viendo un valor obsoleto en errno (sobrante de la llamada connect()). Lo más probable es que su select() simplemente vuelva después del tiempo de espera.

Debe llamar al getsockopt(sktConnect, SOL_SOCKET, SO_ERROR, &err, ...) para obtener el estado real del socket después de select() devuelve.