Serwer TCP
Akceptowanie połączeń
Serwer TCP to bezpłatna lekcja C Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C Academy zawiera 4 lekcji w sumie.
Budowanie serwera TCP
Serwer TCP oczekuje na klientów i akceptuje ich połączenia. Cykl życia wygląda następująco: utworzenie gniazda, przypisanie go do portu, nasłuchiwanie, a następnie akceptowanie połączeń w pętli.
Krok 1: Utworzenie gniazda
Utwórz gniazdo strumieniowe dla IPv4 TCP. Wynik ujemny oznacza niepowodzenie.
#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;
}Krok 2: Zezwolenie na ponowne użycie adresu
Domyślnie po zatrzymaniu serwera port pozostaje w stanie TIME_WAIT, uniemożliwiając ponowne uruchomienie. Ustaw SO_REUSEADDR za pomocą setsockopt, aby móc natychmiast ponownie przypisać gniazdo.
#include <sys/socket.h>
void allow_reuse(int fd) {
int yes = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
}Krok 3: Przypisanie do portu
bind() przypisuje gniazdo do lokalnego adresu i portu. INADDR_ANY umożliwia nasłuchiwanie na wszystkich interfejsach sieciowych.
#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;
}Krok 4: Nasłuchiwanie
listen() oznacza gniazdo jako pasywne (gotowe do akceptowania połączeń). Argument backlog określa, ile oczekujących połączeń jądro może umieścić w kolejce.
#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;
}Krok 5: Akceptowanie połączeń
accept() blokuje działanie do czasu połączenia klienta, a następnie zwraca nowe gniazdo przeznaczone dla tego klienta. Oryginalne gniazdo nadal nasłuchuje.
#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;
}Dwa gniazda, dwie role
Po wywołaniu accept dostępne są dwa gniazda:
- Gniazdo nasłuchujące nadal akceptuje nowych klientów
- Gniazdo połączenia służy do komunikacji z jednym konkretnym klientem
Po zakończeniu obsługi klienta należy zamknąć gniazdo połączenia.
Odczytywanie żądania
Użyj recv, aby odczytać dane klienta do bufora. Wartość 0 oznacza rozłączenie klienta, a -1 — błąd.
#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); }
}Wysyłanie odpowiedzi
Odpowiedz za pomocą send. W przypadku dużych danych wykonuj pętlę, aż wszystkie bajty zostaną wysłane, ponieważ pojedyncze wywołanie może zapisać tylko część bufora.
#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;
}
}Pętla akceptowania
Prosty serwer iteracyjny akceptuje jednego klienta, obsługuje go, zamyka połączenie, a następnie wraca do pętli i akceptuje kolejnego. Obsługuje klientów pojedynczo.
#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 */
}
}Kontrolowane zamykanie
Po zatrzymaniu serwera zamknij gniazdo nasłuchujące i obsłuż SIGINT, aby prawidłowo przerwać pętlę. Zawsze zamykaj deskryptory, aby zwalniać zasoby jądra.
Szybkie sprawdzenie
Sprawdź swoją wiedzę na temat serwerów TCP.
Podsumowanie
Zbudowali Państwo serwer TCP krok po kroku.
- socket, następnie SO_REUSEADDR, bind, listen i accept
acceptzwraca nowe gniazdo dla każdego klienta- recv/send służą do komunikacji, a następnie połączenie należy zamknąć
- Używaj pętli do obsługi klientów i sprawdzaj każdą wartość zwracaną
Często zadawane pytania
Czy lekcja „Serwer TCP” jest bezpłatna?
Tak — pełny tekst „Serwer TCP” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C Academy, przejdź na CoddyKit PRO. Kurs C Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Serwer TCP”?
Akceptowanie połączeń Ćwiczysz C Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć C Academy?
Nie wymagamy żadnego doświadczenia. C Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Serwer TCP”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji C Academy?
Tak. Każda lekcja C Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.