2009-03-24 17 views
8

Escribo un par de cliente-servidor en C++ usando sockets de Linux. Quiero que el servidor escuche una conexión, y mientras un cliente esté conectado, el servidor debería rechazar a cualquier otro cliente que intente conectarse.¿Cómo creo un servidor TCP que aceptará solo una conexión a la vez?

Intenté implementar esto estableciendo el parámetro de retraso en la función listen a 0 y a 1 y ninguno de esos valores parece funcionar. El primer cliente se conecta como se espera, pero los clientes subsiguientes simplemente bloquean mientras termina el primer cliente. Lo que es realmente confuso para mí es que no bloquean la conexión al servidor, bloquean en la primera lectura.

Utilicé the code here para comenzar a escribir mi cliente y servidor. ¿Alguien sabe lo que necesito cambiar para que el servidor acepte solo una conexión de cliente y descarte cualquier intento de conexión posterior?

Respuesta

7

Cuando acepta una conexión, se crea un nuevo socket. El anterior todavía se usa para escuchar conexiones futuras.

Dado que solo desea permitir 1 conexión a la vez, puede aceptar las conexiones y luego cerrar la nueva toma aceptada si detecta que ya está procesando otra.

¿Hay una diferencia neta que está buscando en comparación con cerrar la nueva toma aceptada inmediatamente después de la aceptación? El cliente sabrá tan pronto como intente utilizar su socket (o de inmediato si ya está esperando en el servidor con una llamada de lectura) con un último error de: servidor cerró activamente la conexión.

+0

Estoy modificando mi código para ver si puedo hacer esto. Me pondré en contacto contigo ... –

+0

+1 exactamente lo que estaba por sugerir. –

+0

¡Parece ser una buena forma de hacerlo! ¡Tks! – LeoPucciBr

4

Simplemente no lo haga fork() después de accept().

Este pseudo-C-código solo aceptará un cliente a la vez.

while(1) { 
    listen() 
    accept() 
    *do something with the connection* 
    close() 
} 
+1

No tenedor(). El ejemplo es un servidor de eco simple que solo procesa la solicitud. –

3

Puede cerrar el zócalo original que está escuchando las conexiones después de aceptar la primera conexión. No obstante, no sé si la clase de socket que está utilizando le permitirá hacerlo.

+0

Esa es una idea, pero quiero que acepte nuevas conexiones después de que termine el primer procesamiento. –

+0

@Bill, luego vuelva a abrir el socket cuando esté listo para aceptar conexiones nuevamente. –

3

Parece que tiene que implementarlo manualmente. Deje que un cliente se conecte, luego envíe un mensaje de desconexión desde el servidor al cliente si ya hay otro cliente conectado. Si el cliente recibe este mensaje, déjelo desconectarse.

0

Si tiene control sobre los clientes, puede hacer que los sockets no bloqueen. En este caso, devolverán el mensaje de error EINPROGRESS.

Todavía estoy buscando cómo cambiar el socket para que no sea bloqueante. Si alguien sabe cómo hacerlo, siéntase libre de editar la respuesta.

0

deja que la toma de audio muera después de aceptar e iniciar una nueva conexión. Luego, cuando se realiza esa conexión, haga que escuche una nueva toma de audición.

0

Es posible que tenga la opción de la toma TCP_DEFER_ACCEPT configuró en su socket de escucha:

 
TCP_DEFER_ACCEPT (since Linux 2.4) 
    Allows a listener to be awakened only when data arrives on the socket. 
    Takes an integer value (seconds), this can bound the maximum number of 
    attempts TCP will make to complete the connection. This option should 
    not be used in code intended to be portable. 

quiero suponer que conduciría al efecto que ha descrito, que el cliente que se conecta no bloquea en la connect, pero en el siguiente read.No estoy exactamente seguro de lo que es el ajuste de las opciones por defecto y para lo que se debe establecer para desactivar este comportamiento, pero probablemente un valor de cero vale la pena intentarlo:

int opt = 0; 
setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &opt, sizeof(opt)); 
+0

También estoy buscando permitir solo una conexión a la vez. Intenté usar 'setsockopt' como se menciona arriba: ' int opt ​​= 0; setsockopt (calcetín, IPPROTO_TCP, TCP_DEFER_ACCEPT, y optar, sizeof (opt)); ' pero no funcionó. Así que configuré 'opt' en 1 y lo intenté y aún así no funcionó. ¿Hay algún control que tengamos que hacer en el 'sizeof (opt)' aquí? –

1

Puesto que usted quiere sólo para permitir 1 conexión a la vez, puede aceptar las conexiones y luego cerrar el nuevo socket aceptado si detecta que ya está procesando otro.

Creo que debe ser el zócalo de escucha que se cierre. Cuando se establece la primera conexión, cierra el socket de escucha original. Y después de eso no se pueden establecer más conexiones.

Después de que termine la primera conexión, puede crear un nuevo socket para escuchar nuevamente.

0

Por lo que veo, no es posible escuchar exactamente una conexión.

Tcp implica un apretón de manos de 3 vías. Después de recibir el primer paquete syn, el kernel pone esa "conexión" en una cola de espera, responde con un syn/ack y espera el ack final. Después de recibir esto, mueve la conexión de la cola de espera a la cola de aceptación, donde la aplicación puede recogerla mediante la llamada accept(). (Para obtener detalles, consulte here.)

En Linux, el argumento del retraso acumulado solo limita el tamaño de la cola de aceptación. pero el kernel seguirá haciendo la magia de handshake de 3 vías. El cliente recibe syn/ack y responde con el ack final y llama a la conexión establecida.

Sus únicas opciones son, ya sea apagar la toma de audición tan pronto como haya aceptado la primera conexión. (Sin embargo, esto puede dar como resultado que ya esté disponible otra conexión). O acepta activamente otras conexiones y las cierra inmediatamente para notificar al cliente.

La última opción que tiene es la que ya está utilizando: deje que el servidor ponga sus conexiones en cola y las procese una tras otra. Sus clientes bloquearán en ese caso.

Cuestiones relacionadas