Pregunta

Estamos escribiendo un cliente y un servidor para hacer (lo que creía que era) las comunicaciones de red bastante simples. Mulitple clientes se conectan al servidor que se supone a continuación, enviar los datos de nuevo a todos los demás clientes.

El servidor sólo se sienta en un bucle de bloqueo select de espera para el tráfico, y cuando se trata, envía los datos a los otros clientes. Esto parece funcionar muy bien.

El problema es el cliente. En respuesta a una lectura, que a veces se quiere hacer una reseña.

Sin embargo, he encontrado que si uso:

 rv = select(fdmax + 1, &master_list, NULL, NULL, NULL);

Mi código se bloqueará hasta que haya nuevos datos a leer. Pero a veces (de forma asíncrona, desde otro hilo) Voy a tener nuevos datos para escribir en el hilo de la comunicación en red. Por lo tanto, quiero que mi selección para despertar periódicamente y me permiten comprobar si hay datos para escribir, como:

if (select(....) != -1)
{
  if (FD_SET(sockfd, &master_list))
     // handle data or disconnect
  else
     // look for data to write and write() / send() those.
}

He intentado establecer el modo de selección a (o tiempos de espera ridículamente corta) con la Encuesta:

// master list contains the sockfd from the getaddrinfo/socket/connect seq
struct timeval t;
memset(&t, 0, sizeof t);
rv = select(fdmax + 1, &master_list, NULL, NULL, &t);

, pero han encontrado que a continuación, a continuación, el cliente nunca tiene ningún dato de entrada.

También intentado fijar el zócalo de fd sea no bloqueante, como:

fcntl(sockfd, F_SETFL, O_NONBLOCK);

pero eso no resuelve el problema:

  1. si mi cliente no tiene select() struct timeval, la lectura de las obras de datos, pero nunca se desbloquea para que lo vea para los datos de escritura.
  2. si mi select() cliente tiene un timeval conseguirlo sondee, entonces nunca indica que hay datos de entrada para leer, y mi aplicación se congela pensando que no hay conexión de red hecho (a pesar del hecho de que todas las otras llamadas a funciones han tenido éxito )

Cualquier punteros en absoluto en cuanto a lo que podría estar haciendo mal? ¿No es posible hacer de lectura y escritura en el mismo socket (No puedo creer que esto es cierto).

(EDIT: La respuesta correcta, y lo que recordaba en el servidor, pero no en el cliente, es tener una segunda fd_set, y copiar master_list antes de cada llamada a select ():

// declare and FD_ZERO read_fds:
// put sockfd in master_list

while (1)
{
   read_fds = master_list;
   select(...);

   if (FD_ISSET(read_fds))
     ....
   else
     // sleep or otherwise don't hog cpu resources
}

)

¿Fue útil?

Solución

Todo se ve bien, a excepción de la línea donde se hace if (FD_SET(sockfd, &master_list)). Tengo una estructura de código muy similar y solía FD_ISSET. Se supone que debes probar si la lista está establecido, no que vuelva a hacerlo. Aparte de eso, no veo nada más.

Editar. Además, tengo lo siguiente para el tiempo de espera:

timeval listening_timeout;
listening_timeout.tv_sec = timeout_in_seconds;
listening_timeout.tv_usec = 0;

tal vez hay un problema si se establece en 0 (como parece estar haciendo?)

Edit2. Recordé me encontré con un problema extraño cuando yo no estaba limpiando la lectura establecido después del selecto abandonar, así como antes de entrar de nuevo. Tenía que hacer algo como:

FD_ZERO(&sockfd);
FD_SET(sockfd, &rd);

antes de que yo estaba entrando select. No puedo recordar por qué sin embargo.

Otros consejos

Me parece recordar un truco sobre cómo crear y compartir un descriptor de fichero de lectura / escritura entre el hilo de la red y el hilo principal que se agrega a los descriptores en la selección de llamada. Este fd tiene un byte escrito para ella por el hilo principal cuando tiene algo que enviar. La escritura se despierta hilo de red de la selección de llamada y el hilo de la red se agarra los datos de una memoria compartida y lo escribe en la red y luego volver a dormir en la selección.

Lo siento si eso es un poco vaga y carente de código ... y mi memoria puede ser incorrecta .. para que otros usuarios pueden tener que guiará aún más.

No veo nada malo en su código, así que debería funcionar. Si no puede conseguir que funcione, una manera de evitar que sería la creación de una tubería para ser utilizado por el hilo de la lectura y el hilo que prepara las cosas para la escritura y la lectura añadir extremo de la tubería para el conjunto de select. Entonces, cuando el otro hilo ha preparado para escribir los datos, sólo se envía algo en el tubo, el hilo de la lectura se despertó de la select, y entonces puede hacer la escritura. Dependiendo de la frecuencia con la que hay datos para leer o escribir, esto también podría ser más eficiente.

2 hilos deben ser capaces de trabajar con la misma toma a la vez, por lo que su hilo principal debe ser capaz de escribir a un cliente mientras el otro duerme en selecto de espera de datos entrantes. Por supuesto, esto asume que ambos hilos tienen acceso a la lista de clientes.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top