Files
CS-LABS/mine/lab_8/server.c
2025-12-11 09:40:07 +07:00

178 lines
5.8 KiB
C
Raw Permalink 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.
// UDPсервер: принимает текст по сети, построчно обрабатывает и пишет в файл.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h> // sockaddr_in, htons, htonl, ntohs, ntohl
#include <sys/socket.h> // socket, bind, recvfrom
#include <sys/types.h>
#define BUF_SIZE 4096
#define END_MARKER "END_OF_TRANSMISSION"
// Обработка одной строки по условию: заменяет на пробелы
// все символы, совпадающие с первым, кроме самого первого.
static void process_line(char *line, long long *repl_counter) {
if (!line || !repl_counter) {
return;
}
size_t len = strlen(line);
if (len == 0) {
return;
}
char first = line[0];
for (size_t i = 1; i < len; ++i) {
if (line[i] == first && line[i] != '\n') {
line[i] = ' ';
(*repl_counter)++;
}
}
}
int main(int argc, char *argv[]) {
// argv[1] — порт сервера UDP, argv[2] — выходной файл.
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;
}
// Разбор номера порта.
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 *fout = fopen(out_path, "w");
if (!fout) {
perror("fopen(output_file)");
return -1;
}
// Создаём UDPсокет: AF_INET (IPv4), SOCK_DGRAM (UDP).
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
fclose(fout);
return -1;
}
// Заполняем адрес сервера и привязываем сокет к порту (bind).
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET; // IPv4.
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // принимать на всех интерфейсах.
servaddr.sin_port = htons(port); // порт в сетевом порядке байт.
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датаграммы.
char line_buf[BUF_SIZE]; // здесь накапливаем одну логическую строку.
size_t line_len = 0;
long long total_replacements = 0;
int done = 0; // флаг завершения по END_MARKER.
while (!done) {
struct sockaddr_in cliaddr;
socklen_t cli_len = sizeof(cliaddr);
// recvfrom читает один UDPпакет и заполняет адрес отправителя.
ssize_t n = recvfrom(sockfd,
buf,
sizeof(buf) - 1,
0,
(struct sockaddr *) &cliaddr,
&cli_len);
if (n < 0) {
perror("recvfrom");
total_replacements = -1;
break;
}
buf[n] = '\0'; // удобнее работать как со строкой.
// Специальный маркер конца передачи от клиента.
if (strcmp(buf, END_MARKER) == 0) {
printf("Received END marker, finishing.\n");
done = 1;
break;
}
// Разбор принятого блока посимвольно, сборка полных строк по '\n'.
size_t pos = 0;
while (pos < (size_t) n) {
char c = buf[pos++];
if (c == '\n') {
// Закончили строку в line_buf.
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");
}
}
}
}
// Если соединение завершилось не на границе строки —
// доробатываем последний неполный хвост в line_buf.
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;
}