Mercurial > public > hey
changeset 10:fd707ca47dd0
convert project to simple TCP server client app
author | Dennis <dennisconcepcionmartin@gmail.com> |
---|---|
date | Wed, 19 Jul 2023 18:40:47 +0100 |
parents | ae1a84916424 |
children | 827460e58a24 |
files | CMakeLists.txt src/client/CMakeLists.txt src/client/main.c src/main.c src/server/CMakeLists.txt src/server/main.c |
diffstat | 6 files changed, 202 insertions(+), 149 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Tue Jul 18 20:06:11 2023 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -cmake_minimum_required(VERSION 3.1) -project(hey - VERSION 1.0 - LANGUAGES C -) - -add_executable(hey src/main.c)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/client/CMakeLists.txt Wed Jul 19 18:40:47 2023 +0100 @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.1) +project(hey-client + VERSION 1.0 + LANGUAGES C +) + +add_executable(hey_client main.c)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/client/main.c Wed Jul 19 18:40:47 2023 +0100 @@ -0,0 +1,71 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <netdb.h> +#include <string.h> +#include <sys/socket.h> +#include <unistd.h> + +#define MAX_MSG_SIZE 1000 + + +int main(int argc, char *argv[]) { + if (argc != 3) { + printf("Invalid arguments: hostname port\n"); + exit(1); + } + + char *hostname = argv[1]; + char *port = argv[2]; + struct addrinfo hints; + struct addrinfo *service_info; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + if ((getaddrinfo(hostname, port, &hints, &service_info)) != 0) { + perror("getaddrinfo"); + exit(1); + } + + int clientfd = socket(service_info->ai_family, service_info->ai_socktype, service_info->ai_protocol); + if (clientfd == -1) { + perror("socket"); + } + + if (connect(clientfd, service_info->ai_addr, service_info->ai_addrlen) == -1) { + perror("connect"); + exit(1); + } + + freeaddrinfo(service_info); + printf("Connection established\n"); + + char msg[MAX_MSG_SIZE]; + bool connected = true; + + while (connected) { + printf("Enter command: "); + fgets(msg, MAX_MSG_SIZE, stdin); + msg[strcspn(msg, "\n")] = 0; + + if (strcmp(msg, "exit") == 0) { + break; + } + + ssize_t bytes_sent = send(clientfd, msg, strlen(msg), 0); + if (bytes_sent == -1) { + perror("send"); + exit(1); + } + + printf("%zd bytes sent\n", bytes_sent); + memset(&msg, 0, sizeof(msg)); + } + + close(clientfd); + + return 0; +}
--- a/src/main.c Tue Jul 18 20:06:11 2023 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,142 +0,0 @@ -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/wait.h> -#include <netdb.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <time.h> -#include <errno.h> - - -int listenfd; - -void sigint_handler(int sig_num) { - printf("\nClosing socket\n"); - close(listenfd); - exit(0); -} - -void sigchld_handler(int s) { - int saved_errno = errno; - while(waitpid(-1, NULL, WNOHANG) > 0); - errno = saved_errno; -} - -// Get IPv4 or IPv6 -struct IpPort { - char ipstr[INET6_ADDRSTRLEN]; - unsigned short port; -}; - -struct IpPort get_ipport(struct sockaddr *sa) { - struct IpPort ipport; - - if (sa->sa_family == AF_INET) { - struct sockaddr_in *ipv4 = (struct sockaddr_in *)sa; - inet_ntop(AF_INET, &(ipv4->sin_addr), ipport.ipstr, sizeof(ipport.ipstr)); - ipport.port = ntohs(ipv4->sin_port); - } else { - struct sockaddr_in *ipv6 = (struct sockaddr_in *)sa; - inet_ntop(AF_INET, &(ipv6->sin_addr), ipport.ipstr, sizeof(ipport.ipstr)); - ipport.port = ntohs(ipv6->sin_port); - } - - return ipport; -} - -int main() { - signal(SIGINT, sigint_handler); - - struct addrinfo hints; - struct addrinfo *servinfo; - - memset(&hints, 0, sizeof hints); // Make sure the struct is empty - hints.ai_family = AF_UNSPEC; // Don't care IPv4 or IPv6 - hints.ai_socktype = SOCK_STREAM; // TCP stream sockets - hints.ai_flags = AI_PASSIVE; // Fill in my IP for me - - if ((getaddrinfo(NULL, "5050", &hints, &servinfo)) != 0) { - perror("getaddrinfo: "); - exit(1); - } - - listenfd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol); - if (listenfd == -1) { - perror("socket: "); - exit(1); - } - - // Avoid "Address already in use" - int yes = 1; - if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { - perror("setsockopt: \n"); - } - - if (bind(listenfd, servinfo->ai_addr, servinfo->ai_addrlen) == -1) { - perror("bind: "); - exit(1); - } - - freeaddrinfo(servinfo); - - if (listen(listenfd, 10) == -1) { - perror("listen: "); - exit(1); - } - - // Kill zombie child processes - struct sigaction sig; - sig.sa_handler = sigchld_handler; - sigemptyset(&sig.sa_mask); - sig.sa_flags = SA_RESTART; - if (sigaction(SIGCHLD, &sig, NULL) == -1) { - perror("sigaction: \n"); - exit(1); - } - - struct IpPort server_ipport = get_ipport(servinfo->ai_addr); - printf("Server IP: %s\n", server_ipport.ipstr); - printf("Listening on port: %u\n", server_ipport.port); - - char send_buffer[100]; - struct sockaddr_storage clientinfo; - socklen_t clientinfo_size; - printf("Waiting for connections...\n"); - - while (1) { - int connfd = accept(listenfd, (struct sockaddr *)&clientinfo, &clientinfo_size); - if (connfd == -1) { - perror("accept: \n"); - exit(1); - } - - struct IpPort client_ipport = get_ipport((struct sockaddr *)&clientinfo); - printf("Client IP: %s\n", client_ipport.ipstr); - printf("Client port: %u\n", client_ipport.port); - - int pid = fork(); - if (pid == 0) { - // This is child - close(listenfd); - time_t now = time(NULL); - snprintf(send_buffer, sizeof(send_buffer), "Server time: %s\n", ctime(&now)); - - if (send(connfd, send_buffer, sizeof(send_buffer), 0) == -1) { - perror("send: \n"); - } - - close(connfd); - exit(0); - } - - close(connfd); - } - - return 0; -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/CMakeLists.txt Wed Jul 19 18:40:47 2023 +0100 @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.1) +project(hey-server + VERSION 1.0 + LANGUAGES C +) + +add_executable(hey_server main.c)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/main.c Wed Jul 19 18:40:47 2023 +0100 @@ -0,0 +1,117 @@ +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <netdb.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <time.h> +#include <errno.h> + +#define MAX_MSG_SIZE 1000 + + +// Get IPv4 or IPv6 +struct IpPort { + char ipstr[INET6_ADDRSTRLEN]; + unsigned short port; +}; + +struct IpPort get_ipport(struct sockaddr *sa) { + struct IpPort ipport; + + if (sa->sa_family == AF_INET) { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)sa; + inet_ntop(AF_INET, &(ipv4->sin_addr), ipport.ipstr, sizeof(ipport.ipstr)); + ipport.port = ntohs(ipv4->sin_port); + } else { + struct sockaddr_in *ipv6 = (struct sockaddr_in *)sa; + inet_ntop(AF_INET, &(ipv6->sin_addr), ipport.ipstr, sizeof(ipport.ipstr)); + ipport.port = ntohs(ipv6->sin_port); + } + + return ipport; +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + printf("Invalid arguments: port\n"); + exit(1); + } + + char *port = argv[1]; + struct addrinfo hints; + struct addrinfo *service_info; + + memset(&hints, 0, sizeof hints); // Make sure the struct is empty + hints.ai_family = AF_UNSPEC; // Don't care IPv4 or IPv6 + hints.ai_socktype = SOCK_STREAM; // TCP stream sockets + hints.ai_flags = AI_PASSIVE; // Fill in my IP for me + + if ((getaddrinfo(NULL, port, &hints, &service_info)) != 0) { + perror("getaddrinfo: "); + exit(1); + } + + int listenfd = socket(service_info->ai_family, service_info->ai_socktype, service_info->ai_protocol); + if (listenfd == -1) { + perror("socket: "); + exit(1); + } + + if (bind(listenfd, service_info->ai_addr, service_info->ai_addrlen) == -1) { + perror("bind: "); + exit(1); + } + + + if (listen(listenfd, 10) == -1) { + perror("listen: "); + exit(1); + } + + struct IpPort server_ipport = get_ipport(service_info->ai_addr); + printf("%s listening on port %u\n", server_ipport.ipstr, server_ipport.port); + + freeaddrinfo(service_info); + + struct sockaddr_storage clientinfo; + socklen_t clientinfo_size; + printf("Waiting for connections...\n"); + + int connfd = accept(listenfd, (struct sockaddr *)&clientinfo, &clientinfo_size); + if (connfd == -1) { + perror("accept: \n"); + exit(1); + } + + struct IpPort client_ipport = get_ipport((struct sockaddr *)&clientinfo); + printf("Connection from %s:%u\n", client_ipport.ipstr, client_ipport.port); + + char msg[MAX_MSG_SIZE]; + + while (1) { + int recv_status = recv(connfd, &msg, sizeof(msg), 0); + if (recv_status == -1) { + perror("recv: %s\n"); + exit(1); + } else if (recv_status == 0) { + printf("Client closed connection\n"); + break; + } else { + printf("Client: %s\n", msg); + } + + memset(&msg, 0, sizeof(msg)); + } + + close(connfd); + close(listenfd); + + return 0; +} +