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 — локальная установка не требуется.