0Pricing
C Academy · 课时

TCP 服务器

接受连接

TCP 服务器 是 CoddyKit 上的免费 C Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 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 状态中保留一段时间,从而阻止重新启动。使用 setsockopt 设置 SO_REUSEADDR,这样就可以立即重新绑定。

#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() 将套接字标记为被动模式(准备接受连接)。等待队列长度参数设置内核可以排队等待的连接数量。

#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 服务器」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。

「TCP 服务器」这节课中我会学到什么?

接受连接 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「TCP 服务器」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C Academy 课中编写并运行代码吗?

能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 套接字概述
  2. TCP 服务器
  3. TCP 客户端
  4. 处理多个客户端
← 返回 C Academy