From b445e7ac7a89f2396ec1000802a5fddf14200408 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Fri, 10 Feb 2023 13:38:29 +0100 Subject: [PATCH] clients comming and leaving messages ok --- a.out | Bin 16568 -> 16816 bytes mini_serv.c | 98 ++++++++++++--- mini_serv_eric.c | 143 +++++++++++++++++++++ mini_serv_luke.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 539 insertions(+), 18 deletions(-) create mode 100644 mini_serv_eric.c create mode 100644 mini_serv_luke.c diff --git a/a.out b/a.out index d6d0239c7bfd88650d9e4985ffacdb8a8e900093..7605ae2f9fdd426e95d2a9112e20f13f3b15d7f1 100755 GIT binary patch literal 16816 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 literal 16568 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 NK5uEvb{V)t@h>F^`Tzg` diff --git a/mini_serv.c b/mini_serv.c index 8cca707..c9aee6d 100644 --- a/mini_serv.c +++ b/mini_serv.c @@ -5,6 +5,8 @@ #include #include #include +#include //sprintf + // accept // atoi @@ -31,12 +33,8 @@ #define BUFSIZE 1024 -void putstr(int fd, char *str) { - write(fd, str, strlen(str)); -} - void error(char *str) { - putstr(2, str); + write(2, str, strlen(str)); exit(1); } @@ -44,50 +42,114 @@ int init_socket(struct sockaddr_in *addr, int len, int port) { int server_fd; if ( (server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) - error("Fatal error\n"); + error("Fatal error2\n"); bzero(addr, len); addr->sin_family = AF_INET; addr->sin_addr.s_addr = htonl(2130706433); //127.0.0.1 addr->sin_port = htons(port); if (bind(server_fd, (const struct sockaddr *)addr, len) == -1) - error("Fatal error\n"); + error("Fatal error3\n"); if (listen(server_fd, 10) == -1) - error("Fatal error\n"); + error("Fatal error4\n"); return server_fd; } +void broadcast(char *buf, fd_set *set, int max_fd, int server_fd, int sender_fd) { + write(1, "---\n", 4); + for(int i = 0; i <= max_fd; ++i) { + printf("[%d]\n", i); + if (i == server_fd) + { + write(1, "is server\n", 10); + continue; + } + if (i == sender_fd) + { + write(1, "is sender\n", 10); + continue; + } + if (FD_ISSET(i, set)) + { + send(i, buf, strlen(buf), 0); + write(1, buf, strlen(buf)); + } + } +} + int main(int ac, char **av) { int port; int server_fd; int client_fd; + int max_fd; + int client_id; char buf[BUFSIZE]; struct sockaddr_in addr; socklen_t addr_len; fd_set fdset; + fd_set rdset; + int clients[FD_SETSIZE]; + int ret; if (ac != 2) error("Wrong number of arguments\n"); if ( (port = atoi(av[1])) == -1) - error("Fatal error\n"); + error("Fatal error1\n"); addr_len = sizeof(addr); server_fd = init_socket(&addr, addr_len, port); + FD_ZERO(&fdset); + FD_SET(server_fd, &fdset); + max_fd = server_fd; + client_id = 0; +/* +*/ while (1) { - if ( (client_fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len)) == -1) - error("Fatal error\n"); - FD_ZERO(&fdset); - FD_SET(client_fd, &fdset); - select(client_fd + 1, &fdset, NULL, NULL, NULL); - if (FD_ISSET(client_fd, &fdset)) - recv(client_fd, buf, BUFSIZE, 0); - // "server: client %d just arrived\n" +// FD_ZERO(&rdset); + rdset = fdset; + + select(max_fd + 1, &rdset, NULL, NULL, NULL); + + // new connection + if (FD_ISSET(server_fd, &rdset)) + { + client_fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len); + FD_SET(client_fd, &fdset); + clients[client_fd] = client_id; + if (client_fd > max_fd) + max_fd = client_fd; + sprintf(buf, "server: client %d just arrived\n", client_id); + broadcast(buf, &fdset, max_fd, server_fd, client_fd); + client_id++; + } + + // new message + client_fd = 0; + while(client_fd <= max_fd) { + ret = 1; + if (FD_ISSET(client_fd, &rdset)) + ret = recv(client_fd, buf, BUFSIZE, 0); + if (ret == 0) { + sprintf(buf, "server: client %d just left\n", clients[client_fd]); + write(1, buf, strlen(buf)); + broadcast(buf, &fdset, max_fd, server_fd, client_fd); + FD_CLR(client_fd, &fdset); + } + else { + sprintf(buf, "client %d: %s\n", clients[client_fd], buf); + write(1, buf, strlen(buf)); + broadcast(buf, &fdset, max_fd, server_fd, client_fd); + } + client_fd++; + } + + // "client %d: " // "server: client %d just left\n" - //while () } + return (0); } diff --git a/mini_serv_eric.c b/mini_serv_eric.c new file mode 100644 index 0000000..84cf340 --- /dev/null +++ b/mini_serv_eric.c @@ -0,0 +1,143 @@ +// #include +#include +#include +#include +#include +#include +#include +#include + +typedef struct s_clients { + int id; + char msg[1024]; +} t_clients; + +// so we just have a table of clients, no need to worry about linked lists, yea sounds good to me +t_clients clients[1024]; // 1024 otherwise would have to change FD_SETSIZE and why bother +fd_set readfds, writefds, active; +int fd_Max = 0; +int id_Next = 0; +char bufread[120000]; +char bufwrite[120000]; + +void ft_error(char *str) +{ + // 2 is stderr i guess + if (str) + write(2, str, strlen(str)); + else + write(2, "Fatal error", strlen("Fatal error")); + write(2, "\n", 1); + exit(1); +} + +// not is the fd that send the message meaning you should not send that message to that fd +void send_to_all(int not) +{ + for(int i = 0; i <= fd_Max; i++) + { + // have to check cuz we use an array not a linked list + if (FD_ISSET(i, &writefds) && i != not) + send(i, bufwrite, strlen(bufwrite), 0); // man send explains things well + } +} + + +int main(int ac, char **av) +{ + + if (ac != 2) + ft_error("Wrong number of arguments"); + + // just like in main.c + // all this is explained in the man socket, cool + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) + ft_error(NULL); + + // like bzeroing i guess but for the struct fd_set, yea it clears the set, none are active + FD_ZERO(&active); + // i think this gets all the contents of the structs as well ? yes cuz it's an array not a linked list so easy to bzero + bzero(&clients, sizeof(clients)); + fd_Max = sockfd; // not sure what that does, none of this is in main.c + FD_SET(sockfd, &active); // we add sockfd to active, ok cool + + struct sockaddr_in servaddr; // like in main.c + socklen_t len; // not in main.c, i mean it kinda is but i prefer doing it this way, not even that important + bzero(&servaddr, sizeof(servaddr)); // in main.c + servaddr.sin_family = AF_INET; // like main.c + servaddr.sin_addr.s_addr = htonl(2130706433); // like main.c + servaddr.sin_port = htons(atoi(av[1])); // slightly different than main.c cuz have to get the right port + + // just like main.c, we bind and listen, normal stuff that requres specific numbers + if ((bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr))) < 0) + ft_error(NULL); + if (listen(sockfd, 10) < 0) + ft_error(NULL); + + // no longer like main.c + while(1) + { + readfds = active; + writefds = active; + + // so like if it didn't add a new one? it continues? yea idk something about making sure select has happened + if (select(fd_Max + 1, &readfds, &writefds, NULL, NULL) < 0) + continue; + + // we cycle through all the FDs we've assigned at one point so far (they may not all be active) + for (int fd_i = 0; fd_i <= fd_Max; fd_i++) + { + // for each one we check if it's set, and check if is or isn't sockfd + // ohhh this is if a client just arrived + if (FD_ISSET(fd_i, &readfds) && fd_i == sockfd) + { + // try to accept a new connection + int connfd = accept(sockfd, (struct sockaddr*)&servaddr, &len); // more or less in main.c + if (connfd < 0) + continue; // non blocking but this one didn't work + // reset fd_max + fd_Max = connfd > fd_Max ? connfd : fd_Max; // whichever is larger is the new max + clients[connfd].id = id_Next++; // we add the new client + FD_SET(connfd, &active); // add it to the list + sprintf(bufwrite, "server: client %d just arrived\n", clients[connfd].id); // create message to send out + send_to_all(connfd); + break; + } + // things other than a new connection i guess + if (FD_ISSET(fd_i, &readfds) && fd_i != sockfd) + { + // 65536 is just a big number i think + int res = recv(fd_i, bufread, 65536, 0); // similar to send, also see man recv, it's good + // something happened to a client so we tell the others this one is gone and handle clears and prevent leaks and such + if (res <= 0) // -1 is error and 0 is end of file + { + sprintf(bufwrite, "server: client %d just left\n", clients[fd_i].id); + send_to_all(fd_i); + FD_CLR(fd_i, &active); + close(fd_i); + break; + } + else + { + // we read the whole message we just received and then send it out + for(int i = 0, j = strlen(clients[fd_i].msg); i < res; i++, j++) + { + clients[fd_i].msg[j] = bufread[i]; + if (clients[fd_i].msg[j] == '\n') + { + clients[fd_i].msg[j] = '\0'; + sprintf(bufwrite, "client %d: %s\n", clients[fd_i].id, clients[fd_i].msg); + send_to_all(fd_i); + bzero(clients[fd_i].msg, strlen(clients[fd_i].msg)); + j = -1; // becomes 0 right after this at the end of the loop, i think + } + } + break; + } + } + } + } + + return (0); +} diff --git a/mini_serv_luke.c b/mini_serv_luke.c new file mode 100644 index 0000000..b44da10 --- /dev/null +++ b/mini_serv_luke.c @@ -0,0 +1,316 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // debug + +/////////// +struct s_client +{ + int fd; + int id; + struct s_client *next; +} typedef t_client; + +t_client *g_clients = NULL; +int g_id = 0; +int lsocket = -1; +fd_set rfds; +fd_set wfds; +//////////// +int extract_message(char **buf, char **msg); +char *str_join(char *buf, char *add); + +void init(int port); +t_client *new_client(int fd); +t_client *close_client(t_client *client_to_close); +void broadcast(t_client *client, char *str); +int read_client(t_client *client); +void free_all(); +void fatal_error(); +ssize_t ft_print(int fd, char *buf); +//////////// + +int main(int argc, char** argv) +{ + // int count = 0; // force exit debug + int fd_max; + t_client *clients; + int new_fd; + int client_id; + t_client *last_connected; + char announce_msg[420]; + int ret; + + if (argc != 2) { + ft_print(STDERR_FILENO, "Wrong number of arguments\n"); + exit(1); + } + init(atoi(argv[1])); + fcntl(lsocket, F_SETFL, O_NONBLOCK); // debug + + while (1) + { + // reset rfds and wfds + fd_max = lsocket; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_SET(lsocket, &rfds); + clients = g_clients; + while (clients) + { + if (clients->fd > fd_max) + fd_max = clients->fd; + FD_SET(clients->fd, &rfds); + FD_SET(clients->fd, &wfds); + clients = clients->next; + } + + // multiplexing (select) + select(fd_max + 1, &rfds, &wfds, NULL, NULL); + + // accept new connection + if (FD_ISSET(lsocket, &rfds)) + { + new_fd = accept(lsocket, NULL, NULL); + fcntl(new_fd, F_SETFL, O_NONBLOCK); // debug + last_connected = new_client(new_fd); + sprintf(announce_msg, "server: client %d just arrived\n", last_connected->id); + broadcast(last_connected, announce_msg); + + // debug + // ++count; + // printf("count: %d\n", count); + // if (count == 7) + // break; + } + + // read incoming clients messages + clients = g_clients; + while (clients) + { + ret = 1; + if (FD_ISSET(clients->fd, &rfds)) + ret = read_client(clients); + + if (ret == 0) + { + client_id = clients->id; + clients = close_client(clients); + sprintf(announce_msg, "server: client %d just left\n", client_id); + broadcast(NULL, announce_msg); + } + else + clients = clients->next; + } + } + + free_all(); + return (0); +} + +void init(int port) +{ + struct sockaddr_in servaddr; + + lsocket = socket(AF_INET, SOCK_STREAM, 0); + if (lsocket == -1) + fatal_error(); + + bzero(&servaddr, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(2130706433); //127.0.0.1 + servaddr.sin_port = htons(port); + + if (bind(lsocket, (const struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) + fatal_error(); + if (listen(lsocket, 10) != 0) + fatal_error(); +} + +t_client *new_client(int fd) +{ + t_client *new; + + new = calloc(1, sizeof (t_client)); + if (!new) + fatal_error(); + new->fd = fd; + new->id = g_id++; + + if (!g_clients) + g_clients = new; + else + { + t_client *last = g_clients; + while (last->next) + last = last->next; + last->next = new; + } + return (new); +} + + +t_client *close_client(t_client *client_to_close) +{ + t_client *next_client = client_to_close->next; + t_client *clients = g_clients; + + if (g_clients == client_to_close) + { + g_clients = next_client; + } + else + { + while (clients->next != client_to_close) + clients = clients->next; + clients->next = next_client; + } + close(client_to_close->fd); + free(client_to_close); + return (next_client); +} + +void broadcast(t_client *client, char *str) +{ + t_client *clients = g_clients; + + while (clients) + { + if (clients != client && FD_ISSET(clients->fd, &wfds)) + { + send(clients->fd, str, strlen(str), 0); + } + clients = clients->next; + } +} + +int read_client(t_client *client) +{ + char *buf; + int recv_ret; + + buf = malloc(420000); + if (!buf) + fatal_error(); + + recv_ret = recv(client->fd, buf, 420000, 0); + if (recv_ret > 0) + { + buf[recv_ret] = '\0'; + if (recv_ret == 420000) // debug + ft_print(STDERR_FILENO, "Oupsi, ca depasse. Il faut malloc mon petit\n"); + + char buf_sprintf[420]; + char *msg; + char *final_msg; + int ret = 1; + while (ret == 1) + { + msg = NULL; + ret = extract_message(&buf, &msg); + if (ret == -1) + { + free(buf); + fatal_error(); + } + if (!msg) + msg = buf; + if (msg && msg[0] != 0) + { + sprintf(buf_sprintf, "client %d: ", client->id); + final_msg = str_join(buf_sprintf, msg); + free(msg); + if (!final_msg) + { + free(buf); + fatal_error(); + } + broadcast(client, final_msg); + free(final_msg); + } + else + free(msg); + } + } + else + { + free(buf); + } + + return (recv_ret); +} + +void free_all() +{ + if (lsocket != -1) + close(lsocket); + while (g_clients) + close_client(g_clients); +} + +void fatal_error() +{ + ft_print(STDERR_FILENO, "Fatal error\n"); + free_all(); + exit(1); +} + +ssize_t ft_print(int fd, char *buf) +{ + return write(fd, buf, strlen(buf)); +} + +// Base example function +int extract_message(char **buf, char **msg) +{ + char *newbuf; + int i; + + *msg = 0; + if (*buf == 0) + return (0); + i = 0; + while ((*buf)[i]) + { + if ((*buf)[i] == '\n') + { + newbuf = calloc(1, sizeof(*newbuf) * (strlen(*buf + i + 1) + 1)); + if (newbuf == 0) + return (-1); + strcpy(newbuf, *buf + i + 1); + *msg = *buf; + (*msg)[i + 1] = 0; + *buf = newbuf; + return (1); + } + i++; + } + return (0); +} + +// Base example function, minus the commented free() +char *str_join(char *buf, char *add) +{ + char *newbuf; + int len; + + if (buf == 0) + len = 0; + else + len = strlen(buf); + newbuf = malloc(sizeof(*newbuf) * (len + strlen(add) + 1)); + if (newbuf == 0) + return (0); + newbuf[0] = 0; + if (buf != 0) + strcat(newbuf, buf); + // free(buf); + strcat(newbuf, add); + return (newbuf); +}