// server_udp.c // Лабораторная №8, вариант (UDP, чётный номер): // "Заменить на пробелы все символы, совпадающие с первым символом в строке, кроме первого". [file:22] // Сервер UDP: принимает текстовые блоки от клиента, построчно обрабатывает и пишет в файл. [web:78] #include // printf, fprintf, perror, FILE, fopen, fclose, fgets #include // exit, EXIT_FAILURE, strtoul #include // memset, strlen, strchr, strcpy, strncpy #include // errno #include // close #include // sockaddr_in, inet_ntoa, htons, htonl, ntohs, ntohl #include // socket, bind, recvfrom, sendto #include // типы сокетов #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 \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; }