跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++

TCP Socket 网络编程详解:API、多线程与守护进程

详细讲解了 TCP Socket 网络编程的核心 API,包括 socket、bind、listen、accept 和 connect 的用法。内容涵盖 TCP 三次握手与四次挥手原理、客户端与服务端代码实现、单进程及多进程/多线程模型对比,以及线程池的应用。此外,还介绍了守护进程的创建步骤、信号处理(如 SIGPIPE)及标准输出重定向,帮助开发者构建稳定运行的后台网络服务。

小熊软糖发布于 2026/3/16更新于 2026/10/1593 浏览
TCP Socket 网络编程详解:API、多线程与守护进程

TCP Socket 网络编程详解

本文详细讲解 TCP Socket 网络编程的核心 API,包括 socket、bind、listen、accept 和 connect 的用法。内容涵盖 TCP 三次握手与四次挥手原理、客户端与服务端代码实现、单进程及多进程/多线程模型对比,以及线程池的应用。此外,还介绍了守护进程的创建步骤、信号处理(如 SIGPIPE)及标准输出重定向,帮助开发者构建稳定运行的后台网络服务。

Socket 类型与参数

套接字域 (Domain)

第一个参数指定协议家族,例如 AF_INET 表示 IPv4,AF_INET6 表示 IPv6,AF_UNIX 表示本地通信。

套接字类型 (Type)

第二个参数定义套接字类型:

  • SOCK_STREAM: 面向字节流,对应 TCP。
  • SOCK_DGRAM: 面向用户数据报,对应 UDP。

协议 (Protocol)

第三个参数通常填 0,系统会根据前两个参数自动选择默认协议。

TCP Socket API 详解

以下函数都在 <sys/socket.h> 中定义。

socket()

打开一个网络通讯端口。如果成功,返回文件描述符;如果出错,返回 -1。

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

对于 IPv4,family 参数指定为 AF_INET;对于 TCP 协议,type 参数指定为 SOCK_STREAM。

bind()

服务器程序需要调用 bind 绑定固定的网络地址和端口号。

struct sockaddr_in local;
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port_);
inet_aton(ip_.c_str(), &(local.sin_addr));
bind(sockfd_, (struct sockaddr *)(&local), sizeof(local));
  • 将 sockfd 和 myaddr 绑定在一起。
  • 成功返回 0,失败返回 -1。
  • 注意:云服务器公网 IP 通常不能直接绑定,一般绑定 0.0.0.0 或内网 IP。

listen()

声明 sockfd 处于监听状态,并设置等待队列长度 backlog。

listen(sockfd_, backlog);
  • 最多允许 backlog 个客户端处于连接等待状态。
  • 成功返回 0,失败返回 -1。

accept()

三次握手完成后,服务器调用 accept() 接受连接。

struct sockaddr_in client;
socklen_t len = sizeof(client);
int new_sockfd = accept(listensockfd_, (struct sockaddr*)(&client), &len);
  • 如果没有客户端连接请求,会阻塞等待。
  • 返回新的文件描述符用于通信,原监听描述符保持不变。
  • 类似于'拉客',主线程继续监听,新连接由新描述符处理。

connect()

客户端需要调用 connect() 连接服务器。

struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(serverport);
inet_pton(AF_INET, serverip.c_str(), &(server.sin_addr));
connect(sockfd, (struct sockaddr*)&server, sizeof(server));
  • 客户端发起 connect 时,系统会自动随机 bind 一个端口。
  • 必须知道服务器的 IP 和端口。

服务端与客户端代码实现

服务端基础结构

#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>

using namespace std;

const int defaultfd = -1;
const string defaultip = "0.0.0.0";
const int backlog = 10;

enum { UsageError = 1, SocketError, BindError, ListenError };

class TcpServer {
public:
    TcpServer(const uint16_t &port, const string &ip = defaultip) 
        : listensockfd_(defaultfd), port_(port), ip_(ip) {}

    void InitServer() {
        // 创建套接字
        listensockfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listensockfd_ < 0) {
            perror("create socket error");
            exit(SocketError);
        }

        // 初始化本地信息
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        inet_aton(ip_.c_str(), &(local.sin_addr));

        // 绑定
        int k = bind(listensockfd_, (struct sockaddr *)(&local), sizeof(local));
        if (k < 0) {
            perror("bind error");
            exit(BindError);
        }

        // 监听
        int ls = listen(listensockfd_, backlog);
        if (ls < 0) {
            perror("listen error");
            exit(ListenError);
        }
    }

    void Start() {
        for (;;) {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(listensockfd_, (struct sockaddr*)(&client), &len);
            if (sockfd < 0) continue;

            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));
            printf("get a new link..., sockfd:%d, client ip:%s, client port:%d\n", 
                   sockfd, clientip, clientport);
            // 此处应启动线程或进程处理 sockfd
        }
    }

private:
    int listensockfd_;
    uint16_t port_;
    string ip_;
};

客户端基础结构

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>

using namespace std;

int main(int argc, char* argv[]) {
    if(argc != 3) {
        cerr << "Usage: ./tcpclient serverip serverport" << endl;
        return 1;
    }
    string serverip = argv[1];
    uint16_t serverport = stoi(argv[2]);

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0) {
        cerr << "socket error" << endl;
        return 1;
    }

    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(serverport);
    inet_pton(AF_INET, serverip.c_str(), &(server.sin_addr));

    int n = connect(sockfd, (struct sockaddr*)&server, sizeof(server));
    if(n < 0) {
        cerr << "connect error" << endl;
        return 2;
    }

    string message;
    while(true) {
        cout << "Please Enter#";
        getline(cin, message);
        write(sockfd, message.c_str(), message.size());

        char inbuffer[4096];
        int read_n = read(sockfd, inbuffer, sizeof(inbuffer));
        if(read_n > 0) {
            inbuffer[read_n] = 0;
            cout << inbuffer << endl;
        }
    }
    close(sockfd);
    return 0;
}

并发模型演进

单进程版本

  • 缺点:只允许一个用户在线,客户端断开后无法处理其他请求。

多进程版本

  • 使用 fork() 创建子进程处理连接。
  • 缺点:消耗资源高,成本太高。

多线程版本

  • 使用 pthread_create() 创建线程处理连接。
  • 优点:比多进程更轻量。
  • 注意:需使用 pthread_detach 分离线程,避免资源泄漏。

线程池版本

  • 使用线程池管理固定数量的工作线程。
  • 优点:控制资源消耗,提高性能。
  • 实现:任务类继承 operator(),放入线程池队列。

守护进程与信号处理

前台与后台进程

  • 前台进程受终端影响,关闭终端可能终止进程。
  • 后台进程独立运行,不受终端关闭影响。

守护进程化步骤

  1. 忽略异常信号:如 SIGCLD, SIGPIPE, SIGSTOP。
  2. 创建新会话:调用 setsid() 脱离控制终端。
  3. 更改目录:切换到根目录 /。
  4. 重定向标准 IO:将 stdin/stdout/stderr 重定向到 /dev/null 或日志文件。

信号处理

常见信号及其含义:

  • SIGHUP: 终端挂断,守护进程通常忽略。
  • SIGINT: Ctrl+C 中断,守护进程通常忽略。
  • SIGTERM: 终止请求,可捕获进行清理。
  • SIGQUIT: 退出并生成 core dump,通常忽略。
  • SIGCHLD: 子进程结束,用于回收僵尸进程。
  • SIGPIPE: 管道破裂,写入已关闭的套接字时触发,建议忽略。

示例代码:

void Daemon(const string &cwd = "") {
    signal(SIGCLD, SIG_IGN);
    signal(SIGPIPE, SIG_IGN);
    signal(SIGSTOP, SIG_IGN);
    
    if(fork() > 0) exit(0);
    setsid();
    
    if(!cwd.empty()) chdir(cwd.c_str());
    
    int fd = open("/dev/null", O_RDWR);
    dup2(fd, 0); dup2(fd, 1); dup2(fd, 2);
    close(fd);
}

测试验证

  • 检查端口:netstat -nltp
  • 查看进程:ps ajx | grep tcpserver
  • 验证后台运行:关闭终端后进程仍在运行。

总结

TCP 通信是全双工的。通过合理设计 Socket API 调用流程,结合多线程或线程池模型,并配置为守护进程运行,可以构建稳定、高效的网络服务器。

目录

  1. TCP Socket 网络编程详解
  2. Socket 类型与参数
  3. 套接字域 (Domain)
  4. 套接字类型 (Type)
  5. 协议 (Protocol)
  6. TCP Socket API 详解
  7. socket()
  8. bind()
  9. listen()
  10. accept()
  11. connect()
  12. 服务端与客户端代码实现
  13. 服务端基础结构
  14. 客户端基础结构
  15. 并发模型演进
  16. 单进程版本
  17. 多进程版本
  18. 多线程版本
  19. 线程池版本
  20. 守护进程与信号处理
  21. 前台与后台进程
  22. 守护进程化步骤
  23. 信号处理
  24. 测试验证
  25. 总结

更多推荐文章

查看全部
  • Linux 进程间通信:匿名管道原理与实现
  • Kotlin 中的扩展函数与属性示例详解
  • 利用 Higress MCP Server 插件将 REST API 转为 AI 工具
  • Python 数据思维:元组基础
  • SpringBoot+Vue 乡村政务办公系统设计与实现
  • 基于 CLIProxyAPI 与 New API 的 AI 模型中转站部署指南
  • 基于 C++11 手写前端 Promise 实现
  • AI 辅助撰写高质量文献综述:操作步骤与提示词指南
  • OpenClaw 飞书机器人配置指南:多渠道 AI 助手集成
  • 2026 年三大 AI 写作工具测评:如何消除英文 AI 痕迹
  • 多材料 3D 打印软机器人:集成驱动与自主避障技术解析
  • Python 核心语法:函数定义与使用详解
  • Visual Studio 使用 GitHub Copilot 与 IntelliCode 辅助编码
  • OpenClaw Gateway 命令与交互指南
  • IntelliJ IDEA 2026.1 EAP 发布:Java 26 与 Spring Boot 4 支持
  • OpenClaw:AI 直连并操控本地电脑
  • HTTP 应用层协议详解
  • 前端高频面试题:TypeScript 篇
  • 2026 年 Web 前端开发的 8 大趋势
  • LangChain 工具调用与结构化输出实战

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online