From 93ffcc665db035b6f797fd6e1e17333b07e98767 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Mon, 22 May 2006 15:48:54 +0000 Subject: [PATCH] =?utf8?q?Primera=20parte=20de=20pr=C3=A1ctica=203=20termi?= =?utf8?q?nada.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- practicas/practica3/Makefile | 19 ++ practicas/practica3/common/Makefile | 16 ++ practicas/practica3/common/common.c | 29 +++ practicas/practica3/common/common.h | 21 +++ practicas/practica3/libtcp/Makefile | 17 ++ practicas/practica3/libtcp/libtcp.c | 176 +++++++++++++++++++ practicas/practica3/libtcp/libtcp.h | 40 +++++ practicas/practica3/parte1/Makefile | 27 +++ practicas/practica3/parte1/client | Bin 0 -> 56217 bytes practicas/practica3/parte1/client.cpp | 133 ++++++++++++++ practicas/practica3/parte1/protocol.h | 23 +++ practicas/practica3/parte1/server.cpp | 85 +++++++++ practicas/practica3/parte1/serverhandler.cpp | 111 ++++++++++++ 13 files changed, 697 insertions(+) create mode 100644 practicas/practica3/Makefile create mode 100644 practicas/practica3/common/Makefile create mode 100644 practicas/practica3/common/common.c create mode 100644 practicas/practica3/common/common.h create mode 100644 practicas/practica3/libtcp/Makefile create mode 100644 practicas/practica3/libtcp/libtcp.c create mode 100644 practicas/practica3/libtcp/libtcp.h create mode 100644 practicas/practica3/parte1/Makefile create mode 100755 practicas/practica3/parte1/client create mode 100644 practicas/practica3/parte1/client.cpp create mode 100644 practicas/practica3/parte1/protocol.h create mode 100644 practicas/practica3/parte1/server.cpp create mode 100644 practicas/practica3/parte1/serverhandler.cpp diff --git a/practicas/practica3/Makefile b/practicas/practica3/Makefile new file mode 100644 index 0000000..8a2ef13 --- /dev/null +++ b/practicas/practica3/Makefile @@ -0,0 +1,19 @@ + +SUBDIRS=libtcp common parte1 + +.PHONY: clean +all clean: + @set fnord $(MAKEFLAGS); amf=$$2; target=$@ ; \ + dot_seen=no; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; + diff --git a/practicas/practica3/common/Makefile b/practicas/practica3/common/Makefile new file mode 100644 index 0000000..cfd0c27 --- /dev/null +++ b/practicas/practica3/common/Makefile @@ -0,0 +1,16 @@ + +TARGET=common.a +LIBS= +CFLAGS=-O0 -g +CC=g++ + +all: $(TARGET) + +$(TARGET): common.o + $(AR) cru $(TARGET) common.o + +common.o: common.h common.c + +.PHONY: clean +clean: + rm -f *.o $(TARGET) diff --git a/practicas/practica3/common/common.c b/practicas/practica3/common/common.c new file mode 100644 index 0000000..b933cc7 --- /dev/null +++ b/practicas/practica3/common/common.c @@ -0,0 +1,29 @@ +/* Released underOpen Software License v. 2.0 + * + * This Open Software License (the "License") applies to any original work of authorship + * (the "Original Work") whose owner (the "Licensor") has placed the following notice + * immediately following the copyright notice for the Original Work: + * + * Licensed under the Open Software License version 2.0 + * + * See http://www.opensource.org/licenses/osl-2.0.php or the LICENSE file for more + * details. + */ + +#include "common.h" +#include +#include +#include +#include + +void print_msg (FILE *fp, const char *fmt, ...) +{ + char linea[255]; + va_list va; + + va_start (va, fmt); + vsprintf(linea, fmt, va); + va_end (va); + + write (fileno (fp), linea, strlen (linea)); +} diff --git a/practicas/practica3/common/common.h b/practicas/practica3/common/common.h new file mode 100644 index 0000000..a6652af --- /dev/null +++ b/practicas/practica3/common/common.h @@ -0,0 +1,21 @@ +/* Released underOpen Software License v. 2.0 + * + * This Open Software License (the "License") applies to any original work of authorship + * (the "Original Work") whose owner (the "Licensor") has placed the following notice + * immediately following the copyright notice for the Original Work: + * + * Licensed under the Open Software License version 2.0 + * + * See http://www.opensource.org/licenses/osl-2.0.php or the LICENSE file for more + * details. + */ + +#ifndef _ECHO_COMMON_H_ +#define _ECHO_COMMON_H_ + +#include + +void print_msg (FILE *fp, const char *fmt, ...); + +#endif // _ECHO_COMMON_H_ + diff --git a/practicas/practica3/libtcp/Makefile b/practicas/practica3/libtcp/Makefile new file mode 100644 index 0000000..61c1501 --- /dev/null +++ b/practicas/practica3/libtcp/Makefile @@ -0,0 +1,17 @@ +# LibTcp - Internet stream version (TCP protocol) + +TARGET=libtcp.a +LIBS= +CFLAGS=-O0 -g +CC=g++ + +all: $(TARGET) + +$(TARGET): libtcp.o + $(AR) cru libtcp.a libtcp.o + +libtcp.o: libtcp.h libtcp.c + +.PHONY: clean +clean: + rm -f *.o $(TARGET) diff --git a/practicas/practica3/libtcp/libtcp.c b/practicas/practica3/libtcp/libtcp.c new file mode 100644 index 0000000..9421dc6 --- /dev/null +++ b/practicas/practica3/libtcp/libtcp.c @@ -0,0 +1,176 @@ +/* LibTcp - Released underOpen Software License v. 2.0 + * + * This Open Software License (the "License") applies to any original work of authorship + * (the "Original Work") whose owner (the "Licensor") has placed the following notice + * immediately following the copyright notice for the Original Work: + * + * Licensed under the Open Software License version 2.0 + * + * See http://www.opensource.org/licenses/osl-2.0.php or the LICENSE file for more + * details. + */ + +#include "libtcp.h" + +/** Abre un socket en modo activo para establecer una conexión con un servidor. + * + * Esta función es utilizada por los clientes para establecer una conexión TCP + * con un servidor. + * + * \param servidor Nombre del host server + * \param port Número del puerto + * \return >0 El descriptor del socket, si se conecto al servidor. + * \return -2 Si no existe el nombre del servidor. + * \return -1 Si hubo error en la conexion y se debe consultar errno. + */ +int libtcp_open_activo (const char *server, int port) +{ + int sockfd; /* socket de la conexion */ + struct sockaddr_in serv_addr; + struct hostent *ptr_server; /*puntero a dir del server(gethostbyname)*/ + + /* Borrar la estructura (poner en cero) */ + bzero ((char *) &serv_addr, sizeof(serv_addr)); + + /* Inicializo familia de direcciones (protocolo IP) */ + serv_addr.sin_family = AF_INET; + + /* Cargar port en el socket: Convertir Host-TO-Network-Short integer */ + serv_addr.sin_port = htons (port); + + /* Cargo dirección del server en el socket. Convertir nombre del host en su direccion */ + ptr_server = gethostbyname (server); + if (ptr_server == NULL) { + /* No existe nombre de host. Posible falla en resolución de nombre */ + return -2; + } + memcpy (&serv_addr.sin_addr, ptr_server->h_addr, ptr_server->h_length); + + /* Abro como un socket de TCP (Internet stream socket) */ + if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { + /* Error en la creacion del socket */ + return -1; + } + + if (connect (sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + /* TODO : Deberia ser un codigo de error diferente, asi puedo diferenciarlos */ + return -1; + } + + return sockfd; +} + +/** Abre un socket en modo pasivo usando protocolo TCP. + * + * La función se encarga de inicializar y crear el socket, y + * luego enlazarla con el SO. + * + * \param port Puerto sobre el cual atiende este servidor + * \return >0 El socket, si la operacion fue exitosa + * \return <0 Si hubo un error (ver errno) + */ +int libtcp_open_pasivo (int port) +{ + char mostrar[80]; /* mensajes en la pantalla */ + int sockfd; /* socket que sirve como template */ + struct sockaddr_in serv_addr; + + bzero ((char *)&serv_addr, sizeof (serv_addr)); + serv_addr.sin_family = AF_INET; /* Familia protocolos TCP/IP */ + serv_addr.sin_addr.s_addr = htonl (INADDR_ANY); /* Cualquier cliente */ + serv_addr.sin_port = htons ((u_short)port); /* Port en formato red */ + + /* Crea un socket para TCP (un Internet stream socket) */ + if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { + return -1; + } + + sprintf (mostrar, "LibTcp::ServerPasivo: socket creado %d\n", sockfd); + write (fileno(stdout), mostrar, strlen (mostrar)); + + /* Vincular el socket con la direccion local */ + if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) { + return -1; + } + + sprintf (mostrar, "LibTcp::Server: se hizo el bind\n"); + write(fileno(stdout), mostrar, strlen(mostrar)); + + /* Definir la cola de espera = hasta 5 clientes */ + listen(sockfd, 5); + + sprintf (mostrar, "LibTcp::Server: se hizo el listen con el socket %d\n", sockfd); + write(fileno(stdout), mostrar, strlen(mostrar)); + + return sockfd; +} + +/** Lee de a un byte por vez a un buffer hasta encontrar un "\n". + * + * La cadena leída es terminada en "\0". + * + * \return El tamaño, en caracteres, de la cadena leida. + * \param fd Descriptor del socket + * \param ptr Puntero al buffer + * \param maxlong Tamaño del buffer (en bytes) + * \TODO Soporte de caracteres multibyte + */ +int libtcp_receive (int fd, char *ptr, unsigned int maxlong) +{ + int n, car; + char c; + + for (n = 0; n < maxlong; n++) { + if ((car = read (fd, &c, sizeof (char))) == 1) { + *ptr++ = c; + if (c == '\n') + break; + } else if (car == 0) { + if (n == 1) + /* EOF, sin datos leidos */ + return 0; + else + break; /* EOF, se leyo algo */ + } else + return -1; + } + + *ptr = '\0'; + return n; +} + +/** Lee una informacion binaria */ +int libtcp_receive_bin (int fd, void *ptr, unsigned int maxlong) +{ + return read (fd, ptr, maxlong); +} + + +/** Escribe n bytes sobre un descriptor. + * + * Si no se escribieron n bytes, trata de repetir hasta que se hayan escrito + * los n bytes. + * + * Se debe usar esta funcion cuando el descriptor en un stream socket. + * + * \param fd Descriptor del socket + * \param ptr Puntero al mensaje + * \param n cantidad de bytes + */ +int libtcp_send (int fd, const char *ptr, unsigned int n) +{ + int nfaltan, nenviados; + + nfaltan = n; + while (nfaltan > 0) { + nenviados = write (fd, ptr, nfaltan); + if (nenviados <= 0) + return nenviados; + + nfaltan -= nenviados; + ptr += nenviados; + } + + return n - nfaltan; +} + diff --git a/practicas/practica3/libtcp/libtcp.h b/practicas/practica3/libtcp/libtcp.h new file mode 100644 index 0000000..83754c0 --- /dev/null +++ b/practicas/practica3/libtcp/libtcp.h @@ -0,0 +1,40 @@ +/* LibTcp - Released underOpen Software License v. 2.0 + * + * This Open Software License (the "License") applies to any original work of authorship + * (the "Original Work") whose owner (the "Licensor") has placed the following notice + * immediately following the copyright notice for the Original Work: + * + * Licensed under the Open Software License version 2.0 + * + * See http://www.opensource.org/licenses/osl-2.0.php or the LICENSE file for more + * details. + */ + +#ifndef _LIBTCP_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LIBTCP_DEFAULT_UDP_PORT 5000 +#define LIBTCP_DEFAULT_TCP_PORT 5000 + +extern int errno; + +int libtcp_open_activo (const char *server, int port); +int libtcp_open_pasivo (int port); +int libtcp_receive (int fd, char *ptr, unsigned int maxlong); +int libtcp_receive_bin (int fd, void *ptr, unsigned int maxlong); +int libtcp_send (int fd, const char *ptr, unsigned int n); + +#endif // _LIBTCP_COMMON_H_ + diff --git a/practicas/practica3/parte1/Makefile b/practicas/practica3/parte1/Makefile new file mode 100644 index 0000000..3ca38ce --- /dev/null +++ b/practicas/practica3/parte1/Makefile @@ -0,0 +1,27 @@ + +CLIENTE=client +SERVER_ITER=serverhandler +SERVER_REAL=server +LIBS=../libtcp/libtcp.a ../common/common.a +CFLAGS=-g -Wall -I../libtcp -I../common +CXXFLAGS=$(CFLAGS) +TARGET=$(CLIENTE) $(SERVER_ITER) $(SERVER_REAL) +CC=g++ + +all: $(TARGET) + +$(CLIENTE): client.o $(LIBS) + +client.o: client.cpp + +$(SERVER_ITER): serverhandler.o $(LIBS) + +serverhandler.o: serverhandler.cpp + +$(SERVER_REAL): server.o $(LIBS) + +server.o: server.cpp + +.PHONY: clean +clean: + rm -f *.o $(TARGET) diff --git a/practicas/practica3/parte1/client b/practicas/practica3/parte1/client new file mode 100755 index 0000000000000000000000000000000000000000..a4bf073056b76acc1d2900b40ca0375ef90c1528 GIT binary patch literal 56217 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 +#include +#include + +int main(int argc, char *argv[]) +{ + int sockfd; + int client_id; + char *server_name; + char *localhost = "localhost"; + pid_t pid; + int port; + const char *pname = argv[0]; + + // mostrar el pid del cliente + pid = getpid(); + print_msg(stdout, "%s Cliente con pid = %d\n", pname, pid); + + // Verifico parametros de linea de comandos + if (argc > 2) + port = atoi (argv[2]); + else + port = LIBTCP_DEFAULT_TCP_PORT; + + if (port <= 0) + { + // valor incorrecto: aviso y terminar + print_msg(stdout, "%s (%d): Nro. de port invalido %d\n", pname, pid, port); + exit(1); + } + + if (argc > 1) + server_name = argv[1]; + else + server_name = localhost; + + // id del cliente, por default calculado en base al pid + if (argc > 3) + client_id = atoi(argv[3]); + else + client_id = pid % 32; + + // Abro el socket + sockfd = libtcp_open_activo(server_name, port); + if (sockfd < 0) + { + // ERROR + if (sockfd == -2) + { + print_msg(stdout, "%s (%d): Nombre de server no existe %s\n", pname, pid, server_name); + exit(1); + } + else + { + perror("Error al llamar a libtcp_open_activo"); + exit(1); + } + } + + std::string line; + Protocol::Type type; + while (std::getline(std::cin, line)) + { + std::istringstream iss(line); + std::string token; + if (!(iss >> token)) return 0; + if (token == "put") + { + type = Protocol::PUT; + } + else if (token == "find") + { + type = Protocol::FIND; + } + else if (token == "del") + { + type = Protocol::DEL; + } + else + { + print_msg(stderr, "%s (%d): Invalid token %s!\n", pname, pid, token.c_str()); + exit(1); + } + while (iss >> token) + { + Protocol proto(type, 0, client_id, token.size()); + print_msg(stdout, "%s (%d): escribiendo %s\n", pname, pid, token.c_str()); + if (libtcp_send(sockfd, (char*) &proto, sizeof(Protocol)) != sizeof(Protocol) + || libtcp_send(sockfd, token.c_str(), token.size()) != token.size()) + { + print_msg(stderr, "%s (%d): error en envio sobre el socket\n", pname, pid); + exit(1); + } + } + Protocol proto(type, 1, client_id, 0); + if (libtcp_send(sockfd, (char*) &proto, sizeof(Protocol)) != sizeof(Protocol)) + { + print_msg(stderr, "%s (%d): error en envio sobre el socket\n", pname, pid); + exit(1); + } + // Esperando respuesta del servidor con el resultado + int response; + int n = libtcp_receive(sockfd, (char*) &response, sizeof(response)); + if (n < 0) + { + print_msg(stderr, "%s (%d): error en recibir\n", pname, pid); + } + else + { + print_msg(stdout, "%s (%d): el server responde %d\n", pname, pid, response); + } + } + + Protocol proto(Protocol::QUIT, 1, client_id, 0); + if (libtcp_send(sockfd, (char*) &proto, sizeof(Protocol)) != sizeof(Protocol)) + { + print_msg(stderr, "%s (%d): error en envio sobre el socket\n", pname, pid); + exit(1); + } + + /* Limpio y salgo */ + close(sockfd); + return EXIT_SUCCESS; +} + +// vim: set et sw=4 sts=4 : diff --git a/practicas/practica3/parte1/protocol.h b/practicas/practica3/parte1/protocol.h new file mode 100644 index 0000000..f64a8b0 --- /dev/null +++ b/practicas/practica3/parte1/protocol.h @@ -0,0 +1,23 @@ +#ifndef _PROTOCOL_H_ +#define _PROTOCOL_H_ + +struct Protocol +{ + enum Type { PUT, FIND, DEL, QUIT }; + enum Result { OK, NOT_FOUND, EXISTS }; + + unsigned char type: 2; // 2 bits para tipo + unsigned char end: 1; // 1 bit para marca de FIN + unsigned char client_id: 5; // 5 bits para id de cliente + unsigned char len; // 255 máximo + + Protocol() {} + + Protocol(unsigned type, unsigned end, unsigned client_id, unsigned len): + type(type), end(end), client_id(client_id), len(len) {} + +}; + +#endif // _PROTOCOL_H_ + +// vim: set et sw=4 sts=4 : diff --git a/practicas/practica3/parte1/server.cpp b/practicas/practica3/parte1/server.cpp new file mode 100644 index 0000000..b445c0e --- /dev/null +++ b/practicas/practica3/parte1/server.cpp @@ -0,0 +1,85 @@ +/* + * Server concurrente usando protocolo TCP para manipular un set. + */ + +#include "libtcp.h" +#include "common.h" +#include + +void fin_hijos(int); + +int main (int argc, char *argv[]) +{ + static char el_socket[15]; /* string que contiene el socket para el servidor de eco */ + + int sockfd; /* socket que sirve como template */ + int newsockfd; /* socket conectado al cliente */ + int port; + unsigned int clilen; /* longitud dir. cliente */ + unsigned int childpid; /* pid del hijo */ + struct sockaddr_in cli_addr; + + /* Verifico parametros de linea de comandos */ + if (argc > 1) + port = atoi(argv[1]); + else + port = LIBTCP_DEFAULT_TCP_PORT; + + + /* Inicia Servidor - Open Pasivo */ + if ((sockfd = libtcp_open_pasivo(port)) < 0) + { + perror("Server: no se puede abrir el stream socket"); + exit(1); + } + + print_msg(stdout, "server: se hizo el open pasivo, socket %d\n", sockfd); + + signal(SIGCHLD, fin_hijos); + + /* PROCESAMIENTO DEL SERVER */ + while (1) + { + clilen = sizeof(cli_addr); + newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); + if (newsockfd < 0) + { + perror("server: error en el accept"); + exit(1); + } + + if ((childpid = fork()) < 0) + { + perror("server: error en el fork"); + exit(1); + } + else if (childpid == 0) + { + /* PROCESO HIJO (child) que atiende al cliente */ + close(sockfd); /* cerramos socket original */ + + print_msg(stdout, "server: socket armado con un cliente %d\n", newsockfd); + + /* pasarle el socket al hijo que atiende */ + sprintf(el_socket, "%d\n", newsockfd); + + /* Se lanza el proceso que atiende a ese cliente */ + execlp("./serverhandler", "./serverhandler", el_socket, (char *)0); + perror("Server: error al lanzar el handler del servidor."); + exit(3); + } + + /* PROCESO PADRE, se prepara para recibir otro cliente */ + /* cerrar el socket pasado al hijo */ + close(newsockfd); + } +} + +/** Elimina Procesos-hijos que terminaron */ +void fin_hijos(int) +{ + union wait status; + while (wait3((int *)&status, WNOHANG, (struct rusage *)0) >= 0); +} + +// vim: set et sw=4 sts=4 : diff --git a/practicas/practica3/parte1/serverhandler.cpp b/practicas/practica3/parte1/serverhandler.cpp new file mode 100644 index 0000000..d21a327 --- /dev/null +++ b/practicas/practica3/parte1/serverhandler.cpp @@ -0,0 +1,111 @@ +/* + * Servidor de hash + */ + +#include "libtcp.h" +#include "common.h" +#include "protocol.h" +#include +#include +#include + +int main(int argc, char *argv[]) +{ + char *pname; + int sockfd;/* socket que sirve como template */ + pid_t pid; /* pid del server iterativo */ + char linea[256]; + char fin = 0, fin_cmd = 0; + int result = 0; + std::set< std::string > set; + + pname = argv[0]; + pid = getpid(); + + /* Verifico parametros de linea de comando */ + if (argc > 1) + sockfd = atoi(argv[1]); + else + { + perror("Falta parametro con fd"); + exit (1); + } + + print_msg(stdout, "%s (%d): atendiendo a cliente por socket %d\n", pname, pid, sockfd); + + while (!fin) + { + std::string buffer; + while (!fin_cmd) + { + Protocol proto; + int n = libtcp_receive_bin(sockfd, (char*) &proto, sizeof(Protocol)); + if (n < 0) + { + print_msg(stdout, "%s (%d): error en recibir\n", pname, pid); + exit(1); + } + print_msg(stdout, "%s (%d): cliente %d envio operacion (%d, %d, %d)\n", + pname, pid, proto.client_id, proto.type, proto.end, proto.len); + + n = libtcp_receive_bin(sockfd, linea, proto.len); + if (n < 0) + { + print_msg(stdout, "%s (%d): error en recibir\n", pname, pid); + exit(1); + } + linea[proto.len] = '\0'; + print_msg(stdout, "%s (%d): se recibieron %d bytes de payload (%s)\n", + pname, pid, proto.len, linea); + buffer += linea; + print_msg(stdout, "%s (%d): buffer: %s\n", pname, pid, buffer.c_str()); + + if (proto.end) + { + switch (proto.type) + { + case Protocol::PUT: + if (set.find(buffer) == set.end()) + { + set.insert(buffer); + result = Protocol::OK; + } + else + result = Protocol::EXISTS; + break; + case Protocol::FIND: + if (set.find(buffer) == set.end()) + result = Protocol::NOT_FOUND; + else + result = Protocol::OK; + break; + case Protocol::DEL: + if (set.erase(buffer)) + result = Protocol::OK; + else + result = Protocol::NOT_FOUND; + break; + case Protocol::QUIT: + print_msg(stdout, "%s (%d): Say no more\n", pname, pid); + fin = 1; + fin_cmd = 1; + break; + default: + print_msg(stderr, "%s (%d): Operacion no soportada\n", pname, pid); + } + buffer.clear(); + fin_cmd = 1; + } + } + fin_cmd = 0; + + // Envío respuesta + libtcp_send(sockfd, (char*) &result, sizeof(int)); + print_msg(stdout, "%s (%d) FIN (resultado = %d)\n", pname, pid, result); + } + + close(sockfd); + +} + +// vim: set et sw=4 sts=4 : -- 2.43.0