Python socket select error Filedescriptor fuera de rango en la solución seleccionada

Tabla de contenido

Encuentra la razón

Explica el fenómeno

Solución


Esta noche, un compañero de clase me informó stpclient un error en el paquete de protocolo de red interno  , de la siguiente manera:

File "/data/apps/column-web/eggs/snow-3.2.1-py2.7.egg/snow/client.py", line 146, in service
  stp_response = self._client.call(stp_request.argv)
File "/data/apps/column-web/eggs/snow-3.2.1-py2.7.egg/snow/client.py", line 51, in call
  self.send_request(request)
File "/data/apps/column-web/eggs/stpclient2-0.0.15-py2.7.egg/stpclient2/client.py", line 221, in send_request
  self._timeout)
ValueError: filedescriptor out of range in select()

Esta excepción ha ocurrido varias veces, así que decidí averiguar la causa.

Encuentra la razón

Primero, la versión ampliamente circulada es que cuando  select el fd número de escucha  sobre 1024, cuando habrá la excepción, analicé, esta excepción se lanza stp client, porque esta versión del cliente es la que escribí Sí, así que sé claramente que Es imposible tener más de 1024 fd al mismo tiempo  selectEntonces surge la pregunta ¿Cuál es la razón?

En este momento, el problema que se puede pensar es que debe haber un problema con la versión en el mercado, así que primero eché un vistazo y las instrucciones en la llamada al sistema de selección son las siguientes:

Un fd_set es un búfer de tamaño fijo. La ejecución de FD_CLR () o FD_SET () con un valor de fd que es negativo o es igual o mayor que FD_SETSIZE dará como resultado un comportamiento indefinido. Además, POSIX requiere que fd sea un descriptor de archivo válido.

Está escrito en las notas seleccionadas:

fd_set es un búfer de tamaño fijo. Cuando el conjunto fd es negativo o excede FD_SETSIZE, se producirá un comportamiento indefinido. POSIX requiere que fd sea un fd legal

Desde este punto de vista, hay una diferencia con los rumores en el mercado. No es que haya un problema si el fd que se monitorea al mismo tiempo excede FD_SETSIZE, sino que habrá un problema si el tamaño de fd excede FD_SETSIZE. FD_SETSIZE se define en select.h. Es 1024 (en la máquina problemática), por lo que debería ser un problema si el tamaño de fd excede 1024.

/usr/include/linux/posix_types.h

#undef __FD_SETSIZE
#define __FD_SETSIZE 1024

Sin embargo, hasta este momento, no sé cómo se lanzó la excepción que vimos.

ValueError: descriptor de archivo fuera de rango en select ()

Obviamente, esta es una excepción lanzada por Python, y la llamada al sistema solo dice que producirá un comportamiento indefinido.

En este momento, siguiendo el socket módulo de Python  y encontramos el select código fuente de Python del  módulo, encontramos las siguientes líneas:

Módulos / selectmodule.c

#if defined(_MSC_VER)
    max = 0; /* not used for Win32 */
#else /* !_MSC_VER */
    if (!_PyIsSelectable_fd(v)) {
        PyErr_SetString(PyExc_ValueError,
            "filedescriptor out of range in select()");
        goto finally;
    }
    if (v >= max)
        max = v;
#endif /* _MSC_VER */

Luego descubrimos que cuando la llamada  _PyIsSelectable_fd devuelve falso, se generará la excepción anterior. A continuación, veamos  _PyIsSelectable_fd la implementación:

Incluir / fileobject.h

#ifdef HAVE_SELECT
    #define _PyIsSelectable_fd(FD) (((FD) >= 0) && ((FD) < FD_SETSIZE))
#else
    #define _PyIsSelectable_fd(FD) (1)
#endif /* HAVE_SELECT */

Debido a que POSIX solo estipula que el fd pasado en la llamada al sistema de selección debe ser legal, entonces la persona que llama debe detectar fd, por lo que en Python, cuando fd es negativo o excede FD_SERSIZE, se considerará ilegal y arrojará ValueError

Así que ahora el problema está claro. Debe ser porque cuando se ejecutó la llamada select, se pasó un fd mayor que 1024 o menor que 0, lo que llevó a la excepción anterior . La siguiente pregunta es averiguar por qué fd mayor que 1024 aparece.

Explica el fenómeno

Los alumnos de la arquitectura básica aprendieron que hemos ajustado el número máximo de procesos que se pueden abrir. El número máximo de fd que se pueden abrir para cada proceso en el supervisor es 655360, por lo que es muy posible que fd supere 1024.
Esto La excepción es Aparece en la máquina web, porque algunos servicios de zona utilizan enlaces cortos, por lo que el número de fd propiedad de un solo proceso es muy alto, superando los 1024.

Hasta ahora, este problema puede considerarse una explicación razonable, ya que debido al uso extensivo de enlaces cortos, el número de fd en un solo proceso ha aumentado, superando el límite de 1024, y se produjo la excepción inicial.

Solución

  • Debido a que este valor está definido en el kernel, si la solución actual permanece sin cambios, para resolver este problema, debe volver a compilar el kernel de Linux y aumentar este valor.
  • Modifique el cliente stpclient para usar epoll en lugar del select anterior. La razón para usar select en ese momento era que la cantidad de fd era pequeña y no había problemas de rendimiento. Al mismo tiempo, select también se puede admitir en otras plataformas .

 

 

Supongo que te gusta

Origin blog.csdn.net/whatday/article/details/113771166
Recomendado
Clasificación