Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: mester en 22 Noviembre 2015, 18:30 pm



Título: ¿Cómo funciona select() en c?
Publicado por: mester en 22 Noviembre 2015, 18:30 pm
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.
Código
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<string.h>
  4. #include<sys/types.h>
  5. #include<sys/socket.h>
  6. #include<netinet/in.h>
  7. #include<netdb.h>
  8. #include<fcntl.h>
  9. #include<arpa/inet.h>
  10. #define PUERTO 3317
  11. //PROBLEMA:
  12. //Cuando se va un host deja un espacio libre que hay que rellenar
  13. void usage(char *arg){
  14. printf("%s <puerto>\n",arg);
  15. }
  16. int main(int argc, char **argv){
  17. pid_t id;
  18. fd_set desc;
  19. int c,l,j;
  20. int host=0;
  21. int clilong;
  22. int socket_servidor;
  23. int socket_cliente[25];
  24. char *buffer=calloc(220,sizeof(char));
  25. struct sockaddr_in servidor;
  26. struct sockaddr_in cliente[25];
  27. socket_servidor=socket(AF_INET,SOCK_STREAM,0);
  28. servidor.sin_family = AF_INET;
  29. if(argc>1){
  30. int port=atoi(argv[1]);
  31. servidor.sin_port = htons(port);
  32. }
  33. else
  34. servidor.sin_port = htons(PUERTO);
  35. servidor.sin_addr.s_addr = INADDR_ANY;
  36. if(bind(socket_servidor,(struct sockaddr *)&servidor,sizeof(servidor))<0){
  37. printf("El puerto %d está en uso\n",PUERTO);
  38. usage(argv[0]);
  39. close(socket_servidor);
  40. return 1;
  41. }
  42. listen(socket_servidor,25);
  43. printf("Escuchando por el puerto %d\n",ntohs(servidor.sin_port));
  44. clilong=sizeof(cliente[host]);
  45. socket_cliente[host]=accept(socket_servidor,(struct sockaddr *)&cliente[host],&clilong);
  46. if(socket_cliente[host]<0){
  47. printf("Error aceptando el trafico con el host %s\n",
  48. inet_ntoa(cliente[host].sin_addr));
  49. close(socket_cliente[host]);
  50. close(socket_servidor);
  51. return 1;
  52. }
  53. else
  54. printf("Conectado con el host %s\n",inet_ntoa(cliente[host].sin_addr));
  55. host++;
  56. FD_ZERO(&desc);
  57. FD_SET(socket_servidor,&desc);
  58. for(c=0;c<host;c++)
  59. FD_SET(socket_cliente[c],&desc);
  60. while(1){
  61. if(select(host+4,&desc,NULL,NULL,NULL)<0){
  62. printf("Error\n");
  63. close(socket_cliente[host]);
  64. close(socket_servidor);
  65. return 1;
  66. }
  67. for(c=0;c<host;c++){
  68. printf("C: %d\n",c);
  69. if(FD_ISSET(socket_servidor,&desc)){
  70.                                clilong=sizeof(cliente[host]);
  71.                                socket_cliente[host]=accept(socket_servidor,
  72.                                                        (struct sockaddr *)&cliente[host],&clilong);
  73.                                if(socket_cliente[host]>0){
  74.                                        printf("Se ha conectado el host %s\n",
  75.                                                                inet_ntoa(cliente[host].sin_addr));
  76.                                        host++;
  77.                                        printf("Hosts %d\n",host);
  78.                                }
  79.                                else
  80.                                        printf("Error al conectarse nuevo host\n");
  81. }
  82.                        if(FD_ISSET(socket_cliente[c],&desc)){
  83. printf("Esperando algo\n");
  84. j=recv(socket_cliente[c],buffer,220,0);
  85. if(j>0){
  86. printf("\n%s\n",buffer);
  87. for(l=0;l<=host;l++)
  88. send(l,buffer,220,0);
  89. }
  90. if(j==0){
  91. printf("El host %s se ha desconectado\n",
  92. inet_ntoa(cliente[c].sin_addr));
  93. close(socket_cliente[c]);
  94. host--;
  95. printf("Hosts: %d\n",host);
  96. }
  97. }
  98. }
  99. }
  100. free(buffer);
  101. return 0;
  102. }
  103.  


Título: Re: ¿Cómo funciona select() en c?
Publicado por: 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.


Título: Re: ¿Cómo funciona select() en c?
Publicado por: mester en 22 Noviembre 2015, 18:45 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


Título: Re: ¿Cómo funciona select() en c?
Publicado por: 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:

Código
  1. socket_cliente[host]=accept(socket_servidor,(struct sockaddr *)&cliente[host],&clilong);
  2. if(socket_cliente[host]<0){
  3. printf("Error aceptando el trafico con el host %s\n",
  4. inet_ntoa(cliente[host].sin_addr));
  5. close(socket_cliente[host]);
  6. close(socket_servidor);
  7. return 1;
  8. }
  9. else
  10. printf("Conectado con el host %s\n",inet_ntoa(cliente[host].sin_addr));
  11. host++;
  12. FD_ZERO(&desc);
  13. FD_SET(socket_servidor,&desc);
  14. for(c=0;c<host;c++)
  15. FD_SET(socket_cliente[c],&desc);
  16.  

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:


Título: Re: ¿Cómo funciona select() en c?
Publicado por: mester en 22 Noviembre 2015, 22:11 pm
Hola,

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

tienes esta parte repetida encima del while y dentro:

Código
  1. socket_cliente[host]=accept(socket_servidor,(struct sockaddr *)&cliente[host],&clilong);
  2. if(socket_cliente[host]<0){
  3. printf("Error aceptando el trafico con el host %s\n",
  4. inet_ntoa(cliente[host].sin_addr));
  5. close(socket_cliente[host]);
  6. close(socket_servidor);
  7. return 1;
  8. }
  9. else
  10. printf("Conectado con el host %s\n",inet_ntoa(cliente[host].sin_addr));
  11. host++;
  12. FD_ZERO(&desc);
  13. FD_SET(socket_servidor,&desc);
  14. for(c=0;c<host;c++)
  15. FD_SET(socket_cliente[c],&desc);
  16.  

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:
Código
  1. if(FD_ISSET(socket_servidor,&desc)){
  2.                                clilong=sizeof(cliente[host]);
  3.                                socket_cliente[host]=accept(socket_servidor,
  4.                                                        (struct sockaddr *)&cliente[host],&clilong);
  5.                                if(socket_cliente[host]>0){
  6.                                        printf("Se ha conectado el host %s\n",
  7.                                                                inet_ntoa(cliente[host].sin_addr));
  8.                                        host++;
  9.                                        printf("Hosts %d\n",host);
  10.                                }
  11.                                else
  12.                                        printf("Error al conectarse nuevo host\n");
  13. }
  14.  
Código
  1.                                        host++;
  2.                                        printf("Hosts %d\n",host);
  3.  
Y bueno, sí que podré la funcion de aceptar solo en el while