Files
CS-LABS/lab_8/server.c
2025-12-10 15:06:27 +07:00

177 lines
6.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// server_udp.c
// Лабораторная №8, вариант (UDP, чётный номер):
// "Заменить на пробелы все символы, совпадающие с первым символом в строке, кроме первого". [file:22]
// Сервер UDP: принимает текстовые блоки от клиента, построчно обрабатывает и пишет в файл. [web:78]
#include <stdio.h> // printf, fprintf, perror, FILE, fopen, fclose, fgets
#include <stdlib.h> // exit, EXIT_FAILURE, strtoul
#include <string.h> // memset, strlen, strchr, strcpy, strncpy
#include <errno.h> // errno
#include <unistd.h> // close
#include <arpa/inet.h> // sockaddr_in, inet_ntoa, htons, htonl, ntohs, ntohl
#include <sys/socket.h> // socket, bind, recvfrom, sendto
#include <sys/types.h> // типы сокетов
#define BUF_SIZE 4096 // Размер сетевого буфера. [web:78]
// Специальная строка для обозначения конца передачи. [web:81]
#define END_MARKER "END_OF_TRANSMISSION"
// Функция обработки одной строки по условию варианта. [file:22]
static void process_line(char *line,
long long *repl_counter) {
if (!line || !repl_counter) {
return; // Защита от некорректных указателей. [file:22]
}
size_t len = strlen(line); // Получаем длину строки. [file:73]
if (len == 0) {
return; // Пустая строка не обрабатывается. [file:22]
}
char first = line[0]; // Первый символ строки ключ для замен. [file:22]
// Проходим по строке начиная со второго символа. [file:22]
for (size_t i = 1; i < len; ++i) {
if (line[i] == first && line[i] != '\n') {
// Заменяем совпадающий символ пробелом и увеличиваем счётчик. [file:22]
line[i] = ' ';
(*repl_counter)++;
}
}
}
int main(int argc, char *argv[]) {
// Ожидаемые аргументы:
// argv[1] - порт UDP сервера (например, 5000). [web:78]
// argv[2] - имя выходного файла. [file:22]
if (argc < 3) {
fprintf(stderr,
"Usage: %s <port> <output_file>\n",
argv[0]);
fprintf(stderr,
"Example: %s 5000 out.txt\n",
argv[0]);
return -1;
}
// Разбираем номер порта. [web:78]
char *endptr = NULL;
errno = 0;
long port_long = strtol(argv[1], &endptr, 10);
if (errno != 0 || endptr == argv[1] || *endptr != '\0' ||
port_long <= 0 || port_long > 65535) {
fprintf(stderr, "ERROR: invalid port '%s'\n", argv[1]);
return -1;
}
int port = (int) port_long;
const char *out_path = argv[2]; // Имя выходного файла. [file:22]
FILE *fout = fopen(out_path, "w");
if (!fout) {
perror("fopen(output_file)");
return -1;
}
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // Создаём UDP-сокет. [web:74]
if (sockfd < 0) {
perror("socket");
fclose(fout);
return -1;
}
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr)); // Обнуляем структуру адреса. [web:74]
servaddr.sin_family = AF_INET; // IPv4. [web:74]
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // Принимать на всех интерфейсах. [web:74]
servaddr.sin_port = htons(port); // Порт сервера в сетевом порядке байт. [web:74]
if (bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
perror("bind");
close(sockfd);
fclose(fout);
return -1;
}
printf("UDP server is listening on port %d, output file: %s\n",
port, out_path);
char buf[BUF_SIZE]; // Буфер для приёма UDP-пакетов. [web:78]
char line_buf[BUF_SIZE]; // Буфер для накопления текущей строки. [file:22]
size_t line_len = 0; // Текущая длина строки в line_buf. [file:22]
long long total_replacements = 0; // Общее количество замен. [file:22]
int done = 0; // Флаг завершения при получении END_MARKER. [web:81]
while (!done) {
struct sockaddr_in cliaddr;
socklen_t cli_len = sizeof(cliaddr);
ssize_t n = recvfrom(sockfd,
buf,
sizeof(buf) - 1,
0,
(struct sockaddr *) &cliaddr,
&cli_len); // Принимаем UDP-дейтаграмму. [web:74]
if (n < 0) {
perror("recvfrom");
total_replacements = -1;
break;
}
buf[n] = '\0'; // Делаем строку ASCIIZ для удобства. [web:78]
if (strcmp(buf, END_MARKER) == 0) {
printf("Received END marker, finishing.\n");
done = 1;
break;
}
size_t pos = 0;
while (pos < (size_t) n) {
char c = buf[pos++];
if (c == '\n') {
line_buf[line_len] = '\0';
process_line(line_buf, &total_replacements);
if (fprintf(fout, "%s\n", line_buf) < 0) {
perror("fprintf");
total_replacements = -1;
done = 1;
break;
}
line_len = 0;
} else {
if (line_len + 1 < sizeof(line_buf)) {
line_buf[line_len++] = c;
} else {
fprintf(stderr,
"Line buffer overflow, truncating line\n");
}
}
}
}
if (line_len > 0 && total_replacements >= 0) {
line_buf[line_len] = '\0';
process_line(line_buf, &total_replacements);
if (fprintf(fout, "%s\n", line_buf) < 0) {
perror("fprintf");
total_replacements = -1;
}
}
if (fclose(fout) == EOF) {
perror("fclose(output_file)");
total_replacements = -1;
}
close(sockfd);
printf("Total replacements: %lld\n", total_replacements);
if (total_replacements < 0) {
return -1;
}
return 0;
}