chat

idk what is
git clone git://git.evenfri.xyz/chat.git
Log | Files | Refs

commit 385af01b7ea5b08bc7d03841c17b156afaa9401f
Author: evenfri <evenfri256@gmail.com>
Date:   Fri, 28 Aug 2026 00:46:38 +0800

initial commit

Diffstat:
A.gitignore | 3+++
Abuild.sh | 21+++++++++++++++++++++
Aclient.c | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aserver.c | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 301 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,3 @@ +*.o +server +client diff --git a/build.sh b/build.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +cflags="-Wall -Wextra" + +set -e + +compile() { + f="$1" + + echo "cc $f" + gcc -c $cflags $f +} + +compile server.c +compile client.c + +echo "ld server" +gcc -o server server.o + +echo "ld client" +gcc -o client client.o diff --git a/client.c b/client.c @@ -0,0 +1,127 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <poll.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#define BUFFER_SIZE 1024 + +int main(int argc, char *argv[]) { + int fd; + int n; + int result; + int message_size; + struct sockaddr_in addr; + struct pollfd fds[2]; + char buffer[BUFFER_SIZE]; + char message[BUFFER_SIZE]; + char *nickname; + + if (argc > 1) { + nickname = argv[1]; + } else { + nickname = "Client"; + } + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + perror("socket"); + return 1; + } + + memset(&addr, 0, sizeof(addr)); + + addr.sin_family = AF_INET; + addr.sin_port = htons(8080); + + if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) { + fprintf(stderr, "invalid address\n"); + close(fd); + return 1; + } + + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + perror("connect"); + close(fd); + return 1; + } + + printf("connected\n"); + printf("> "); + fflush(stdout); + + fds[0].fd = fd; + fds[0].events = POLLIN; + + fds[1].fd = STDIN_FILENO; + fds[1].events = POLLIN; + + while (1) { + result = poll(fds, 2, -1); + + if (result == -1) { + perror("poll"); + break; + } + + /* + * Server sent something. + */ + if (fds[0].revents & POLLIN) { + n = recv(fd, buffer, sizeof(buffer) - 1, 0); + + if (n == -1) { + perror("recv"); + break; + } + + if (n == 0) { + printf("\nserver disconnected\n"); + break; + } + + buffer[n] = '\0'; + + printf("\r%s", buffer); + printf("> "); + fflush(stdout); + } + + /* + * User typed something. + */ + if (fds[1].revents & POLLIN) { + if (fgets(buffer, sizeof(buffer), stdin) == NULL) { + break; + } + + message_size = snprintf( + message, + sizeof(message), + "%s: %s", + nickname, + buffer + ); + + if (message_size < 0 || message_size >= (int)sizeof(message)) { + fprintf(stderr, "message too long\n"); + continue; + } + + if (send(fd, message, message_size, 0) == -1) { + perror("send"); + break; + } + + printf("> "); + fflush(stdout); + } + } + + close(fd); + + return 0; +} diff --git a/server.c b/server.c @@ -0,0 +1,150 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <poll.h> + +#include <sys/socket.h> +#include <netinet/in.h> + +#define MAX_CLIENTS 16 +#define BUFFER_SIZE 1024 + +int main() { + int server_fd; + int client_fd; + int client_count; + int i; + int j; + int n; + int result; + struct sockaddr_in addr; + struct pollfd fds[MAX_CLIENTS + 1]; + char buffer[BUFFER_SIZE]; + + server_fd = socket(AF_INET, SOCK_STREAM, 0); + if (server_fd == -1) { + perror("socket"); + return 1; + } + + memset(&addr, 0, sizeof(addr)); + + addr.sin_family = AF_INET; + addr.sin_port = htons(8080); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + perror("bind"); + close(server_fd); + return 1; + } + + if (listen(server_fd, 16) == -1) { + perror("listen"); + close(server_fd); + return 1; + } + + memset(fds, 0, sizeof(fds)); + + fds[0].fd = server_fd; + fds[0].events = POLLIN; + + client_count = 0; + + printf("listening on port 8080\n"); + + while (1) { + result = poll(fds, client_count + 1, -1); + + if (result == -1) { + perror("poll"); + break; + } + + /* + * New client. + */ + if (fds[0].revents & POLLIN) { + client_fd = accept(server_fd, NULL, NULL); + + if (client_fd == -1) { + perror("accept"); + } else if (client_count >= MAX_CLIENTS) { + printf("too many clients\n"); + close(client_fd); + } else { + client_count++; + + fds[client_count].fd = client_fd; + fds[client_count].events = POLLIN; + + printf("client %d connected\n", client_fd); + } + } + + /* + * Existing clients. + */ + for (i = 1; i <= client_count; i++) { + if (!(fds[i].revents & POLLIN)) { + continue; + } + + n = recv(fds[i].fd, buffer, sizeof(buffer), 0); + + if (n == -1) { + perror("recv"); + + close(fds[i].fd); + + for (j = i; j < client_count; j++) { + fds[j] = fds[j + 1]; + } + + client_count--; + i--; + + continue; + } + + if (n == 0) { + printf("client %d disconnected\n", fds[i].fd); + + close(fds[i].fd); + + for (j = i; j < client_count; j++) { + fds[j] = fds[j + 1]; + } + + client_count--; + i--; + + continue; + } + + /* + * Broadcast. + */ + printf("client %d sent %d bytes\n", fds[i].fd, n); + + for (j = 1; j <= client_count; j++) { + if (j == i) { + continue; + } + + if (send(fds[j].fd, buffer, n, 0) == -1) { + perror("send"); + } + } + } + } + + for (i = 1; i <= client_count; i++) { + close(fds[i].fd); + } + + close(server_fd); + + return 0; +}