No se puede asignar la dirección solicitada. ¿Causas posibles?

5 minutos de lectura

avatar de usuario
cerveza

Tengo un programa que consta de un servidor maestro y servidores esclavos distribuidos. Los servidores esclavos envían actualizaciones de estado al servidor, y si el servidor no ha tenido noticias de un esclavo específico en un período fijo, lo marca como inactivo. Esto está sucediendo constantemente.

Al inspeccionar los registros, descubrí que el esclavo solo puede enviar una actualización de estado al servidor, y luego nunca puede enviar otra actualización, siempre fallando en la llamada para conectar () “No se puede asignar la dirección solicitada (99).

Por extraño que parezca, el esclavo puede enviar varias otras actualizaciones al servidor y todas las conexiones se realizan en el mismo puerto. Parece que la causa más común de esta falla es que las conexiones se dejan abiertas, pero tengo problemas para encontrar algo que quede abierto. ¿Hay otras explicaciones posibles?

Para aclarar, así es como me estoy conectando:

struct sockaddr *sa; // parameter
size_t           sa_size; //parameter
int              i = 1;
int              stream;

stream = socket(AF_INET,SOCK_STREAM,0);
setsockopt(stream,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(i));
bindresvport(stream,NULL);
connect(stream,sa,sa_size);

Este código está en una función para obtener una conexión a otro servidor, y una falla en cualquiera de esas 4 llamadas hace que la función falle.

  • He verificado que el puerto y la dirección IP son correctos.

    – cerveza

    3 oct 2011 a las 21:21

avatar de usuario
cerveza

Resulta que el problema realmente era que la dirección estaba ocupada; la ocupación se debió a otros problemas en la forma en que manejamos las comunicaciones de red. Tus aportes me han ayudado a resolver esto. Gracias.

EDITAR: para ser específicos, los problemas en el manejo de las comunicaciones de nuestra red eran que estas actualizaciones de estado se reenviaban constantemente si fallaba la primera. Era solo cuestión de tiempo hasta que tuviéramos todos los esclavos distribuidos tratando de enviar su actualización de estado al mismo tiempo, lo que estaba saturando nuestra red.

  • Me encantaría una elaboración sobre “ocupado” en caso de que sea la causa del mismo error aquí en mi propio código. ¿Quiere decir “el servidor que acepta conexiones tenía una cola demasiado larga de sockets esperando aceptar () para otra conexión a ser permitido en la cola?” ¿U otra circunstancia? ¡Gracias!

    – Brandon Rodas

    7 de marzo de 2013 a las 13:32

  • @BrandonRhodes, nuestro problema fue que tuvimos algunos reintentos sin un algoritmo de retroceso adecuado, por lo que tuvimos cientos o más de intentos de conexión al mismo socket cada segundo. Esta contienda estaba causando nuestro fracaso. La implementación de un algoritmo de retroceso adecuado fue crucial para resolver este problema.

    – cerveza

    7 de marzo de 2013 a las 16:26

¿Quizás SO_REUSEADDR ayude aquí?
http://www.unixguide.net/network/socketfaq/4.5.shtml

  • SO_REUSEADDR está configurado para todas las conexiones.

    – cerveza

    3 oct 2011 a las 21:23

  • aquí hay uno similar: stackoverflow.com/questions/3886506/…

    – dmh2000

    3 oct 2011 a las 22:35

  • @ dmh2000: miré ese ejemplo antes de publicar y no he tenido éxito tratando de analizar esos factores. Me pregunto si solo necesito seguir buscando o si hay algo que no estoy teniendo en cuenta.

    – cerveza

    4 oct 2011 a las 17:10

  • ¿Esa función de la que hablas se ejecuta varias veces? ¿Cierras el socket antes de volver a llamar a connect? ¿Puede explicar la diferencia entre “actualizaciones de estado” y “otras actualizaciones” en su pregunta? Estoy confundido por qué dices “… el esclavo solo puede enviar una actualización de estado…” y luego “… el esclavo puede enviar varias otras actualizaciones…”.

    – Miguel

    4 oct 2011 a las 18:31

  • @Michel: la conexión se cierra inmediatamente después de enviar la actualización y recibir la confirmación de que se recibió. Las ‘otras actualizaciones’ informan principalmente sobre tareas que el servidor le pidió al esclavo que realizara. El esclavo puede ponerse en contacto con el servidor para este tipo de informes, pero no para su actualización de estado. Es desconcertante. Las otras actualizaciones en su mayoría escriben en un socket abierto desde el servidor maestro, y para estas actualizaciones, el esclavo abre la conexión.

    – cerveza

    4 oct 2011 a las 20:48

esto es solo un tiro en la oscuridad: cuando llama primero a connect sin un enlace, el sistema asigna su puerto local, y si tiene varios subprocesos que se conectan y desconectan, posiblemente podría intentar asignar un puerto que ya está en uso. el archivo fuente del kernel inet_connection_sock.c sugiere esta condición. solo como un experimento, intente hacer un enlace a un puerto local primero, asegurándose de que cada enlace/conexión use un número de puerto local diferente.

  • Lo siento, no estaba mirando mi código cuando publiqué eso. Llamo a un enlace antes de conectar. Actualizaré mi pregunta para mostrar mejor lo que estoy haciendo.

    – cerveza

    4 oct 2011 a las 17:12

Bien, mi problema no era el puerto, sino la dirección de enlace. Mi servidor tiene una dirección interna (10.0.0.4) y una dirección externa (52.175.223.XX). Cuando intenté conectarme con:

$sock = @stream_socket_server('tcp://52.175.223.XX:123', $errNo, $errStr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN);

Falló porque el socket local era 10.0.0.4 y no el externo 52.175.223.XX. Puede consultar las interfaces locales disponibles con sudo ifconfig.

sysctl -w net.ipv4.tcp_timestamps=1
sysctl -w net.ipv4.tcp_tw_recycle=1

  • Sin explicación, esta respuesta no tiene ningún valor.

    – Pavel Simerda

    17 de junio de 2016 a las 12:09


  • Sin explicación, esta respuesta no tiene ningún valor.

    – Pavel Simerda

    17 de junio de 2016 a las 12:09


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad