¿Cómo funciona select() en c?

Iniciado por mester, 22 Noviembre 2015, 18:30 PM

0 Miembros y 1 Visitante están viendo este tema.

mester

Hola.
Estoy utilizando la función select() para hacer un servidor de chat pero, no sé que problemas tengo jeje. Espero vuestra ayuda.
Ignorad que el código no esté dividido en funciones.
No quiero que me terminéis el programa, solo quiero que me digais, qué problemas tiene. Compilar compila, pero cuando se conectan dos hosts, el segundo no envía mensajes, o cuando se conecta éste, no sucede lo que debe suceder.
Gracias.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<fcntl.h>
#include<arpa/inet.h>
#define PUERTO 3317
//PROBLEMA:
//Cuando se va un host deja un espacio libre que hay que rellenar
void usage(char *arg){
printf("%s <puerto>\n",arg);
}
int main(int argc, char **argv){
pid_t id;
fd_set desc;
int c,l,j;
int host=0;
int clilong;
int socket_servidor;
int socket_cliente[25];
char *buffer=calloc(220,sizeof(char));
struct sockaddr_in servidor;
struct sockaddr_in cliente[25];
socket_servidor=socket(AF_INET,SOCK_STREAM,0);
servidor.sin_family = AF_INET;
if(argc>1){
int port=atoi(argv[1]);
servidor.sin_port = htons(port);
}
else
servidor.sin_port = htons(PUERTO);
servidor.sin_addr.s_addr = INADDR_ANY;
if(bind(socket_servidor,(struct sockaddr *)&servidor,sizeof(servidor))<0){
printf("El puerto %d está en uso\n",PUERTO);
usage(argv[0]);
close(socket_servidor);
return 1;
}
listen(socket_servidor,25);
printf("Escuchando por el puerto %d\n",ntohs(servidor.sin_port));
clilong=sizeof(cliente[host]);
socket_cliente[host]=accept(socket_servidor,(struct sockaddr *)&cliente[host],&clilong);
if(socket_cliente[host]<0){
printf("Error aceptando el trafico con el host %s\n",
inet_ntoa(cliente[host].sin_addr));
close(socket_cliente[host]);
close(socket_servidor);
return 1;
}
else
printf("Conectado con el host %s\n",inet_ntoa(cliente[host].sin_addr));
host++;
FD_ZERO(&desc);
FD_SET(socket_servidor,&desc);
for(c=0;c<host;c++)
FD_SET(socket_cliente[c],&desc);
while(1){
if(select(host+4,&desc,NULL,NULL,NULL)<0){
printf("Error\n");
close(socket_cliente[host]);
close(socket_servidor);
return 1;
}
for(c=0;c<host;c++){
printf("C: %d\n",c);
if(FD_ISSET(socket_servidor,&desc)){
                               clilong=sizeof(cliente[host]);
                               socket_cliente[host]=accept(socket_servidor,
                                                       (struct sockaddr *)&cliente[host],&clilong);
                               if(socket_cliente[host]>0){
                                       printf("Se ha conectado el host %s\n",
                                                               inet_ntoa(cliente[host].sin_addr));
                                       host++;
                                       printf("Hosts %d\n",host);
                               }
                               else
                                       printf("Error al conectarse nuevo host\n");
}
                       if(FD_ISSET(socket_cliente[c],&desc)){
printf("Esperando algo\n");
j=recv(socket_cliente[c],buffer,220,0);
if(j>0){
printf("\n%s\n",buffer);
for(l=0;l<=host;l++)
send(l,buffer,220,0);
}
if(j==0){
printf("El host %s se ha desconectado\n",
inet_ntoa(cliente[c].sin_addr));
close(socket_cliente[c]);
host--;
printf("Hosts: %d\n",host);
}
}
}
}
free(buffer);
return 0;
}
Justicia es dar a cada uno lo que se merece

ivancea96

Si no sabes qué problemas tienes, ¿cómo sabes que tienes problemas?

Di qué error tienes, qué no ocurre correctamente, o qué no sabes implementar.

mester

Cita de: ivancea96 en 22 Noviembre 2015, 18:37 PM
Si no sabes qué problemas tienes, ¿cómo sabes que tienes problemas?

Di qué error tienes, qué no ocurre correctamente, o qué no sabes implementar.
Vale.
Principalmente, cuando ejecuto el programa y conecto un cliente, bien, el cliente envia paquetes y el servidor recibe e imprime. Pero cuando conecto un segundo cliente:
1-No me sale que se haya conectado.
2-No incrementa la variable host
3-No envía nada al servidor. (Enviar envía, pero el servidor no lo imprime)
Y si conecto los dos clientes a la vez despues de haber iniciado el servidor, es decir, conecto uno, sin enviar nada, y luego otro, se queda esperando una segunda conexión, y no recibe ni envía.

Es decir, que es o un if u otro. No quiero usar ni threads ni forks, he probado con sockets no bloqueantes, pero no son la solución.
Gracias
Justicia es dar a cada uno lo que se merece

kondrag_X1

Hola,

Te comento un poco a grandes rasgos lo que he visto:

tienes esta parte repetida encima del while y dentro:


socket_cliente[host]=accept(socket_servidor,(struct sockaddr *)&cliente[host],&clilong);
if(socket_cliente[host]<0){
printf("Error aceptando el trafico con el host %s\n",
inet_ntoa(cliente[host].sin_addr));
close(socket_cliente[host]);
close(socket_servidor);
return 1;
}
else
printf("Conectado con el host %s\n",inet_ntoa(cliente[host].sin_addr));
host++;
FD_ZERO(&desc);
FD_SET(socket_servidor,&desc);
for(c=0;c<host;c++)
FD_SET(socket_cliente[c],&desc);


lo primero que yo te aconsejaría es que si escribes un if{} el else que también tengo las llaves {} así evitaras confusiones.

la segunda cosa que veo rara es que solo incrementas el número de host cuando aceptas la primera conexión, es decir, dentro del while aceptas pero no incrementas el contador de host o yo no he visto donde esta el host++; como en el fragmento de arriba.

Si yo fuese tu interaria aceptar las conexiones dentro del while te simplificará mucho la tarea.

espero haberte ayudado. :silbar:

mester

Cita de: kondrag_X1 en 22 Noviembre 2015, 19:59 PM
Hola,

Te comento un poco a grandes rasgos lo que he visto:

tienes esta parte repetida encima del while y dentro:


socket_cliente[host]=accept(socket_servidor,(struct sockaddr *)&cliente[host],&clilong);
if(socket_cliente[host]<0){
printf("Error aceptando el trafico con el host %s\n",
inet_ntoa(cliente[host].sin_addr));
close(socket_cliente[host]);
close(socket_servidor);
return 1;
}
else
printf("Conectado con el host %s\n",inet_ntoa(cliente[host].sin_addr));
host++;
FD_ZERO(&desc);
FD_SET(socket_servidor,&desc);
for(c=0;c<host;c++)
FD_SET(socket_cliente[c],&desc);


lo primero que yo te aconsejaría es que si escribes un if{} el else que también tengo las llaves {} así evitaras confusiones.

la segunda cosa que veo rara es que solo incrementas el número de host cuando aceptas la primera conexión, es decir, dentro del while aceptas pero no incrementas el contador de host o yo no he visto donde esta el host++; como en el fragmento de arriba.

Si yo fuese tu interaria aceptar las conexiones dentro del while te simplificará mucho la tarea.

espero haberte ayudado. :silbar:
-Al principio la función la utilizo para que se conecte el primer cliente.
-Sí que incremento hosts:

if(FD_ISSET(socket_servidor,&desc)){
                                clilong=sizeof(cliente[host]);
                                socket_cliente[host]=accept(socket_servidor,
                                                        (struct sockaddr *)&cliente[host],&clilong);
                                if(socket_cliente[host]>0){
                                        printf("Se ha conectado el host %s\n",
                                                                inet_ntoa(cliente[host].sin_addr));
                                        host++;
                                        printf("Hosts %d\n",host);
                                }
                                else
                                        printf("Error al conectarse nuevo host\n");
}


                                        host++;
                                        printf("Hosts %d\n",host);

Y bueno, sí que podré la funcion de aceptar solo en el while
Justicia es dar a cada uno lo que se merece