Compilació
Es tracta d'una aplicació client servidor d'echos, que vam realitzar en el Curs de Programació Linux de la ICE-UPC (Sergi Tur):
el servidor escolta els echos (missatges per pantalla) que li arriben dels clients. La única cosa que fa el servidor es mostrar per pantalla els missatges que li envien els clients. És un exercici de programació de sockets en C.
En la primera part compilarem el codi. Després l'executarem en un client i en un servidor per comprovar que funciona. Més tard farem que el servidor sigui un dimoni. I més tard en farem un paquet (el debianitzarem) per tal de poder distribuir-lo.
Codi. Compilació
El codi el podem descarregar de La Farga: https://lafarga.cpl.upc.edu/plugins/scmsvn/viewcvs.php/sessio5/ClientServerEcho/?rev=12&root=plinux
server.c
/* http://xarxantoni.net:8080/mediawiki/index.php/Programaci%C3%B3_en_xarxes */ #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> //Aquí podeu escollir el port del servidor. int port = 8000; void main() { struct sockaddr_in sin; struct sockaddr_in pin; int sock_descriptor; int temp_sock_descriptor; int address_size=0; char buf[16384]; int i, len; /* PF_INET/AF_INET Determinem IPv4 com la familia de protocols. Veieu man ip(7) SOCK_STREAM Mode orientat a connexió. 0 Al fitxer /etc/protocols el protocol 0 és el IP. */ sock_descriptor = socket(AF_INET, SOCK_STREAM, 0); if (sock_descriptor == -1) { perror("Error al cridar socket..."); exit(1); } memset(&sin,0 , sizeof(sin)); sin.sin_family = AF_INET; // INADDR_ANY ens permet fer el vincle amb qualsevol de les adreces IP del // servidor. sin.sin_addr.s_addr = INADDR_ANY; //La comanda htons transforma un número de port en el format de xarxa. sin.sin_port = htons(port); if (bind(sock_descriptor, (struct sockaddr *)&sin, sizeof(sin)) == -1) { perror("Error al cridar bind..."); exit(1); } if (listen(sock_descriptor, 20) == -1) { perror("Error al cridar listen..."); exit(1); } printf("El servidor esta a l'espera de rebre connexions ...\n"); // El bucle infinit fa que el servidor es quedi escoltant noves peticions // permanentment. Cada nova petició, s'obra un nou socket per fer la // la comunicació entre el client i el servidor. while(1) { temp_sock_descriptor = accept(sock_descriptor, (struct sockaddr *)&pin, &address_size); if (temp_sock_descriptor == -1) { perror("Error al cridar accept..."); exit(1); } if (recv(temp_sock_descriptor, buf, 16384, 0) == -1) { perror("Error al cridar recv..."); exit(1); } printf("S'ha rebut del client el següent String:%s\n", buf); if (send(temp_sock_descriptor, buf, strlen(buf), 0) == -1) { perror("Error al cridar send"); exit(1); } close(temp_sock_descriptor); } }
En el client he de posar la IP del servidor al que em vull connectar client.c
#include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> /* Aquí heu de declarar l'adreça IP i número de port del servidor */ //char * host_name = "127.0.0.1"; char * host_name = "192.168.1.130"; int port = 8000; void main(int argc, char *argv[]) { char buf[8192]; char missatge[256]; int socket_fd; struct sockaddr_in sin; struct hostent *server_host_name; char * str; if (argc != 2) { printf("Utilitza: %s missatge\n",argv[0]); exit(1); } else { str = argv[1]; } if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("Error creant el socket\n"); exit(1); } if ((server_host_name = gethostbyname(host_name)) == 0) { perror("Error resolent l'adreça del servidor\n"); exit(1); } /*Inicialització de la variable sockaddr tal i com s'indica a a man 2 bind*/ memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_addr.s_addr = ((struct in_addr *)(server_host_name->h_addr))->s_addr; sin.sin_port = htons(port); if (connect(socket_fd, (void *)&sin, sizeof(sin)) == -1) { perror("Error conectant-se al socket\n"); exit(1); } printf("Enviant missatge %s al servidor...\n", str); if (send(socket_fd, str, 8192, 0) == -1) { perror("Error enviant el missatge...\n"); exit(1); } printf("..Misatge enviat .. esperant la resposta...\n"); if (recv(socket_fd, buf, 8192, 0) == -1) { perror("Error reben la resposta del servidor...\n"); exit(1); } printf("\nResposta del servidor: %s\n", buf); close(socket_fd); }
i compilem:
$ sudo make
Compila bé excepte alguns warnings, es generer els executables client i server
Per fer la primera prova ho fem en la mateixa màquina. En un terminal obrim el server i en l'altre terminal el client:
$ ./server El servidor esta a l'espera de rebre connexions ...
$ ./client hola Enviant missatge hola al servidor... ..Misatge enviat .. esperant la resposta... Resposta del servidor: hola
i en el servidor hem obtingut:
S'ha rebut del client el següent String:hola
Faig la prova en dos ordinadors diferents, i funciona bé.
Com que em connecto pel port 8000, des de la màquina client també em puc connectar al servidor per telnet:
$ telnet 192.168.1.130 8000 hola món hola món -> resposta del servidor GENT_PID=5477Connection closed by foreign host $
5477 és el PID (identificador del procés):
$ ps aux | grep server joan 19274 0.0 0.0 1544 368 pts/0 S+ 10:14 0:00 ./server
Doncs no, el PID=19274
per fer un scanner dels ports, i veure que el 8000 està obert (ho faig en el client):
$ sudo apt-get install nmap $ nmap 192.168.1.130 8000/tcp open http-alt
creat per Joan Quintana Compte, octubre 2008