Socket编程实战:从基础API到多线程服务器

作者:violet-lz日期:2025/11/8

一、Socket编程概述:网络通信的桥梁

Socket(套接字)是网络通信的端点,它提供了不同主机间进程通信的接口。在Linux系统中,Socket可以被视为一种特殊的文件描述符,通过标准的文件I/O操作来进行网络数据传输。

Socket编程的核心概念

通信域:确定通信的协议族和地址格式

套接字类型:定义通信的语义和特性

协议:指定具体的传输协议

地址:标识网络中的通信端点

学习Socket编程的重要性

网络应用开发的基础

理解网络协议的实现原理

系统编程能力的重要体现

二、socket()函数详解:创建通信端点

socket()函数是Socket编程的起点,用于创建通信端点。

函数原型

int socket(int domain, int type, int protocol);

参数详解表

参数类型说明常用值示例值含义
domainint协议族/地址族AF_INET, AF_INET6, AF_UNIXAF_INET: IPv4网络通信
typeint套接字类型SOCK_STREAM, SOCK_DGRAMSOCK_STREAM: TCP流式套接字
protocolint具体协议0, IPPROTO_TCP, IPPROTO_UDP0: 根据前两个参数自动选择

常用参数组合

TCP套接字

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

UDP套接字

int udp_socket = socket(AF_INET, SOCK_DGRAM, 0);

本地套接字

int local_socket = socket(AF_UNIX, SOCK_STREAM, 0);

返回值说明

成功:返回非负的文件描述符 失败:返回-1,并设置errno

记忆技巧:将socket()参数记为"族型协"——协议族、套接字类型、协议。

三、bind()函数与sockaddr_in结构体

bind()函数将套接字与特定的IP地址和端口号关联起来。

函数原型

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockaddr_in结构体详解

1struct sockaddr_in {
2    sa_family_t    sin_family;   // 地址族,如AF_INET
3    in_port_t      sin_port;     // 端口号(网络字节序)
4    struct in_addr sin_addr;     // IP地址(网络字节序)
5    unsigned char  sin_zero[8];  // 填充字段,通常设为0
6};
7
8struct in_addr {
9    uint32_t s_addr;             // IPv4地址
10};

地址设置示例

1struct sockaddr_in server_addr;
2memset(&server_addr, 0, sizeof(server_addr));
3server_addr.sin_family = AF_INET;
4server_addr.sin_port = htons(8080);                // 端口8080
5server_addr.sin_addr.s_addr = htonl(INADDR_ANY);   // 任意网络接口

bind()使用示例

1int server_fd = socket(AF_INET, SOCK_STREAM, 0);
2struct sockaddr_in addr;
3memset(&addr, 0, sizeof(addr));
4addr.sin_family = AF_INET;
5addr.sin_port = htons(8080);
6addr.sin_addr.s_addr = INADDR_ANY;
7
8if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
9    perror("bind failed");
10    exit(EXIT_FAILURE);
11}

关键点

需要将sockaddr_in强制转换为sockaddr*

端口和地址必须使用网络字节序(大端序)

INADDR_ANY表示绑定到所有可用的网络接口

四、listen()与accept()函数详解

listen()函数

listen()将套接字转换为被动套接字,开始监听连接请求。

int listen(int sockfd, int backlog);

参数说明

   sockfd:已绑定的套接字描述符

    backlog:连接请求队列的最大长度

backlog参数详解

表示已完成三次握手但尚未被accept()接受的连接数

典型值:5-10(根据服务器负载能力调整)

过大:浪费内核资源;过小:可能导致连接被拒绝

accept()函数

accept()从监听队列中接受连接,创建新的连接套接字。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数说明

   sockfd:监听套接字描述符

   addr:输出参数,存储客户端地址信息

   addrlen:输入输出参数,指定地址结构大小

使用示例

1int server_fd = socket(AF_INET, SOCK_STREAM, 0);
2// ... bind操作 ...
3
4if (listen(server_fd, 5) < 0) {
5    perror("listen failed");
6    exit(EXIT_FAILURE);
7}
8
9printf("Server listening on port 8080...\n");
10
11struct sockaddr_in client_addr;
12socklen_t client_len = sizeof(client_addr);
13int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
14if (client_fd < 0) {
15    perror("accept failed");
16    exit(EXIT_FAILURE);
17}
18
19printf("Client connected from %s:%d\n", 
20       inet_ntoa(client_addr.sin_addr), 
21       ntohs(client_addr.sin_port));

五、监听套接字 vs 连接套接字

理解两种套接字的区别对于编写正确的服务器程序至关重要。

对比分析表

特性监听套接字连接套接字
创建方式socket()创建accept()返回
角色被动接受连接主动数据通信
生命周期整个服务器运行期间单个连接期间
数量通常1个每个客户端连接1个
操作bind(), listen(), accept()send(), recv(), close()
端口使用绑定特定端口使用相同端口但不同描述符

套接字状态转换

socket() → bind() → listen() → accept() → 新连接套接字 ↑ ↑ ↑ ↑ 监听套接字 绑定地址 开始监听 接受连接

重要概念:监听套接字只负责接受新连接,不用于数据传输。每个接受的连接都会创建一个新的连接套接字专门处理该客户端通信。

六、connect()、getpeername()、close()等函数使用

connect()函数

客户端使用connect()主动连接服务器。

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

使用示例

1int client_fd = socket(AF_INET, SOCK_STREAM, 0);
2struct sockaddr_in server_addr;
3memset(&server_addr, 0, sizeof(server_addr));
4server_addr.sin_family = AF_INET;
5server_addr.sin_port = htons(8080);
6inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
7
8if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
9    perror("connect failed");
10    exit(EXIT_FAILURE);
11}
12printf("Connected to server\n");

getpeername()函数

获取对端套接字的地址信息。

int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

使用场景

服务器想知道客户端的详细信息

调试和日志记录

安全审计

close()函数

关闭套接字,释放资源。

int close(int fd);

重要提示

关闭套接字会触发TCP连接终止序列

服务器需要关闭监听套接字和所有连接套接字

关闭后文件描述符不再有效

完整函数参考表

函数头文件参数说明返回值主要用途
socket()<sys/socket.h>domain, type, protocol套接字描述符创建通信端点
bind()<sys/socket.h>sockfd, addr, addrlen0成功/-1失败绑定地址到套接字
listen()<sys/socket.h>sockfd, backlog0成功/-1失败开始监听连接
accept()<sys/socket.h>sockfd, addr, addrlen新套接字描述符接受客户端连接
connect()<sys/socket.h>sockfd, addr, addrlen0成功/-1失败连接服务器
getpeername()<sys/socket.h>sockfd, addr, addrlen0成功/-1失败获取对端地址
close()<unistd.h>fd0成功/-1失败关闭套接字

七、多线程与pthread_detach()

多线程服务器可以同时处理多个客户端连接,提高服务器并发能力。

pthread_create()创建线程

1int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
2                   void *(*start_routine) (void *), void *arg);

pthread_detach()分离线程

设置线程为分离状态,线程结束后自动释放资源。

int pthread_detach(pthread_t thread);

为什么使用pthread_detach()?

分离线程不需要主线程调用pthread_join()等待

线程结束后自动回收资源

避免内存泄漏

多线程服务器示例

1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <pthread.h>
6#include <sys/socket.h>
7#include <netinet/in.h>
8#include <arpa/inet.h>
9#define PORT 8080
10#define BUFFER_SIZE 1024
11void* handle_client(void* arg) {
12    int client_fd = *(int*)arg;
13    free(arg); // 释放动态分配的内存
14    char buffer[BUFFER_SIZE];
15    ssize_t bytes_read;
16    pthread_detach(pthread_self()); // 分离线程,自动回收资源
17    while ((bytes_read = recv(client_fd, buffer, sizeof(buffer) - 1, 0)) > 0) {
18        buffer[bytes_read] = '\0';
19        printf("Received: %s", buffer);
20        send(client_fd, buffer, bytes_read, 0); // 回显数据
21    }
22    close(client_fd);
23    printf("Client disconnected\n");
24    return NULL;
25}
26int main() {
27    int server_fd, *client_fd;
28    struct sockaddr_in address;
29    socklen_t addrlen = sizeof(address);
30    pthread_t thread_id;
31    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
32        perror("socket failed");
33        exit(EXIT_FAILURE);
34    }
35    address.sin_family = AF_INET;
36    address.sin_addr.s_addr = INADDR_ANY;
37    address.sin_port = htons(PORT);
38    if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
39        perror("bind failed");
40        exit(EXIT_FAILURE);
41    }
42    if (listen(server_fd, 10) < 0) {
43        perror("listen");
44        exit(EXIT_FAILURE);
45    }
46    printf("Multi-threaded server listening on port %d...\n", PORT);
47    while (1) {
48        client_fd = malloc(sizeof(int)); // 为每个客户端动态分配内存
49        if (!client_fd) {
50            perror("malloc failed");
51            continue;
52        }
53        *client_fd = accept(server_fd, (struct sockaddr*)&address, &addrlen);
54        if (*client_fd < 0) {
55            perror("accept");
56            free(client_fd);
57            continue;
58        }
59        printf("New client connected: %s:%d\n", 
60               inet_ntoa(address.sin_addr), ntohs(address.sin_port));
61        if (pthread_create(&thread_id, NULL, handle_client, client_fd) != 0) {
62            perror("pthread_create");
63            close(*client_fd);
64            free(client_fd);
65        }
66    }
67    close(server_fd);
68    return 0;
69}

八、完整代码示例:TCP服务器与客户端

TCP服务器完整代码

1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <sys/socket.h>
6#include <netinet/in.h>
7#include <arpa/inet.h>
8#define PORT 8080
9#define MAX_CLIENTS 10
10#define BUFFER_SIZE 1024
11void handle_connection(int client_fd, struct sockaddr_in client_addr) {
12    char buffer[BUFFER_SIZE];
13    ssize_t bytes_read;
14    printf("Handling client %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
15    while ((bytes_read = recv(client_fd, buffer, sizeof(buffer) - 1, 0)) > 0) {
16        buffer[bytes_read] = '\0';
17        printf("From %s:%d: %s", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer);
18        if (send(client_fd, buffer, bytes_read, 0) < 0) {
19            perror("send failed");
20            break;
21        }
22        if (strncmp(buffer, "quit", 4) == 0) {
23            printf("Client %s:%d requested to quit\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
24            break;
25        }
26    }
27    close(client_fd);
28    printf("Client %s:%d disconnected\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
29}
30int main() {
31    int server_fd, client_fd;
32    struct sockaddr_in server_addr, client_addr;
33    socklen_t client_len = sizeof(client_addr);
34    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
35        perror("socket creation failed");
36        exit(EXIT_FAILURE);
37    }
38    int opt = 1;
39    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
40        perror("setsockopt");
41        exit(EXIT_FAILURE);
42    }
43    server_addr.sin_family = AF_INET;
44    server_addr.sin_addr.s_addr = INADDR_ANY;
45    server_addr.sin_port = htons(PORT);
46    if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
47        perror("bind failed");
48        close(server_fd);
49        exit(EXIT_FAILURE);
50    }
51    if (listen(server_fd, MAX_CLIENTS) < 0) {
52        perror("listen failed");
53        close(server_fd);
54        exit(EXIT_FAILURE);
55    }
56    printf("TCP Echo Server listening on port %d...\n", PORT);
57    printf("Server will echo back received messages. Send 'quit' to disconnect.\n");
58    while (1) {
59        client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
60        if (client_fd < 0) {
61            perror("accept failed");
62            continue;
63        }
64        handle_connection(client_fd, client_addr);
65    }
66    close(server_fd);
67    return 0;
68}

TCP客户端完整代码

1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <sys/socket.h>
6#include <netinet/in.h>
7#include <arpa/inet.h>
8#define SERVER_IP "127.0.0.1"
9#define SERVER_PORT 8080
10#define BUFFER_SIZE 1024
11int main() {
12    int sockfd;
13    struct sockaddr_in server_addr;
14    char buffer[BUFFER_SIZE];
15    ssize_t bytes_sent, bytes_received;
16    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
17        perror("socket creation failed");
18        exit(EXIT_FAILURE);
19    }
20    server_addr.sin_family = AF_INET;
21    server_addr.sin_port = htons(SERVER_PORT);
22    if (inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr) <= 0) {
23        perror("invalid address");
24        close(sockfd);
25        exit(EXIT_FAILURE);
26    }
27    if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
28        perror("connection failed");
29        close(sockfd);
30        exit(EXIT_FAILURE);
31    }
32    printf("Connected to server %s:%d\n", SERVER_IP, SERVER_PORT);
33    printf("Type messages to send to server (type 'quit' to exit):\n");
34    while (1) {
35        printf("Client: ");
36        if (!fgets(buffer, sizeof(buffer), stdin)) {
37            break;
38        }
39        bytes_sent = send(sockfd, buffer, strlen(buffer), 0);
40        if (bytes_sent < 0) {
41            perror("send failed");
42            break;
43        }
44        if (strncmp(buffer, "quit", 4) == 0) {
45            printf("Disconnecting...\n");
46            break;
47        }
48        bytes_received = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
49        if (bytes_received < 0) {
50            perror("recv failed");
51            break;
52        } else if (bytes_received == 0) {
53            printf("Server closed connection\n");
54            break;
55        }
56        buffer[bytes_received] = '\0';
57        printf("Server: %s", buffer);
58    }
59    close(sockfd);
60    printf("Connection closed\n");
61    return 0;
62}

九、常见面试题精析

1. socket()函数中AF_INET和PF_INET有什么区别?

参考答案
AF_INET表示地址族(Address Family),PF_INET表示协议族(Protocol Family)。在大多数实现中,它们被定义为相同的值,可以互换使用。但严格来说:

AF_xxx用于地址结构(如sockaddr_in)

PF_xxx用于协议族(如socket()的第一个参数)

2. TCP服务器为什么需要调用listen()函数?

参考答案
listen()函数将主动套接字转换为被动套接字,使其能够接受连接请求。具体作用:

创建连接请求队列

设置同时等待处理的最大连接数

使套接字进入监听状态

3. accept()函数返回的套接字和监听套接字有什么区别?

参考答案

监听套接字:用于接受新连接,生命周期与服务器相同

连接套接字:用于与特定客户端通信,每个客户端连接一个

监听套接字绑定到固定端口,连接套接字使用相同端口但不同文件描述符

4. 什么是字节序?网络编程中为什么要处理字节序?

参考答案
字节序是多字节数据在内存中的存储顺序:

大端序:高位字节存储在低地址

小端序:低位字节存储在低地址

网络编程使用**网络字节序(大端序)**保证不同架构主机间的兼容性。需要使用htons()、htonl()、ntohs()、ntohl()进行转换。

5. 多线程服务器中为什么建议使用pthread_detach()?

参考答案

分离线程结束后自动释放资源,避免内存泄漏

不需要主线程调用pthread_join()等待线程结束

提高资源利用率,避免僵尸线程

简化线程管理代码

6. 如何优雅地关闭套接字连接?

参考答案

  • 服务器端:先close()连接套接字,最后close()监听套接字
  • 客户端:调用close()关闭连接
  • 可以使用shutdown()控制关闭方向:
    SHUT_RD:关闭读端 SHUT_WR:关闭写端 SHUT_RDWR:完全关闭

7. 什么是SO_REUSEADDR选项?有什么作用?

参考答案
SO_REUSEADDR允许套接字绑定到处于TIME_WAIT状态的地址。作用:

服务器重启后可以立即重用相同端口

避免"Address already in use"错误

提高服务器可用性

8. 如何实现一个并发服务器?

参考答案
几种常见的并发模型:

多进程:fork()创建子进程处理连接

多线程:pthread_create()创建线程处理连接

I/O多路复用:select()/poll()/epoll()监控多个套接字

异步I/O:aio_*系列函数

9. TCP的粘包问题如何解决?

参考答案

固定长度:所有消息采用相同长度

长度前缀:在消息前添加长度字段

分隔符:使用特殊字符作为消息边界

协议设计:设计自描述的应用层协议

10. 什么是非阻塞I/O?如何设置非阻塞套接字?

参考答案
非阻塞I/O使操作立即返回,不等待操作完成。

设置方法

1#include <fcntl.h>
2int flags = fcntl(sockfd, F_GETFL, 0);
3fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

总结

Socket编程是网络应用开发的核心技术,通过本文的学习,你应该掌握:

  1. 核心API理解:socket()、bind()、listen()、accept()等函数的作用和参数
  2. 套接字类型区分:监听套接字与连接套接字的不同角色
  3. 地址处理能力:sockaddr_in结构体的使用和字节序转换
  4. 并发编程技巧:多线程服务器的实现和线程管理
  5. 完整项目实践:TCP服务器和客户端的完整实现
  6. 面试准备充分:常见Socket编程面试题的解答

进阶学习建议

学习I/O多路复用(select/poll/epoll)

掌握非阻塞I/O和异步编程

理解网络协议底层原理

实践实际项目,如HTTP服务器、聊天程序等


Socket编程实战:从基础API到多线程服务器》 是转载文章,点击查看原文


相关推荐


Python编程实战 · 基础入门篇 | 列表(list)
程序员爱钓鱼2025/11/6

在 Python 中,列表(list) 是最常用、最灵活的数据结构之一。 它能存放多个数据,可以增删改查,还能嵌套其他列表,是编程中处理“集合类信息”的核心工具。 本章我们将系统学习列表的定义、操作方法、常用函数与实战应用。 一、什么是列表 列表(list)是一个 有序、可变 的元素集合。 它可以存储任意类型的数据,包括数字、字符串、布尔值、甚至其他列表。 示例: numbers = [1, 2, 3, 4, 5] fruits = ["apple", "banana", "cherry"]


Python 的内置函数 float
IMPYLH2025/11/1

Python 内建函数列表 > Python 的内置函数 float Python 的内置函数 float() 是一个用于将数字或字符串转换为浮点数(即带有小数部分的数字)的函数。它是 Python 中处理数值转换的重要工具之一,常用于数据类型转换和数值计算场景。 功能说明 无参数调用:当不带任何参数调用时,float() 会返回 0.0 print(float()) # 输出: 0.0 数字转换: 整数转换为浮点数print(float(5)) # 输出: 5.0 布尔


【操作系统】计算机系统概述
.笑对人生.2025/10/30

目录 一、操作系统的基本概念 (一)操作系统的概念 (二)操作系统的功能和目标 (三)操作系统的特征 二、操作系统发展历程 (一)手工操作阶段(此阶段无操作系统) (二)批处理阶段(操作系统开始出现) (三)分时操作系统 (四)实时操作系统 (五)网络操作系统和分布式计算机系统 (六)个人计算机操作系统 三、操作系统的运行环境 (一)处理器运行模式 (二)中断和异常的概念 (三)系统调用 (四)操作系统运行环境的切换 四、操作系统结构 五、操作系统引导


搭建虚拟机完全分布式(centos)
小鹿学程序2025/10/27

在搭建完全分布式集群前,通常需要先在一台基础节点(可作为主节点或模板节点) 上完成基础环境配置,后续再通过克隆或批量操作同步到其他节点。以下是详细的实操步骤(以 CentOS 7 为例,其他 Linux 发行版操作类似): 一、准备工作 操作系统:确保基础节点已安装好 Linux 系统(推荐 CentOS 7/8、Ubuntu 20.04 等),并配置好静态 IP(避免 IP 动态变化影响集群通信)。 查看 IP:ip addr 配置静态 IP(CentOS 7):编辑 /etc/syscon


系统权限与信息收集:从CPU架构到后渗透实战的完整技术体系
PyHaVolask2025/10/24

文章目录 前言系统权限体系Windows权限层级权限等级划分各权限特点详解权限实战应用 Linux权限体系权限结构权限查看 虚拟机环境配置 CPU保护环机制Ring架构概述Ring 0(内核态)Ring 3(用户态)硬件黑客技术BadUSB攻击USB Killer(烧鹅)高级侧信道攻击 漏洞编号体系Microsoft漏洞编号(MS)CVE漏洞编号CNNVD漏洞编号漏洞研究资源 GitHub技术积累账号建设价值技术搜索技巧开源贡献建议 后渗透信息收集MSF信息收


scrapy爬取豆瓣电影
Derrick__12025/10/22

在李玺老师《爬虫逆向进阶实战》中了解到scrapy后,本意是打算利用b站上更详细的教程爬取一下豆瓣网站国产高分电影的列表。 但是最后爬取出来的结果并没有成功分出国产这一栏目 在ai帮我调试了好几次也没有做好


【自动化测试07】nodejs代码覆盖率测试工具Istanbul(nyc)
郑同学的笔记2025/10/21

【自动化测试07】nodejs代码覆盖率测试工具Istanbul(nyc) 一、代码覆盖率? 二、测试nodejs代码覆盖率的工具优缺点介绍 三、Istanbul(nyc) 1、简介 2、官网 3、安装 4、在项目的package.json 脚本中添加如下命令: 5、配置脚本:在你的项目根目录中,创建一个名为 .nycrc 的文件,并添加以下配置信息: 6、运行测试并生成覆盖率报告:在你的项目根


Redis(72)Redis分布式锁的常见使用场景有哪些?
Victor3562025/10/20

Redis分布式锁在很多需要协调多个分布式系统或组件的场景中都能发挥重要作用。以下是一些常见的使用场景以及相应的代码示例: 常见使用场景 防止资源竞争: 多个进程或线程需要访问同一共享资源时,使用分布式锁可以防止资源竞争,确保同一时间只有一个进程或线程在操作该资源。 定时任务调度: 在分布式系统中,确保某个定时任务在同一时刻只被一个调度器执行,避免重复执行任务。 库存扣减: 电商系统中,多个用户同时下单时,需要确保库存扣减操作的原子性和一致性。 分布式事务: 在跨多


Java中Elasticsearch完全指南:从零基础到实战应用
xxxxxxllllllshi2025/10/19

Java中Elasticsearch完全指南:从零基础到实战应用 环境准备与基础概念 Elasticsearch 与关系型数据库核心概念对比 对于零基础读者,理解 Elasticsearch 的核心概念最直观的方式是与熟悉的关系型数据库进行类比。以下对比表清晰展示了两者核心组件的对应关系: Elasticsearch 概念关系型数据库概念说明索引(Index)数据库(Database)存储相关文档的集合,相当于关系型数据库中的数据库文档(Document)行(Row)索引中的一条数据记录


PCIe协议之 flit 模式 之 速率 vs flit/non-flit vs 编码方式对比汇总
那么菜2025/10/17

一、归纳对比汇总表 特性维度 PCIe 1.0-5.0 (非 FLIT 模式) PCIe 6.0 (FLIT 模式) 适用速率 2.5 GT/s (Gen1), 5.0 GT/s (Gen2), 8.0 GT/s (Gen3), 16.0 GT/s (Gen4), 32.0 GT/s (Gen5) 64.0 GT/s (Gen6) 数据包模式 非 FLIT 模式、FLIT

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0