Autor
|
Tema: Abrir multiples conexiones Sockets C (Leído 7,239 veces)
|
mester
Desconectado
Mensajes: 219
https://www.youtube.com/watch?v=IlY9C6pzxKc
|
Hola. Estoy introduciéndome en el mundo de los sockets en Linux y haciendo tanto cliente como servidor quise iniciar mi primer chat. Hasta ahí bien, pero ahora lo que quiero es que el servidor del chat pueda soportar varias conexiones (que hacerlo, lo hace) pero que lea también de éstas. Es decir, este "chat" solo funciona por turnos jeje. Escribo mi código: Servidor: #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<netdb.h> int main(int argc, char **argv){ if(argc<2){ printf("%s <puerto>\n",argv [0]); return 1; } int con_ser,con_cli,puerto; int I; socklen_t clilen; char *buffer; struct sockaddr_in cliente; struct sockaddr_in servidor; con_ser=socket(AF_INET,SOCK_STREAM,0); if(con_ser<0){ printf("Error creando el socket\n"); close(con_ser); return 1; } bzero((char *)&servidor,sizeof(servidor)); servidor.sin_family = AF_INET; servidor.sin_port = htons(puerto); servidor.sin_addr.s_addr = INADDR_ANY; I=bind(con_ser,(struct sockaddr *)&servidor,sizeof(servidor)); if(I<0){ printf("Error al asignar el puerto\n"); close(con_ser); return 1; } listen(con_ser,3); clilen = sizeof(cliente); con_cli=accept(con_ser,(struct sockaddr *)&cliente,&clilen); if(con_cli<0){ printf("Error en la transaccion\n"); close(con_ser); return 1; } buffer =calloc(220,sizeof(char)); do{ I=read(con_cli,buffer,220); if(I<0){ printf("Error recibiendo información\n"); close(con_ser); return 1; } if(strcmp(buffer ,"101001001")!=0) else{ break; } buffer =calloc(220,sizeof(char)); I=write(con_cli,buffer,220); if(I<0){ printf("Error enviando información\n"); close(con_ser); return 1; } }while(1); return 0; }
Cliente: #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<netdb.h> #define RED "\x1b[31m" #define GREEN "\x1b[32m" #define YELLOW "\x1b[33m" #define BLUE "\x1b[34m" #define MAGENTA "\x1b[35m" #define CYAN "\x1b[36m" #define RESET "\x1b[0m" int cmp(char *s1, char *s2, char *s3){ int ret = 0; while(!(ret=*(unsigned char *)s1 - *(unsigned char *)s3) && *s3) ++s1, ++s3; if(ret<0) ret=-1; if(ret > 0) ret=1; return ret; } int main(int argc, char **argv){ if(argc<3){ printf(YELLOW "%s <host> <puerto>\n"RESET ,argv [0]); return 1; } int conexion,puerto,i; char *frase; char *buffer; struct hostent *server; struct sockaddr_in cliente; server=gethostbyname(argv[1]); if(server==NULL){ printf(RED "Host erróneo, introduce el host\n"RESET ); return 1; } conexion=socket(AF_INET,SOCK_STREAM,0); cliente.sin_family = AF_INET; cliente.sin_port = htons(puerto); bcopy((char *)server->h_addr,(char *)&cliente.sin_addr.s_addr,sizeof(server->h_length)); i=connect(conexion,(struct sockaddr *)&cliente,sizeof(cliente)); if(i<0){ printf("Error conectando con el host\n"); close(conexion); return 1; } printf(YELLOW "Escribe "RED "\"EOF\""RESET " para salir\n"RESET ); do{ buffer =calloc(220,sizeof(char)); if(buffer==NULL){ printf("No se ha podido reservar memoria\n"); close(conexion); return 1; } frase =calloc(200,sizeof(char)); if(frase==NULL){ printf("No se ha podido reservar memoria\n"); close(conexion); return 1; } printf(YELLOW "%s: "RESET ,getlogin ()); if(cmp(buffer,"EOF\n",getlogin())==0){ write(conexion,"101001001",10); break; } i=write(conexion,buffer,220); if(i<0){ printf(RED "Error al enviar los datos\n"RESET ); break; } i=read(conexion,buffer,220); if(i<0){ printf(RED "Error al recibir los datos\n"RESET ); break; } }while(1); close(conexion); return 0; }
Se agradece de antemano
|
|
« Última modificación: 9 Noviembre 2015, 12:42 pm por nonpromisc »
|
En línea
|
Justicia es dar a cada uno lo que se merece
|
|
|
ivancea96
Desconectado
Mensajes: 3.412
ASMático
|
Los sockets abiertos, los conservas en un array. Luego, basta iterar por cada socket del array, y leer en caso de que haya bytes que leer, y enviar datos si es necesario.
Deberías estructurar tu programa. Crea funciones para hacer el código legible.
|
|
|
En línea
|
|
|
|
mester
Desconectado
Mensajes: 219
https://www.youtube.com/watch?v=IlY9C6pzxKc
|
Los sockets abiertos, los conservas en un array. Luego, basta iterar por cada socket del array, y leer en caso de que haya bytes que leer, y enviar datos si es necesario.
Deberías estructurar tu programa. Crea funciones para hacer el código legible.
Supongo que entiendo lo que dices, pero no sé aplicarlo. ¿puedes explicármelo de diferente manera si es posible? Se agradece
|
|
|
En línea
|
Justicia es dar a cada uno lo que se merece
|
|
|
ivancea96
Desconectado
Mensajes: 3.412
ASMático
|
Te pongo un ejemplo práctico: socket *sockets; listener li; crearArray(&sockets); inicializarSocketDeEscucha(li); while(true){ socket sock; sock = nuevoCliente(listener); if(sock) añadirSocket(&sockets, sock); porCadaSocket -i-{ escucharYResponder(sockets[i]); } }
En fin, es un esquema, con funciones que creo que entiendes lo que hacen. En bucle, haces estas acciones: -1: Encuentras nuevos clientes si los hay. -2: Escuchas y respondes a cada cliente. Si por ejemplo un cliente te envía un mensaje de chat, reenvías ese mensaje a todos los demás clientes.
|
|
|
En línea
|
|
|
|
mester
Desconectado
Mensajes: 219
https://www.youtube.com/watch?v=IlY9C6pzxKc
|
Te pongo un ejemplo práctico: socket *sockets; listener li; crearArray(&sockets); inicializarSocketDeEscucha(li); while(true){ socket sock; sock = nuevoCliente(listener); if(sock) añadirSocket(&sockets, sock); porCadaSocket -i-{ escucharYResponder(sockets[i]); } }
En fin, es un esquema, con funciones que creo que entiendes lo que hacen. En bucle, haces estas acciones: -1: Encuentras nuevos clientes si los hay. -2: Escuchas y respondes a cada cliente. Si por ejemplo un cliente te envía un mensaje de chat, reenvías ese mensaje a todos los demás clientes. El problema es que cuando espero una conexión entrante con la función 'accept()' el programa se detiene esperando una conexión entrante. Y con el cliente, cuando le indico que reciba con 'recv()' hasta que no recibe información no puedes seguir escribiendo. Agradezco el ejemplo de codigo, ahora mismo me pongo a organizarlo.
|
|
|
En línea
|
Justicia es dar a cada uno lo que se merece
|
|
|
ivancea96
Desconectado
Mensajes: 3.412
ASMático
|
Los sockets pueden ser "bloqueantes" o "no bloqueantes". En el caso que comentas, probablemente sea bloquenate. Para ponerlo "non-blocking", no te puedo ayudar, que no utilizo unix. Busca por ahí, y encontrarás. De todos modos, tal ocmo los tienes, otra opción es tener un thread para leer del servidor, y luego otro thread para los sockets ya abiertos (o un thread por socket, tú verás). Claro que, para recv, me parece más cómodo un socket no bloqueante. Lo dicho, echa un vistazo para ver cómo cambiar. En caso de sockets de Windows, se haría así: u_long block = 1 // 1 or 0, bloquing or non blocking; ioctlsocket(sock, FIONBIO, &block);
|
|
|
En línea
|
|
|
|
mester
Desconectado
Mensajes: 219
https://www.youtube.com/watch?v=IlY9C6pzxKc
|
Los sockets pueden ser "bloqueantes" o "no bloqueantes". En el caso que comentas, probablemente sea bloquenate. Para ponerlo "non-blocking", no te puedo ayudar, que no utilizo unix. Busca por ahí, y encontrarás. De todos modos, tal ocmo los tienes, otra opción es tener un thread para leer del servidor, y luego otro thread para los sockets ya abiertos (o un thread por socket, tú verás). Claro que, para recv, me parece más cómodo un socket no bloqueante. Lo dicho, echa un vistazo para ver cómo cambiar. En caso de sockets de Windows, se haría así: u_long block = 1 // 1 or 0, bloquing or non blocking; ioctlsocket(sock, FIONBIO, &block);
He estado probando a ponerlo non-blocking, de momento funciona, ahora, no sabría como desarrollar el programa para que tanto cliente como servidor puedan enviar mensajes sin parar, y el otro los reciba, es decir, que me gustaría que el fgets() no bloquease el programa a la espera de una entrada de datos, para hacerlo más fácil, sino, se acumulan todos los mensajes. Escribo las funciones de la conexión: int conectar(int sock, struct sockaddr_in client){ char *frase; char *buffer; if(connect(sock,(struct sockaddr *)&client,sizeof(client))<0) error(1,inet_ntoa(client.sin_addr)); else printf("Conectando con %s:%d\n\n",inet_ntoa (client. sin_addr),ntohs (client. sin_port)); printf("\t\t\t\t%s\n",inet_ntoa (client. sin_addr)); fcntl(sock,F_SETFL,O_NONBLOCK); frase =(char *)calloc(200,sizeof(char)); buffer =(char *)calloc(220,sizeof(char)); while(1){ if(leer(sock)!=0) continue; break; } buffer=cmp(frase,getlogin()); if(send(sock,buffer,220,0)<0) error(2,inet_ntoa(client.sin_addr)); } return 0; } int leer(int conexion){ int c; char *buffer; buffer =(char *)calloc(200,sizeof(char)); if(recv(conexion,buffer,200,0)>0){ c=0; } else c=1; return c; }
Agradezco tu ayuda, me es muy útil para desarrollar mi programa.
|
|
|
En línea
|
Justicia es dar a cada uno lo que se merece
|
|
|
ivancea96
Desconectado
Mensajes: 3.412
ASMático
|
Para hacerlo con consola, y querer leer de consola, lo puedes hacer con 2 threads, uno para leer la consola, y otro para trabajar el/los sockets.
De todos modos, ten en cuenta algo: si recibes un mensaje mientras escribes, la consola escribirá sobre lo que tú estás escribiendo. Para practicar está bien, pero bueno.
Para eso, lo dicho, threads.
|
|
|
En línea
|
|
|
|
mester
Desconectado
Mensajes: 219
https://www.youtube.com/watch?v=IlY9C6pzxKc
|
Para hacerlo con consola, y querer leer de consola, lo puedes hacer con 2 threads, uno para leer la consola, y otro para trabajar el/los sockets.
De todos modos, ten en cuenta algo: si recibes un mensaje mientras escribes, la consola escribirá sobre lo que tú estás escribiendo. Para practicar está bien, pero bueno.
Para eso, lo dicho, threads.
Vale ya lo tengo, ahora necesito saber cómo matar un fork. He estado buscando, pero con kill(pid,SIGKILL); no me funciona, te muestro el codigo: (MODIFICADO) Ya lo he hecho para que funcione. Funciona mal, porque mato directamente el proceso, pero bueno, ya lo mejoraré. Posteo aquí el codigo tanto de cliente como de servidor. Cliente: #include<stdio.h> #include<wait.h> #include<signal.h> #include<sys/types.h> #include<string.h> #include<stdlib.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> #include<netinet/in.h> #include<netdb.h> #include<fcntl.h> void usage(const char *arg){ printf("%s <host> <puerto>\n",arg ); } void error(int codigo, const char *err){ switch(codigo){ case 0: printf("La dirección del Host no es válida\n"); break; case 1: printf("Error conectando con el host %s\n",err ); break; case 2: printf("Error enviando los datos a %s\n",err ); break; } } char *cmp(char *palabra, char *nombre){ char *mem =(char *)calloc(220,sizeof(char)); return mem; } void leer(int); int escribir(int,struct sockaddr_in); int conectar(int, struct sockaddr_in); int main(int argc, char **argv){ if(argc<3) usage(argv[0]); int conexion, puerto; struct sockaddr_in cliente; struct hostent *servidor; servidor=gethostbyname(argv[1]); if(servidor==NULL) error(0," "); conexion=socket(AF_INET,SOCK_STREAM,0); cliente.sin_family=AF_INET; cliente.sin_port=htons(puerto); bcopy((char *)servidor->h_addr,(char *)&cliente.sin_addr,sizeof(servidor->h_length)); conectar(conexion, cliente); send(conexion,"78421687541295",15,0); close(conexion); return 0; } int conectar(int sock, struct sockaddr_in client){ int c; int id; int estado; if(connect(sock,(struct sockaddr *)&client,sizeof(client))<0) error(1,inet_ntoa(client.sin_addr)); else printf("Conectando con %s:%d\n\n",inet_ntoa (client. sin_addr),ntohs (client. sin_port)); printf("Escribe \"EOF\" para salir\n"); printf("\t\t\t\t%s\n",inet_ntoa (client. sin_addr)); fcntl(sock,F_SETFL,O_NONBLOCK); id=fork(); if(id==0){ while(1){ leer(sock); sleep(1); } } while(1){ c=escribir(sock,client); if(c==1) break; } kill(id,SIGKILL); return 0; } void leer(int conexion){ char *cadena; cadena =(char *)calloc(220,sizeof(char)); if(recv(conexion,cadena,220,0)>0) else } int escribir(int conexion,struct sockaddr_in client){ char *buffer =(char *)calloc(220,sizeof(char)); char *cadena =(char *)calloc(200,sizeof(char)); buffer=cmp(cadena,getlogin()); return 1; if(send(conexion,buffer,220,0)<0) error(2,inet_ntoa(client.sin_addr)); return 0; }
Servidor: #include<stdio.h> #include<wait.h> #include<sys/types.h> #include<string.h> #include<stdlib.h> #include<unistd.h> #include<arpa/inet.h> #include<netinet/in.h> #include<netdb.h> #include<fcntl.h> void usage(const char *arg){ } char *cmp(char *palabra, char *nombre){ char *mem =(char *)calloc(220,sizeof(char)); return mem; } void escribir(int); int recibir(int); int escuchar(int, struct sockaddr_in); int main(int argc, char **argv){ if(argc<2) usage(argv[0]); int conexion_servidor, puerto; char *buffer; struct sockaddr_in servidor; conexion_servidor=socket(AF_INET,SOCK_STREAM,0); servidor.sin_family=AF_INET; servidor.sin_port=htons(puerto); servidor.sin_addr.s_addr=INADDR_ANY; escuchar(conexion_servidor,servidor); close(conexion_servidor); return 0; } int escuchar(int conexion_servidor, struct sockaddr_in servidor){ struct sockaddr_in cliente; int c; int id; int conexion_cliente; int clilong; if(bind(conexion_servidor,(struct sockaddr *)&servidor,sizeof(servidor))<0){ printf("Error. El puerto está en uso\n"); close(conexion_servidor); return 1; } listen(conexion_servidor,5); clilong=sizeof(cliente); printf("Escuchando en el puerto %d\n",htons (servidor. sin_port)); conexion_cliente=accept(conexion_servidor,(struct sockaddr *)&cliente,&clilong); if(conexion_cliente<0){ printf("Error en la asociacion con el host %s\n",inet_ntoa (cliente. sin_addr)); close(conexion_servidor); return 1; } else printf("Conectado con %s:%d\n",inet_ntoa (cliente. sin_addr),ntohs (servidor. sin_port)); fcntl(conexion_cliente,F_SETFL,O_NONBLOCK); id=fork(); if(id==0){ while(1){ sleep(1); c=recibir(conexion_cliente); if(c==1) break; } } while(c!=1) escribir(conexion_cliente); kill(id,SIGKILL); return 0; } int recibir(int conexion){ int c=0; char *buffer =(char *)calloc(220,sizeof(char)); if(recv(conexion,buffer,220,0)>0){ if(strcmp(buffer ,"78421687541295")!=0) else c=1; } return c; } void escribir(int conexion){ char *buffer =(char *)calloc(220,sizeof(char)); char *cadena =(char *)calloc(200,sizeof(char)); buffer=cmp(cadena,"SERVIDOR"); if(send(conexion,buffer,220,0)<0) printf("Error enviando la información\n"); }
|
|
« Última modificación: 11 Noviembre 2015, 12:41 pm por nonpromisc »
|
En línea
|
Justicia es dar a cada uno lo que se merece
|
|
|
ivancea96
Desconectado
Mensajes: 3.412
ASMático
|
Matarlo es muy bruto. En vez de eso, cambia el while(1) por una variable que compartan, y cuando quieras que se detenga, pones esa variable a 0, por ejemplo.
|
|
|
En línea
|
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
Duda cliente-servidor, multiples conexiones, administrador de conexiones
Programación Visual Basic
|
-Xenon-
|
8
|
5,594
|
14 Enero 2006, 14:44 pm
por -Xenon-
|
|
|
Conexiones multiples
Programación Visual Basic
|
demoniox12
|
5
|
2,643
|
7 Diciembre 2007, 15:06 pm
por demoniox12
|
|
|
Sockets C#: Multiples Conexiones
Programación General
|
9ttnix
|
0
|
2,752
|
29 Mayo 2013, 23:11 pm
por 9ttnix
|
|
|
Administrar múltiples sockets
« 1 2 »
Análisis y Diseño de Malware
|
.:UND3R:.
|
14
|
8,275
|
16 Febrero 2014, 07:14 am
por Vaagish
|
|
|
[Sockets] Conexiones múltiples de clientes a servidor.
Programación C/C++
|
Zodiak98
|
6
|
5,682
|
25 Enero 2016, 00:42 am
por sodark
|
|