Herramientas de usuario

Herramientas del sitio


sockets-jo

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anteriorRevisión previa
Próxima revisión
Revisión previa
sockets-jo [2014/10/29 15:38] – [Servidor Multi-Clientes con Fork] lmateusockets-jo [2018/08/16 13:04] (actual) – [Proxy genérico] lmateu
Línea 134: Línea 134:
 #include <stdlib.h> #include <stdlib.h>
 #include <unistd.h> #include <unistd.h>
 +#include <errno.h>
 +
 #include "jsocket.h" #include "jsocket.h"
- 
-/* 
- * client_echo2: envía toda su entrada estándar al servidor y todo lo 
- * que recibe de vuelta lo envía a su salida estándar. 
- */ 
  
 #define BUF_SIZE 1024 #define BUF_SIZE 1024
  
 int main() { int main() {
-  int s; +   int s; 
-  int cnt, cnt2; +   int rc; 
-  char buf[BUF_SIZE];+   int cnt, cnt2; 
 +   char buf[BUF_SIZE];
  
-  s = j_socket();+   s = j_socket();
  
-  if (j_connect(s, "localhost", 1818) < 0) { +   rc= j_connect(s, "localhost", 1818)
-    fprintf(stderr, "connection refused\n"); +   if (rc<0) { 
-    exit(1); +        perror("connect"); 
-  }+        exit(1); 
 +   }
  
-  while ((cnt=read(0, buf, BUF_SIZE)) > 0) { +   while ((cnt=read(0, buf, BUF_SIZE)) > 0) { 
-    if (write(s, buf, cnt) != cnt) { +        if(write(s, buf, cnt) != cnt) { 
-      fprintf(stderr, "Fall el write al servidor\n"); +           perror("write"); 
-      exit(1); +           exit(1); 
-    +        
-    while (cnt > 0 && (cnt2=read(s, buf, BUF_SIZE)) > 0) { +        while(cnt > 0) { 
-      write(1, buf, cnt2); +           cnt2=read(s, buf, BUF_SIZE)
-      cnt -= cnt2; +           if (cnt2<=0) { 
-    +             if (cnt2==0) 
-  }+               fprintf(stderr, "El socket fue cerrado por el servidor\n"); 
 +             else 
 +               perror("read"); 
 +             return 1; 
 +           } 
 +           write(1, "echo: ", 6); 
 +           write(1, buf, cnt2); 
 +           cnt -= cnt2; 
 +        
 +   }
  
-  return 0;+   return 0;
 } }
 </code> </code>
Línea 365: Línea 373:
 </code> </code>
  
-=== Ejercicio resuelto: servidor para cat remoto === +=== Ejercicio resuelto: Servidor para cat remoto ===
- +
-Estudie los programas servidor-cat.c y cat-remoto.c en [[http://users.dcc.uchile.cl/~lmateu/CC3301/download/serv-cat.zip|este link]].  Esta es la solución de la +
-[[http://users.dcc.uchile.cl/~lmateu/CC3301/tareas/t4-2012-2.pdf|tarea 4 del semestre Primavera de 2012]].+
  
 +Estudie los programas servidor-cat.c y cat-remoto.c en [[http://users.dcc.uchile.cl/~lmateu/CC3301/download/serv-cat.zip|este link]].  Esta es la solución de la [[http://users.dcc.uchile.cl/~lmateu/CC3301/tareas/t4-2012-2.pdf|tarea 4 del semestre Primavera de 2012]].
 ===== Servidor Multi-Clientes con Threads ===== ===== Servidor Multi-Clientes con Threads =====
  
Línea 573: Línea 579:
 </code> </code>
  
-=== Ejercicio ===+=== Ejercicios propuestos ===
  
   * Modifique el servidor de chat para que no reenvíe el mensaje al cliente que lo envía.   * Modifique el servidor de chat para que no reenvíe el mensaje al cliente que lo envía.
   * Modifique el cliente de chat para que agregue el nombre del usuario a todos los mensajes.   * Modifique el cliente de chat para que agregue el nombre del usuario a todos los mensajes.
-  * Estudie el código de serv-dict2.c correspondiente al ejercicio resuelto al comienzo de esta sección.  En esta versión, cuando un cliente consulta una llave inexistente, se bloquea hasta que se defina esa llava y por lo tanto satisface el enunciado.  En este caso hay que usar múltiples threads en el servidor. 
  
-=== Ejercicio resueltoservidor para un diccionario inter procesos ===+=== Ejercicios resueltos ===
  
-Estudie los programas serv-dict.c, serv-dict2.c y dict.c en [[http://users.dcc.uchile.cl/~lmateu/CC3301/download/serv-dict.tgz|este link]] en formato tar comprimido con gzip.  El programa serv-dict.c es una solución incompleta de la +  * Servidor para un diccionario inter procesos.  Estudie los programas serv-dict.c, serv-dict2.c y dict.c en [[http://users.dcc.uchile.cl/~lmateu/CC3301/download/serv-dict.tgz|este link]] en formato tar comprimido con gzip.  El programa serv-dict.c es una solución incompleta de la [[http://users.dcc.uchile.cl/~lmateu/CC3301/tareas/t4-2013-1.pdf|tarea 4 del semestre Otoño de 2013]].  Es incompleta porque si un cliente consulta una llave y la llave no está definida, el cliente no espera.  La solución completa es serv-dict2.c.  Además los comandos usados son d para definir (no def), q para consultar (no query) y e para eliminar
-[[http://users.dcc.uchile.cl/~lmateu/CC3301/tareas/t4-2013-1.pdf|tarea 4 del semestre Otoño de 2013]]. +  * Determinar si un número es primo buscando algún factor.  Estudie la [[http://users.dcc.uchile.cl/~lmateu/CC3301/download/c3-sol-2013-2.zip|solución]] del [[http://users.dcc.uchile.cl/~lmateu/CC3301/controles/c3-132.pdf|control 3 del semestre Primavera 2013]].  Pruebe las distintas implementaciones con números primos sacados de la [[http://en.wikipedia.org/wiki/List_of_prime_numbers|wikipedia]].
-Es incompleta porque si un cliente consulta una llave y la llave no está definida, el cliente no +
-espera.  La solución completa es serv-dict2.c.  Además los comandos usados son d para definir (no def), q para consultar (no query) y e para eliminar.+
 ===== Servidor Multi-cliente con select ===== ===== Servidor Multi-cliente con select =====
  
Línea 696: Línea 699:
 de chat con threads: nunca se bloquea para todos los clientes. de chat con threads: nunca se bloquea para todos los clientes.
  
-===== Proxy genérico ===== 
- 
-Se trata de escribir un programa que haga de "proxy" de un servidor: se trata de instalar un intermediario que simula ser un servidor, pero que en realidad "representa" a otro servidor que ahora está en otra máquina. Es como un "forwarder" que sirve para instalarlo si movemos un servidor de una máquina a otra y queremos que los clientes antiguos sigan funcionando, o para instalar en un computador que es accesible desde Internet para representar un servidor que está en un computador sin acceso a Internet (una intranet por ejemplo). La invocación de este proxy es: 
-<code> 
-% ./proxy port-in server port-out 
-</code> 
-Escucha en la máquina local conexiones que llegan a port-in, luego se conecta a (server, port-out) y luego envía y recibe todos los datos de ambos lados. Haremos dos versiones, una que crea dos procesos hijos (uno que copia en una 
-dirección del socket y otro que copia en la dirección opuesta) y otra con select que queda mejor. 
- 
-Solución con 2 hijos: 
-<code C> 
- #include <stdio.h> 
-#include <stdlib.h> 
-#include <signal.h> 
-#include <wait.h> 
-#include "jsocket.h" 
- 
-/* 
- * proxy: proxy multi-cliente usando procesos pesados 
- * Hacer version con select? 
- */ 
- 
-#define BUF_SIZE 200 
- 
-/* 
- * Esta es la forma mas simple de enterrar a los hijos sin complicarse l 
-a vida 
- */ 
-void child() { 
-    int status; 
- 
-    while(waitpid(-1, &status, WNOHANG)>0) 
- ; 
-} 
- 
-void die() { 
-    fprintf(stderr, "cliente desconectado\n"); 
-    exit(0); 
-} 
- 
-/* 
- * Este es el servidor y el codigo para un socket cliente ya conectado:  
- */ 
-void proxy(int s1, char *host, int portout) { 
-   int cnt, size = BUF_SIZE; 
-   char buf[BUF_SIZE]; 
-   int s2; 
-   int pid; 
- 
-   signal(SIGUSR1, die); 
- 
-   s2 = j_socket(); 
- 
-   if(j_connect(s2, host, portout) < 0) { 
- fprintf(stderr, "connection refused to %s/%d\n", host, portout); 
- exit(1); 
-   } 
-   fprintf(stderr, "cliente conectado\n"); 
-  
-   if((pid = fork()) < 0) { 
-    fprintf(stderr, "no pude fork\n"); 
- exit(1); 
-   } 
- 
-   if(pid == 0) { 
-    while((cnt=read(s1, buf, size)) > 0) 
-     if(write(s2, buf, cnt) < 0) break; 
- kill(getppid(), SIGUSR1); 
- exit(0); 
-   } else 
-    while((cnt=read(s2, buf, size)) > 0) 
-     if(write(s1, buf, cnt) < 0) break; 
- 
-    kill(pid, SIGKILL); 
-    fprintf(stderr, "cliente desconectado\n"); 
-} 
- 
-/* 
- * Este es el principal: solo acepta conexiones y crea a los hijos servi 
-dores 
- */ 
-main(int argc, char **argv) { 
-   int s, s2; 
-   int portin, portout; 
-   char *host; 
- 
-   if(argc != 4) { 
- fprintf(stderr, "Use: %s port-in host port-out\n", argv[0]); 
- exit(1); 
-   } 
- 
-   portin = atoi(argv[1]); 
-   host = argv[2]; 
-   portout = atoi(argv[3]); 
- 
-   signal(SIGCHLD, child); 
- 
-   s = j_socket(); 
- 
-   if(j_bind(s, portin) < 0) { 
- fprintf(stderr, "bind failed\n"); 
- exit(1); 
-   } 
- 
-   for(;;) { 
- s2 = j_accept(s); 
- if(fork() == 0) { /* Este es el hijo */ 
-     close(s); /* cerrar el socket que no voy a usar */ 
-     proxy(s2, host, portout); 
-     exit(0); 
- } else 
-     close(s2); /* cerrar el socket que no voy a usar */ 
-   } 
-} 
-</code> 
- 
-Y una mejor con select: 
-<code C> 
-#include <stdio.h> 
-#include <stdlib.h> 
-#include <signal.h> 
-#include <wait.h> 
-#include "jsocket.h" 
- 
-/* 
- * proxy: proxy multi-cliente usando procesos pesados 
- * version con select 
- */ 
- 
-#define BUF_SIZE 200 
- 
-/* 
- * Esta es la forma mas simple de enterrar a los hijos sin complicarse l 
-a vida 
- */ 
-void child() { 
-    int status; 
- 
-    while(waitpid(-1, &status, WNOHANG)>0) 
- ; 
-} 
- 
-/* 
- * Este es el servidor y el codigo para un socket cliente ya conectado:  
-s 
- */ 
-void proxy(int s1, char *host, int portout) { 
-   int cnt, size = BUF_SIZE; 
-   char buf[BUF_SIZE]; 
-   int s2; 
-   int pid; 
-   fd_set mask; 
- 
-   s2 = j_socket(); 
- 
-   if(j_connect(s2, host, portout) < 0) { 
- fprintf(stderr, "connection refused to %s/%d\n", host, portout); 
- exit(1); 
-   } 
-   fprintf(stderr, "cliente conectado\n"); 
-  
-/* 
-       int select(int numfds, fd_set *readfds, fd_set *writefds , 
-       fd_set *exceptfds, struct timeval * timeout); 
- 
-       FD_CLR(int fd, fd_set *set); 
-       FD_ISSET(int fd, fd_set *set); 
-       FD_SET(int fd, fd_set *set); 
-       FD_ZERO(fd_set * set); 
-*/ 
-    
-    
-    for(;;) { 
-        FD_ZERO(&mask); 
-        FD_SET(s1, &mask); FD_SET(s2, &mask); 
- select(getdtablesize(), &mask, NULL, NULL, NULL); 
- if(FD_ISSET(s1, &mask)) { 
-        cnt=read(s1, buf, size); 
-     if(cnt <= 0) { 
-    fprintf(stderr, "cliente desconectado\n"); 
- exit(0); 
-     } 
-     write(s2, buf, cnt); 
- } 
- if(FD_ISSET(s2, &mask)) { 
-        cnt=read(s2, buf, size); 
-     if(cnt <= 0) { 
-    fprintf(stderr, "cliente desconectado\n"); 
-  exit(0); 
-     } 
-     write(s1, buf, cnt); 
- } 
-    } 
-} 
- 
-/* 
- * Este es el principal: solo acepta conexiones y crea a los hijos servi 
-dores 
- */ 
-main(int argc, char **argv) { 
-   int s, s2; 
-   int portin, portout; 
-   char *host; 
- 
-   if(argc != 4) { 
- fprintf(stderr, "Use: %s port-in host port-out\n", argv[0]); 
- exit(1); 
-   } 
- 
-   portin = atoi(argv[1]); 
-   host = argv[2]; 
-   portout = atoi(argv[3]); 
- 
-   signal(SIGCHLD, child); 
- 
-   s = j_socket(); 
- 
-   if(j_bind(s, portin) < 0) { 
- fprintf(stderr, "bind failed\n"); 
- exit(1); 
-   } 
- 
-   for(;;) { 
- s2 = j_accept(s); 
- if(fork() == 0) { /* Este es el hijo */ 
-     close(s); /* cerrar el socket que no voy a usar */ 
-     proxy(s2, host, portout); 
-     exit(0); 
- } else 
-     close(s2); /* cerrar el socket que no voy a usar */ 
-   } 
-} 
-</code> 
- 
-=== El super demonio inetd === 
  
-Estudie [[http://users.dcc.uchile.cl/~lmateu/CC3301/apuntes/Sockets/|el super demonio inetd]] que aparece en los apuntes de Patricio Poblete. 
  
sockets-jo.1414597081.txt.gz · Última modificación: 2014/10/29 15:38 por lmateu