0Pricing
C Academy · Урок

TCP-сервер

Принимайте соединения

«TCP-сервер» — бесплатный урок C Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C Academy содержит 4 уроков всего.

Создание TCP-сервера

TCP-сервер ожидает клиентов и принимает их подключения. Его жизненный цикл таков: создать сокет, связать его с портом, начать прослушивание, а затем принимать подключения в цикле.

Шаг 1: создание сокета

Создайте потоковый сокет для IPv4 TCP. Отрицательный результат означает сбой.

#include <sys/socket.h>
#include <stdio.h>

int make_server_socket(void) {
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) { perror("socket"); }
    return fd;
}

Шаг 2: разрешение повторного использования адреса

По умолчанию после остановки сервера порт некоторое время находится в состоянии TIME_WAIT, что блокирует перезапуск. Установите SO_REUSEADDR с помощью setsockopt, чтобы немедленно связать сокет с адресом снова.

#include <sys/socket.h>

void allow_reuse(int fd) {
    int yes = 1;
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
}

Шаг 3: связывание с портом

bind() связывает сокет с локальными адресом и портом. INADDR_ANY включает прослушивание всех сетевых интерфейсов.

#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>

int bind_port(int fd, unsigned short port) {
    struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(port);
    if (bind(fd, (struct sockaddr *)&addr, sizeof addr) < 0) {
        perror("bind"); return -1;
    }
    return 0;
}

Шаг 4: прослушивание

listen() переводит сокет в пассивный режим (готовность принимать подключения). Аргумент backlog задаёт количество ожидающих подключений, которые ядро может поставить в очередь.

#include <sys/socket.h>
#include <stdio.h>

int start_listen(int fd) {
    if (listen(fd, 16) < 0) { /* backlog of 16 */
        perror("listen"); return -1;
    }
    return 0;
}

Шаг 5: приём подключений

accept() блокируется до подключения клиента, а затем возвращает новый сокет для этого клиента. Исходный сокет продолжает прослушивание.

#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>

int accept_one(int listen_fd) {
    struct sockaddr_in cli;
    socklen_t len = sizeof cli;
    int conn = accept(listen_fd, (struct sockaddr *)&cli, &len);
    if (conn < 0) perror("accept");
    return conn;
}

Два сокета, две роли

После вызова accept у Вас есть два сокета:

  • прослушивающий сокет продолжает принимать новых клиентов
  • сокет подключения взаимодействует с одним конкретным клиентом

После завершения работы с клиентом закройте сокет подключения.

Чтение запроса

Используйте recv, чтобы прочитать данные клиента в буфер. Возврат 0 означает, что клиент отключился; -1 означает ошибку.

#include <sys/socket.h>
#include <stdio.h>

void handle(int conn) {
    char buf[256];
    ssize_t n = recv(conn, buf, sizeof buf - 1, 0);
    if (n > 0) { buf[n] = 0; printf("got: %s\n", buf); }
}

Отправка ответа

Ответьте с помощью send. Для больших объёмов данных повторяйте вызов, пока все байты не будут отправлены, поскольку один вызов может записать только часть буфера.

#include <sys/socket.h>
#include <string.h>

void reply(int conn) {
    const char *msg = "hello from server\n";
    size_t left = strlen(msg);
    const char *p = msg;
    while (left > 0) {
        ssize_t n = send(conn, p, left, 0);
        if (n <= 0) break;
        p += n; left -= (size_t)n;
    }
}

Цикл приёма подключений

Простой итеративный сервер принимает одного клиента, обслуживает его, закрывает соединение, а затем возвращается к приёму следующего. Клиенты обрабатываются по одному.

#include <unistd.h>

void serve_loop(int listen_fd, int (*accept_one)(int), void (*handle)(int)) {
    for (;;) {
        int conn = accept_one(listen_fd);
        if (conn < 0) continue;
        handle(conn);
        close(conn); /* done with this client */
    }
}

Корректное завершение работы

При остановке сервера закройте прослушивающий сокет и обработайте SIGINT, чтобы корректно прервать цикл. Всегда закрывайте дескрипторы, чтобы освобождать ресурсы ядра.

Быстрая проверка

Проверьте, насколько хорошо Вы поняли принципы работы TCP-серверов.

Итоги

Вы пошагово создали TCP-сервер.

  • socket, затем SO_REUSEADDR, затем bind, listen и accept
  • accept возвращает новый сокет для каждого клиента
  • Для обмена данными используются recv и send, после чего соединение закрывается
  • Цикл позволяет обслуживать клиентов; проверяйте каждое возвращаемое значение

Часто задаваемые вопросы

Урок «TCP-сервер» бесплатный?

Да — полный текст урока «TCP-сервер» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C Academy, подпишись на CoddyKit PRO. Курс C Academy содержит 4 уроков всего.

Чему я научусь в уроке «TCP-сервер»?

Принимайте соединения Ты практикуешь C Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C Academy?

Предыдущий опыт не требуется. C Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «TCP-сервер»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C Academy?

Да. Каждый урок C Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Обзор сокетов
  2. TCP-сервер
  3. TCP-клиент
  4. Обработка нескольких клиентов
← Назад к C Academy