From 81488417d97dd0b45fad9706086f23c2f2e06d30 Mon Sep 17 00:00:00 2001 From: Colton Staiduhar Date: Sun, 26 Apr 2026 12:14:31 -0400 Subject: [PATCH] Working Server and Client --- .gitignore | 3 +- court.c | 4 +- game.h | 9 +-- main.c | 143 +++++++++++++++++++++++++++++++++++++------ network/networking.c | 88 ++++++++++++++++++++++++++ network/networking.h | 26 ++++++++ 6 files changed, 248 insertions(+), 25 deletions(-) create mode 100644 network/networking.c create mode 100644 network/networking.h diff --git a/.gitignore b/.gitignore index f9dfa2f..0ec6e3b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.o netpong -netpong.dSYM/ \ No newline at end of file +netpong.dSYM/ +netpong.c diff --git a/court.c b/court.c index 465466c..c0589a9 100644 --- a/court.c +++ b/court.c @@ -6,7 +6,7 @@ #include #include -void DrawWalls(struct GameData data) +void DrawWalls(GameData data) { for (int i = LEFT_COL; i <= RIGHT_COL; i++) { move(TOP_ROW, i); @@ -25,7 +25,7 @@ void DrawWalls(struct GameData data) refresh(); } -void DrawHeader(struct GameData data) +void DrawHeader(GameData data) { move(TOP_ROW - 2, LEFT_COL); addch('P'); diff --git a/game.h b/game.h index 0aed6ff..e1719f6 100644 --- a/game.h +++ b/game.h @@ -7,16 +7,17 @@ #define LEFT_COL 9 #define RIGHT_COL 70 -struct GameData +typedef struct { + int host; int playerNumber; char* domain; int port; -}; +} GameData; -void DrawWalls(struct GameData); -void DrawHeader(struct GameData); +void DrawWalls(GameData); +void DrawHeader(GameData); #endif \ No newline at end of file diff --git a/main.c b/main.c index f6b7b1a..e292b7a 100644 --- a/main.c +++ b/main.c @@ -3,20 +3,24 @@ #include #include #include +#include #include +#include "network/networking.h" + /** * Main Fucntion */ int main(int argc, char* argv[]) { // Create GameData Object - struct GameData data; + GameData data = { false, 0, NULL, 0 }; // Detect Server or Client switch (argc) { case 2: // Start Server + data.host = true; data.playerNumber = 0; data.port = atoi(argv[1]); break; @@ -34,27 +38,130 @@ int main(int argc, char* argv[]) return 1; } - srand(getpid()); + // srand(getpid()); - // Setup Terminal - if (initscr() == NULL) { - perror("initscr failed"); - exit(1); - } - noecho(); - cbreak(); - nodelay(stdscr, TRUE); + // // Setup Terminal + // if (initscr() == NULL) { + // perror("initscr failed"); + // exit(1); + // } + // noecho(); + // cbreak(); + // nodelay(stdscr, TRUE); - DrawWalls(data); - DrawHeader(data); + int game_running = true; - int socket_fd = 0; + if (data.host) { + // Create Server + Server s = StartServer(data.port); - while (1) { - int ch = getch(); - if (ch == 'q') - break; + printf("Server Started\n"); + + fd_set fds; + FD_ZERO(&fds); + FD_SET(s.server_fd, &fds); + + struct timeval tv = { 0, 0 }; // non-blocking check + + int updateChar = 0; + + while (game_running) { + fd_set read_fds; + FD_ZERO(&read_fds); + + // Add server socket + FD_SET(s.server_fd, &read_fds); + int max_fd = s.server_fd; + + // Add client sockets + for (int i = 0; i < s.client_count; i++) { + int fd = s.clients[i]; + FD_SET(fd, &read_fds); + if (fd > max_fd) + max_fd = fd; + } + + // Small timeout (prevents 100% CPU usage) + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 1000; // 1ms + + int ret = select(max_fd + 1, &read_fds, NULL, NULL, &tv); + + if (ret < 0) { + perror("select"); + break; + } + + // New connection + if (FD_ISSET(s.server_fd, &read_fds)) { + int client_fd = accept(s.server_fd, NULL, NULL); + if (client_fd >= 0 && s.client_count < s.max_clients) { + s.clients[s.client_count++] = client_fd; + printf("New client connected: %d\n", client_fd); + } + } + + // Handle client data + for (int i = 0; i < s.client_count; i++) { + int fd = s.clients[i]; + + if (FD_ISSET(fd, &read_fds)) { + char buffer[1024]; + int bytes = recv(fd, buffer, sizeof(buffer) - 1, 0); + + if (bytes > 0) { + buffer[bytes] = '\0'; + printf("Client %d says: %s\n", fd, buffer); + + // Example: echo back + send(fd, buffer, bytes, 0); + } else if (bytes == 0) { + printf("Client %d disconnected\n", fd); + RemoveClient(&s, i); + i--; // re-check swapped client + } else { + perror("recv"); + RemoveClient(&s, i); + i--; + } + } + } + + + } + + close(s.server_fd); + + } else { + + printf("Connecting to %s:%i\n", data.domain, data.port); + + // Create Client + + Client c = StartClient(data.domain, data.port); + + char* msg = "Hello from client"; + send(c.client_fd, msg, strlen(msg), 0); + + { + char buffer[1024] = { 0 }; + read(c.client_fd, buffer, sizeof(buffer)); + printf("Server: %s\n", buffer); + } + + sleep(10); + char* msg2 = "Ok I am leaving now"; + send(c.client_fd, msg2, strlen(msg2), 0); + { + char buffer[1024] = { 0 }; + read(c.client_fd, buffer, sizeof(buffer)); + printf("Server: %s\n", buffer); + } + + close(c.client_fd); + return 0; } - endwin(); + // endwin(); } \ No newline at end of file diff --git a/network/networking.c b/network/networking.c new file mode 100644 index 0000000..00609ef --- /dev/null +++ b/network/networking.c @@ -0,0 +1,88 @@ +#include "networking.h" +#include +#include +#include +#include +#include +#include + +Server StartServer(int port) { + Server s = {2}; + s.clientID = 0; + + + // Create Socket + if ((s.server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + perror("socket failed"); + exit(EXIT_FAILURE); + } + + // Set Address + s.address.sin_family = AF_INET; + s.address.sin_addr.s_addr = INADDR_ANY; // listen on all interfaces + s.address.sin_port = htons(port); + + // Bind Port + if (bind(s.server_fd, (struct sockaddr *)&s.address, sizeof(s.address)) < 0) { + perror("bind failed"); + close(s.server_fd); + exit(EXIT_FAILURE); + } + + // Listen for incoming connections + if (listen(s.server_fd, 3) < 0) { + perror("listen"); + close(s.server_fd); + exit(EXIT_FAILURE); + } + + printf("Server listening on port %d...\n", port); + + return s; +} + +void RemoveClient(Server* s, int index) { + close(s->clients[index]); + s->clients[index] = s->clients[s->client_count - 1]; + s->client_count--; +} + +Client StartClient(char* host, int port) { + + Client c; + + // Create socket + if ((c.client_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket failed"); + exit(EXIT_FAILURE); + } + + // Set address info + c.address.sin_family = AF_INET; + c.address.sin_port = htons(port); + + // Convert hostname/IP to binary form + if (inet_pton(AF_INET, host, &c.address.sin_addr) <= 0) { + // If not a direct IP, try resolving hostname + struct hostent* he = gethostbyname(host); + if (he == NULL) { + perror("gethostbyname failed"); + close(c.client_fd); + exit(EXIT_FAILURE); + } + memcpy(&c.address.sin_addr, he->h_addr_list[0], he->h_length); + } + + // Connect to server + if (connect(c.client_fd, (struct sockaddr*)&c.address, sizeof(c.address)) < 0) { + perror("connect failed"); + close(c.client_fd); + exit(EXIT_FAILURE); + } + + printf("Connected to %s:%d\n", host, port); + + return c; +} + + diff --git a/network/networking.h b/network/networking.h new file mode 100644 index 0000000..0186c9c --- /dev/null +++ b/network/networking.h @@ -0,0 +1,26 @@ +#ifndef GAME_NETWORKING_H +#define GAME_NETWORKING_H 1 + +#include + +typedef struct { + const int max_clients; + int server_fd; + struct sockaddr_in address; + int clients[2]; + int clientID; + int client_count; +} Server; + +Server StartServer(int port); +void RemoveClient(Server* s, int index); + +typedef struct { + int client_fd; + struct sockaddr_in address; +} Client; + + +Client StartClient(char* host, int port); + +#endif \ No newline at end of file