commit 8e54631e4bdc30be93e983d8d360c80c4a84a78c Author: TolaMironcenko Date: Fri Feb 13 18:01:07 2026 +0700 initial commit diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..24fab55 --- /dev/null +++ b/.clang-format @@ -0,0 +1,6 @@ +BasedOnStyle: Google +AllowShortFunctionsOnASingleLine: false +SpaceAfterCStyleCast: true +PointerBindsToType: false +DerivePointerBinding: false +IncludeBlocks: Preserve diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b8b284e --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +build +*.o +sch +schc +.cache diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..70fb887 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required (VERSION 3.6) +project(sch LANGUAGES C) + +set(CMAKE_C_STANDARD 23) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +FILE(GLOB_RECURSE SOURCES src/main.c) +FILE(GLOB_RECURSE SOURCES_CLIENT src/client.c) + +add_executable( + sch + ${SOURCES} +) +add_executable( + schc + ${SOURCES_CLIENT} +) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..390f8f8 --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +CC = gcc +CFLAGS = -Wall -g -std=gnu2x +LDFLAGS = +LIBS = +INCLUDES = -I./src/lib -I./src +SRCS = src/main.c +CSRCS = src/client.c +OBJS = src/main.o +COBJS = src/client.o +TARGET = sch +CTARGET = schc +CROSS_COMPILE = + +all: $(TARGET) $(CTARGET) + +$(TARGET): $(OBJS) + $(CROSS_COMPILE)$(CC) $(LDFLAGS) $^ -o $@ $(LIBS) + +$(CTARGET): $(COBJS) + $(CROSS_COMPILE)$(CC) $(LDFLAGS) $^ -o $@ $(LIBS) + +%.o: %.c + $(CROSS_COMPILE)$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +clean: + rm -f $(OBJS) $(TARGET) $(CTARGET) + +test: $(TARGET) + bash ./tests.sh diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..2e47809 --- /dev/null +++ b/meson.build @@ -0,0 +1,4 @@ +project('sch', 'c', default_options: ['cpp_std=c20']) +include_dirs = include_directories('src') +executable('sch', 'src/main.c', include_directories: include_dirs, install: true) +executable('schc', 'src/client.c', include_directories: include_dirs, install: true) diff --git a/src/client.c b/src/client.c new file mode 100644 index 0000000..cf296a8 --- /dev/null +++ b/src/client.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include + +#define PORT 5555 +#define BUFFER_SIZE 1024 + +int main() { + int sock; + struct sockaddr_in server_addr; + char buffer[BUFFER_SIZE]; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + perror("socket"); + return 1; + } + + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(PORT); + inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr); + + if (connect(sock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < + 0) { + perror("connect"); + return 1; + } + + if (fork() == 0) { + // Процесс чтения + while (1) { + int valread = read(sock, buffer, BUFFER_SIZE); + if (valread > 0) { + buffer[valread] = '\0'; + printf("%s", buffer); + } + } + } else { + char username[50]; + fgets(username, 50, stdin); + username[strlen(username)-1] = '\0'; + send(sock, username, 50, 0); + printf("username = %s\n", username); + // Процесс отправки + while (1) { + fgets(buffer, BUFFER_SIZE, stdin); + send(sock, buffer, strlen(buffer), 0); + } + } + + return 0; +} diff --git a/src/colors.h b/src/colors.h new file mode 100644 index 0000000..43cd64a --- /dev/null +++ b/src/colors.h @@ -0,0 +1,61 @@ +#ifndef COLORS_H +#define COLORS_H +#define RESET "\033[0m" +#define GREEN "\033[0;32m" // GREEN +#define BLUE "\033[0;34m" // BLUE +#define YELLOW "\033[1;33m" // YELLOW +#define RED "\033[0;31m" // RED +#define BLACK "\033[0;30m" // BLACK +#define PURPLE "\033[0;35m" // PURPLE +#define CYAN "\033[0;36m" // CYAN +#define WHITE "\033[0;37m" // WHITE +#define BBLACK "\033[1;30m" // BLACK +#define BRED "\033[1;31m" // RED +#define BGREEN "\033[1;32m" // GREEN +#define BYELLOW "\033[1;33m" // YELLOW +#define BBLUE "\033[1;34m" // BLUE +#define BPURPLE "\033[1;35m" // PURPLE +#define BCYAN "\033[1;36m" // CYAN +#define BWHITE "\033[1;37m" // WHITE +#define UBLACK "\033[4;30m" // BLACK +#define URED "\033[4;31m" // RED +#define UGREEN "\033[4;32m" // GREEN +#define UYELLOW "\033[4;33m" // YELLOW +#define UBLUE "\033[4;34m" // BLUE +#define UPURPLE "\033[4;35m" // PURPLE +#define UCYAN "\033[4;36m" // CYAN +#define UWHITE "\033[4;37m" // WHITE +#define ON_BLACK "\033[40m" // BLACK +#define ON_RED "\033[41m" // RED +#define ON_GREEN "\033[42m" // GREEN +#define ON_YELLOW "\033[43m" // YELLOW +#define ON_BLUE "\033[44m" // BLUE +#define ON_PURPLE "\033[45m" // PURPLE +#define ON_CYAN "\033[46m" // CYAN +#define ON_WHITE "\033[47m" // WHITE +#define IBLACK "\033[0;90m" // BLACK +#define IRED "\033[0;91m" // RED +#define IGREEN "\033[0;92m" // GREEN +#define IYELLOW "\033[0;93m" // YELLOW +#define IBLUE "\033[0;94m" // BLUE +#define IPURPLE "\033[0;95m" // PURPLE +#define ICYAN "\033[0;96m" // CYAN +#define IWHITE "\033[0;97m" // WHITE +#define BIBLACK "\033[1;90m" // BLACK +#define BIRED "\033[1;91m" // RED +#define BIGREEN "\033[1;92m" // GREEN +#define BIYELLOW "\033[1;93m" // YELLOW +#define BIBLUE "\033[1;94m" // BLUE +#define BIPURPLE "\033[1;95m" // PURPLE +#define BICYAN "\033[1;96m" // CYAN +#define BIWHITE "\033[1;97m" // WHITE +#define ON_IBLACK "\033[0;100m" // BLACK +#define ON_IRED "\033[0;101m" // RED +#define ON_IGREEN "\033[0;102m" // GREEN +#define ON_IYELLOW "\033[0;103m" // YELLOW +#define ON_IBLUE "\033[0;104m" // BLUE +#define ON_IPURPLE "\033[0;105m" // PURPLE +#define ON_ICYAN "\033[0;106m" // CYAN +#define ON_IWHITE "\033[0;107m" // WHITE + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..3c8dfac --- /dev/null +++ b/src/main.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 5555 +#define MAX_CLIENTS 10 +#define BUFFER_SIZE 1024 + +struct client_t { + int sock; + char username[50]; +}; + +int main() { + int server_fd; + struct client_t clients[MAX_CLIENTS]; + struct sockaddr_in address; + int addrlen = sizeof(address); + fd_set readfds; + char buffer[BUFFER_SIZE]; + + for (int i = 0; i < MAX_CLIENTS; i++) { + clients[i].sock = 0; + bzero(clients[i].username, sizeof(clients[i].username)); + } + + server_fd = socket(AF_INET, SOCK_STREAM, 0); + if (server_fd < 0) { + perror("socket"); + exit(EXIT_FAILURE); + } + + int opt = 1; + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { + perror("setsockopt"); + exit(EXIT_FAILURE); + } + + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(PORT); + + if (bind(server_fd, (struct sockaddr *) &address, sizeof(address)) < 0) { + perror("bind"); + exit(EXIT_FAILURE); + } + + if (listen(server_fd, 5) < 0) { + perror("listen"); + exit(EXIT_FAILURE); + } + + printf("Chat server started on port %d\n", PORT); + + while (1) { + FD_ZERO(&readfds); + FD_SET(server_fd, &readfds); + int max_sd = server_fd; + + for (int i = 0; i < MAX_CLIENTS; i++) { + int sd = clients[i].sock; + if (sd > 0) FD_SET(sd, &readfds); + if (sd > max_sd) max_sd = sd; + } + + if (select(max_sd + 1, &readfds, NULL, NULL, NULL) < 0) { + perror("select"); + exit(EXIT_FAILURE); + } + + // Новое подключение + if (FD_ISSET(server_fd, &readfds)) { + int new_socket = accept(server_fd, (struct sockaddr *) &address, + (socklen_t *) &addrlen); + + printf("New connection: socket %d\n", new_socket); + read(new_socket, buffer, BUFFER_SIZE); + + for (int i = 0; i < MAX_CLIENTS; i++) { + if (clients[i].sock == 0) { + clients[i].sock = new_socket; + strcpy(clients[i].username, buffer); + break; + } + } + } + + // Сообщения от клиентов + for (int i = 0; i < MAX_CLIENTS; i++) { + int sd = clients[i].sock; + char sd_username[50]; + bzero(sd_username, sizeof(sd_username)); + strcpy(sd_username, clients[i].username); + + if (FD_ISSET(sd, &readfds)) { + int valread = read(sd, buffer, BUFFER_SIZE); + + if (valread == 0) { + printf("Client disconnected: socket %d\n", sd); + close(sd); + clients[i].sock = 0; + bzero(clients[i].username, sizeof(clients[i].username)); + } else { + buffer[valread] = '\0'; + printf("from_socket: %d\n", sd); + printf("from_username: %s\n", sd_username); + printf("Message: %s\n", buffer); + + // Рассылка всем другим + for (int j = 0; j < MAX_CLIENTS; j++) { + if (clients[j].sock != 0 && clients[j].sock != sd) { + send(clients[j].sock, buffer, strlen(buffer), 0); + } + } + } + } + } + } + + return 0; +}