前言

Socket(套接字)是 TCP/IP 网络体系中,位于应用层与传输层之间的标准网络编程接口。套接字本质是一种特殊的文件描述符,操作系统将网络通信行为抽象为文件读写,开发者可通过 read、write 等文件操作函数,实现跨主机、跨进程的网络数据收发,完成双向网络通信。

TCP 协议对应流式套接字(SOCK_STREAM),具备三大核心特性:面向连接、可靠传输、有序无重复。通信前通过三次握手建立专属连接通道,保障数据可靠交付;通信结束后通过四次挥手正常释放连接资源。

TCP 网络通信默认采用客户端-服务器(C/S)架构:服务器负责监听、接收连接、处理业务数据;客户端主动发起连接请求,与服务端建立通信会话。

本文优化说明:市面多数基础 Demo 仅实现「单向发送、无应答」的简易通信,存在逻辑残缺。本文基于标准 TCP 双向通信流程,修复单向通信缺陷,配套完整一问一答双向交互可运行源码,适配零基础学习与工程入门参考。

一、TCP 整体通信时序与核心流程

TCP 通信存在严格的先后执行顺序:必须先启动服务器完成初始化,再启动客户端发起连接,否则客户端连接会直接失败。

1.1 TCP 服务器完整执行流程

服务端核心职责:创建服务端点、绑定地址端口、开启监听、等待客户端接入、处理双向数据交互、释放资源。完整调用链路如下:

socket() → bind() → listen() → accept() → 双向数据读写 → close()

各步骤详细解析:

1. 创建套接字 socket():生成专属监听套接字文件描述符 server_fd,专门用于监听和接收新客户端连接,不负责业务数据收发

2. 绑定地址端口 bind():为套接字绑定本机 IP 地址与固定端口号,确定服务唯一访问入口,客户端通过「IP+端口」精准定位服务器程序。

3. 开启监听 listen():将普通套接字转换为监听套接字,设置连接等待队列上限,系统开始持续监听客户端的连接请求。

4. 阻塞接收连接 accept():核心阻塞函数,无客户端连接时程序休眠等待;客户端三次握手完成后,函数返回全新的通信套接字,专门用于数据交互。

核心区分:监听套接字(server_fd)只负责接收新连接;所有数据收发、业务交互,必须使用 accept 返回的通信套接字。

5. 双向数据交互:通过通信套接字读取客户端数据,完成业务逻辑处理后,向客户端返回应答数据,实现完整双向通信。

6. 释放资源 close():客户端断开后关闭对应通信套接字;服务程序退出时,关闭监听套接字,释放端口、文件描述符等系统资源。

1.2 TCP 客户端完整执行流程

客户端核心职责:创建套接字、主动发起连接、与服务端双向收发数据、断开连接释放资源。完整调用链路如下:

socket() → connect() → 数据发送 → 应答接收 → close()

各步骤详细解析:

1. 创建套接字 socket():创建客户端流式套接字,生成客户端专属文件描述符。

2. 发起连接 connect():填入服务器 IP 与端口,主动向服务端发起 TCP 连接请求,底层自动完成三次握手,建立通信通道。

3. 双向数据交互:连接建立成功后,向服务端发送业务数据,同时阻塞接收服务端返回的应答报文。

缺陷修复:传统入门代码仅实现客户端单向发送,缺失应答接收逻辑,本文代码已完整补齐双向收发能力。

4. 断开连接释放资源:收到退出指令后,调用 close 关闭套接字,触发 TCP 四次挥手,正常断开连接、释放系统资源。

二、TCP 核心通信 API 详解

TCP 套接字编程所有功能,均依托固定系统 API 实现,各函数功能、使用主体明确,是网络编程核心基础。

核心函数

核心功能说明

调用主体

socket()

创建流式套接字,返回套接字文件描述符,完成网络通信初始化

服务端、客户端

bind()

绑定本机 IP 与端口号,固定服务访问地址,对外暴露服务入口

主要服务端调用,客户端可选

listen()

将普通套接字转为监听套接字,设置连接等待队列,开启监听状态

仅服务端调用

accept()

阻塞等待客户端连接,三次握手完成后返回数据通信套接字

仅服务端调用

connect()

主动向远端服务器发起 TCP 连接请求,完成三次握手建连

仅客户端调用

read()/recv()

从套接字缓冲区读取对端发送的网络数据

服务端、客户端

write()/send()

向套接字缓冲区写入数据,发送给通信对端

服务端、客户端

close()/shutdown()

关闭套接字,释放文件描述符、端口、TCP 连接等系统资源

服务端、客户端

三、TCP 一对一通信模型解析

一对一串行通信是 TCP 最基础的通信模型,也是入门学习的核心模型,所有基础 Demo 均基于该模型实现。

3.1 模型运行逻辑

1. 服务端完成 socket、bind、listen 初始化后,阻塞在 accept 函数,等待客户端接入;

2. 成功连接单个客户端后,进入数据交互循环,持续处理当前客户端的收发请求;

3. 串行阻塞特性:当前客户端未断开连接时,服务端无法执行 accept,不能接收新的客户端连接;

4. 客户端主动退出、关闭通信套接字后,服务端结束当前会话,重新阻塞在 accept,等待下一个客户端接入。

3.2 模型优缺点

优点:逻辑简单、流程清晰、代码极简,适合初学者理解 TCP 三次握手、数据交互、四次挥手完整流程。

缺点:无并发能力,同一时刻仅能服务一个客户端,无法满足多用户同时访问的业务场景,仅适用于学习测试。

四、TCP 一对一双向通信完整可运行代码

以下为 Linux C 语言完整源码,已修复单向通信缺陷,实现客户端发消息、服务端自动应答的标准双向交互,可直接编译运行测试。

4.1 服务端代码(server.c)

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

#define PORT 8888
#define BUF_SIZE 1024

int main(void)
{
    // 1. 创建监听套接字
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(server_fd < 0)
    {
        perror("socket create fail");
        return -1;
    }

    // 配置服务器地址信息
    struct sockaddr_in s_addr;
    s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(PORT);
    s_addr.sin_addr.s_addr = INADDR_ANY;
    memset(s_addr.sin_zero, 0, sizeof(s_addr.sin_zero));

    // 2. 绑定IP和端口
    if(bind(server_fd, (struct sockaddr *)&s_addr, sizeof(s_addr)) < 0)
    {
        perror("bind fail");
        close(server_fd);
        return -1;
    }

    // 3. 开启监听
    if(listen(server_fd, 5) < 0)
    {
        perror("listen fail");
        close(server_fd);
        return -1;
    }
    printf("服务端启动成功,监听端口:%d\n", PORT);

    char buf[BUF_SIZE] = {0};
    // 循环等待客户端连接
    while(1)
    {
        struct sockaddr_in c_addr;
        socklen_t c_len = sizeof(c_addr);
        // 4. 阻塞等待客户端连接
        int conn_fd = accept(server_fd, (struct sockaddr *)&c_addr, &c_len);
        if(conn_fd < 0)
        {
            perror("accept fail");
            continue;
        }
        printf("客户端连接成功!\n");

        // 双向数据交互循环
        while(1)
        {
            memset(buf, 0, BUF_SIZE);
            // 读取客户端数据
            int ret = read(conn_fd, buf, BUF_SIZE);
            if(ret <= 0)
            {
                printf("客户端断开连接\n");
                break;
            }
            printf("接收客户端消息:%s\n", buf);

            // 服务端返回应答消息
            char rsp[BUF_SIZE] = {0};
            snprintf(rsp, BUF_SIZE, "服务端已收到:%s", buf);
            write(conn_fd, rsp, strlen(rsp));
        }
        close(conn_fd);
    }

    close(server_fd);
    return 0;
}

4.2 客户端代码(client.c)


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

#define PORT 8888
#define BUF_SIZE 1024

int main(void)
{
    // 1. 创建客户端套接字
    int client_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(client_fd < 0)
    {
        perror("socket create fail");
        return -1;
    }

    // 配置服务器地址信息
    struct sockaddr_in s_addr;
    s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &s_addr.sin_addr);
    memset(s_addr.sin_zero, 0, sizeof(s_addr.sin_zero));

    // 2. 发起连接请求
    if(connect(client_fd, (struct sockaddr *)&s_addr, sizeof(s_addr)) < 0)
    {
        perror("connect fail");
        close(client_fd);
        return -1;
    }
    printf("成功连接服务端!\n");

    char send_buf[BUF_SIZE] = {0};
    char recv_buf[BUF_SIZE] = {0};

    // 循环双向通信
    while(1)
    {
        printf("请输入发送消息(输入exit退出):");
        fgets(send_buf, BUF_SIZE, stdin);

        // 退出逻辑
        if(strstr(send_buf, "exit"))
            break;

        // 发送数据到服务端
        write(client_fd, send_buf, strlen(send_buf));
        memset(recv_buf, 0, BUF_SIZE);
        // 接收服务端应答
        read(client_fd, recv_buf, BUF_SIZE);
        printf("接收服务端应答:%s\n\n", recv_buf);
    }

    close(client_fd);
    return 0;
}

五、编译与运行教程

5.1 编译命令(Linux 环境)

gcc server.c -o server 
gcc client.c -o client

5.2 运行顺序

1. 终端1启动服务端:./server

2. 终端2启动客户端:./client

3. 客户端输入任意消息,服务端自动回复应答,输入 exit 可退出客户端、断开 TCP 连接。

六、总结

1. TCP 套接字编程核心分为服务端初始化流程客户端建连流程,启动时序不可颠倒;

2. 严格区分监听套接字通信套接字,职责分离是 TCP 编程的核心关键点;

3. 本文代码补齐了传统 Demo 的单向通信缺陷,实现标准 C/S 架构双向问答通信;

4. 一对一模型适合入门学习,若需支持多客户端并发,可在此基础上拓展多进程、多线程或 IO 多路复用模型。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐