commit f3284c7436a7c9682edea71e82cc2e35411dc17c Author: TolaMironcenko Date: Thu Nov 20 18:15:23 2025 +0700 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ef42b49 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +*.o +.vscode +.cache +.idea +build +builddir +speedtest +*.swp +*.log +.proxy.sh +.no-proxy.sh diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d189e03 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required (VERSION 3.6) +project(speedtest LANGUAGES C) + +set(CMAKE_C_STANDARD 23) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_C_FLAGS "-ffunction-sections -fdata-sections") +if (APPLE) +elseif (UNIX) + set(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections") +endif() + +include_directories(./src/lib/ ./src) + +FILE(GLOB SOURCES src/*.c src/lib/*.c src/file_db/*.c src/config/*.c src/api/*.c src/database/*.c src/security/*.c src/utils/*.c) + +option(USE_WERROR "Enable warnings as errors support" OFF) + +if(USE_WERROR) + add_definitions(-Werror) +endif() + +add_executable( + speedtest + ${SOURCES} +) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3e8e9f8 --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +CC = gcc +CFLAGS = -Wall -g -std=gnu2x -ffunction-sections -fdata-sections +LDFLAGS = +INCLUDES = -I./src/lib -I./src +SRCS = $(wildcard src/lib/*.c src/file_db/*.c src/*.c src/config/*.c src/database/*.c src/api/*.c src/security/*.c src/utils/*.c) +OBJS = $(SRCS:.c=.o) +TARGET = speedtest +BUILD_DIR=./build +CROSS_COMPILE = +LIBS = +WERROR ?= 0 + +ifeq ($(shell uname), Linux) + LDFLAGS += -Wl,--gc-sections +endif + +ifeq ($(WERROR), 1) + CFLAGS += -Werror +endif + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CROSS_COMPILE)$(CC) $(LDFLAGS) $^ -o $@ $(LIBS) + +%.o: %.c + $(CROSS_COMPILE)$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +clean: + rm -f $(OBJS) $(TARGET) + +test: $(TARGET) + bash ./tests.sh diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..94a9e6d --- /dev/null +++ b/meson.build @@ -0,0 +1,25 @@ +project('speedtest', 'c', default_options: ['c_std=gnu2x']) +include_dirs = include_directories('src') +deps = [] +extra_c_args = ['-ffunction-sections', '-fdata-sections'] +extra_c_link_args = [] +system = host_machine.system() +if system == 'linux' + extra_c_link_args += ['-Wl,--gc-sections'] +endif + +use_werror = get_option('use_werror') +sources = ['src/main.c', 'src/client.c', 'src/server.c', 'src/utils.c'] + +if use_werror + add_project_arguments('-Werror', language: 'c') +endif + +executable( + 'speedtest', + sources, + include_directories: include_dirs, + dependencies: deps, + c_args: extra_c_args, + link_args: extra_c_link_args, +) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..d6d760c --- /dev/null +++ b/meson_options.txt @@ -0,0 +1 @@ +option('use_werror', type: 'boolean', value: false, description: 'Build with warning as errors') diff --git a/src/client.c b/src/client.c new file mode 100644 index 0000000..1f23a93 --- /dev/null +++ b/src/client.c @@ -0,0 +1,44 @@ +#include "client.h" +#include "utils.h" +#include +#include +#include + +void run_client(const char *server_ip) { + int sock; + struct sockaddr_in serv_addr; + char buffer[BUFFER_SIZE]; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + error("Ошибка создания сокета"); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(PORT); + + if (inet_pton(AF_INET, server_ip, &serv_addr.sin_addr) <= 0) + error("Неверный адрес"); + + if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + error("Ошибка подключения"); + + // Отправка данных + ssize_t total_sent = 0; + double start = get_time_ms(); + + while (total_sent < TOTAL_DATA_SIZE) { + ssize_t sent = send(sock, buffer, BUFFER_SIZE, 0); + if (sent < 0) { + error("Ошибка отправки"); + } + total_sent += sent; + } + + double end = get_time_ms(); + double elapsed = end - start; + + printf("Отправлено %.2f MB за %.2f ms\n", (double)total_sent / (1024 * 1024), + elapsed); + printf("Скорость: %.2f Mbps\n", (total_sent * 8) / (elapsed * 1000)); + + close(sock); +} diff --git a/src/client.h b/src/client.h new file mode 100644 index 0000000..54ded89 --- /dev/null +++ b/src/client.h @@ -0,0 +1,3 @@ +#pragma once + +void run_client(const char *server_ip); diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..b26961a --- /dev/null +++ b/src/main.c @@ -0,0 +1,21 @@ +#include "client.h" +#include "server.h" +#include +#include + +int main(int argc, char *argv[]) { + if (argc == 2 && (!strcmp(argv[1], "server") || !strcmp(argv[1], "s"))) { + run_server(false); + } else if (argc == 3 && (!strcmp(argv[1], "client") || !strcmp(argv[1], "c"))) { + run_client(argv[2]); + } else if (argc == 3 && (!strcmp(argv[1], "server") || !strcmp(argv[1], "s"))) { + run_server(true); + } else { + printf("Использование:\n"); + printf("Сервер: %s server|s\n", argv[0]); + printf("Сервер: %s server|s \n", argv[0]); + printf("Клиент: %s client|c \n", argv[0]); + return 1; + } + return 0; +} diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..c221fd1 --- /dev/null +++ b/src/server.c @@ -0,0 +1,62 @@ +#include "server.h" +#include "utils.h" +#include +#include +#include + +void run_server(const bool testing) { + int server_fd, client_fd; + struct sockaddr_in address; + char buffer[BUFFER_SIZE]; + + if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) + error("Сокет не создан"); + + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(PORT); + + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < + 0) + error("Ошибка setsockopt"); + + if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) + error("Ошибка bind"); + + if (listen(server_fd, 3) < 0) + error("Ошибка listen"); + + printf("Сервер запущен на порту %d\n", PORT); + + while (1) { + socklen_t addrlen = sizeof(address); + if ((client_fd = accept(server_fd, (struct sockaddr *)&address, &addrlen)) < + 0) + error("Ошибка accept"); + + // Прием данных + ssize_t total_received = 0; + double start = get_time_ms(); + + while (total_received < TOTAL_DATA_SIZE) { + ssize_t received = recv(client_fd, buffer, BUFFER_SIZE, 0); + if (received < 0) { + error("Ошибка приема"); + } + total_received += received; + } + + double end = get_time_ms(); + double elapsed = end - start; + + printf("Получено %.2f MB за %.2f ms\n", + (double)total_received / (1024 * 1024), elapsed); + printf("Скорость: %.2f Mbps\n", (total_received * 8) / (elapsed * 1000)); + + close(client_fd); + if (testing) { + break; + } + } + close(server_fd); +} diff --git a/src/server.h b/src/server.h new file mode 100644 index 0000000..75e9040 --- /dev/null +++ b/src/server.h @@ -0,0 +1,3 @@ +#pragma once + +void run_server(const bool testing); diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..0fdbebd --- /dev/null +++ b/src/utils.c @@ -0,0 +1,15 @@ +#include "utils.h" +#include +#include +#include + +void error(const char *msg) { + perror(msg); + exit(1); +} + +double get_time_ms() { + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000.0) + (tv.tv_usec / 1000.0); +} diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..c8caa6c --- /dev/null +++ b/src/utils.h @@ -0,0 +1,8 @@ +#pragma once + +#define PORT 8080 +#define BUFFER_SIZE 1024 +#define TOTAL_DATA_SIZE (1024 * 1024 * 100) // 100 MB + +void error(const char *msg); +double get_time_ms(); diff --git a/tests.sh b/tests.sh new file mode 100755 index 0000000..344ee72 --- /dev/null +++ b/tests.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +( + ./speedtest s test + if [ "$?" -eq 0 ] + then + echo "Speedtest server successful" + else + echo "Speedtest server failed" + exit 1 + fi +) & +sleep 0.3 +./speedtest c 127.0.0.1 +if [ "$?" -eq 0 ] +then + echo "Speedtest client successful" +else + echo "Speedtest client failed" + exit 1 +fi + +wait +exit 0