跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
C++

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

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

小熊软糖发布于 2026/3/16更新于 2026/5/417 浏览
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. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • GPT-5.5 超高智商模型1元抵1刀ChatGPT中转购买
  • 代充Chatgpt Plus/pro 帐号了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 基于 nomic-embed-text-v2-moe 与 Gradio 构建多语言文本相似度 WebUI
  • learn-claude-code:从零理解 AI Agent 设计与实现
  • 自然语言处理在社交媒体分析中的应用与实战
  • 前端加密 encrypt-labs 靶场:环境搭建与全关卡解析
  • Python 网址匹配正则表达式实战
  • Python Requests 库网络爬虫基础与实战
  • VSCode + GitHub Copilot AI 编程实战指南
  • VSCode 集成 GitHub Copilot 使用指南
  • VS Code 中常用的 Python 代码格式化工具
  • Neo4j APOC 插件安装与配置指南
  • Web3 技术解析:下一代互联网范式与普通人应用指南
  • DeepSeek 深度使用指南:提示词技巧与本地知识库搭建
  • Python 非官方 Google 搜索 API 集成指南
  • OpenClaw 入门指南:AI Agent 本地部署与优化
  • 基于 Redis 与 Caffeine 的图片系统性能优化及分布式 Session 实践
  • Prompt 驱动的结构化抽取:从文本中提取表格
  • Linux 远程服务器直接下载 HuggingFace 模型与数据集
  • 二叉树深度计算与先序序列重构算法解析
  • Python 数学可视化:显函数、隐函数及复杂曲线交互绘图
  • Consistency Model 重塑图像生成范式:100 倍提速技术解析

相关免费在线工具

  • 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