服务器模型
在 网络编程 中,服务器通常需要处理多个客户端的请求。根据服务器处理多个客户端的方式,可以分为 循环服务器模型 和 并发服务器模型。
在网络程序里面,通常都是一个服务器处理多个客户机。为了处理多个客户机的请求, 服务器端的程序有不同的处理方式。目前最常用的服务器模型.
循环服务器:循环服务器在同一个时刻只能响应一个客户端的请求
并发服务器:并发服务器在同一个时刻可以响应多个客户端的请求
📌 1. 循环服务器模型
目前最常用的服务器模型.
1》循环服务器:循环服务器在同一个时刻只能响应一个客户端的请求 TCP服务器端运行后等待客户端的连接请求。TCP服务器接受一个客户端的连接后开始处理,完成了客户的所有请求后断开连接。 TCP循环服务器一次只能处理一个客户端的请求。只有在当前客户的所有请求都完成后,服务器才能处理下一个客户的连接/服务请求。如果某个客户端一直占用服务器资源,那么其它的客户端都不能被处理。TCP服务器一般很少采用循环服务器模型
特点:
- 服务器 一次只能处理一个客户端 的请求,其他客户端必须等待。
- 如果某个客户端 长时间占用服务器,其他客户端无法访问。
- 适用于 简单应用 或 单客户端环境,但 不适合大并发场景。
✅ 一、TCP 循环服务器
工作流程:
-
创建套接字(
socket()
) -
绑定 IP 和端口(
bind()
) -
监听连接(
listen()
) -
循环等待客户端连接(
accept()
) -
接收请求并处理(
recv()
->process()
->send()
) -
关闭连接(
close()
) -
处理下一个客户端
socket(...);bind(...);listen(...);while(1){accept(...);while(1){recv(...);process(...);send(...);}close(...);}
TCP 循环服务器代码示例(C 语言):
代码功能
- 服务器监听 指定端口
- 单客户端模式:一次只能处理一个客户端
- 客户端连接后可以发送消息,服务器 回显(echo) 该消息
- 服务器处理完 当前客户端 后,才能接受下一个客户端连接
C语言实现:代码可执行(每个环节都标记上了重点,每一步流程根据上述编程思路实现,依次执行代码,已经过测试,代码可直接使用)
#include <stdio.h> // 标准输入输出
#include <stdlib.h> // exit()、malloc()等
#include <string.h> // 字符串操作
#include <unistd.h> // read(), write(), close()
#include <arpa/inet.h> // sockaddr_in, inet_addr()
#include <sys/socket.h> // 套接字 API
#include <netinet/in.h> // sockaddr_in 结构体#define PORT 8080 // 服务器监听端口
#define BUFFER_SIZE 1024 // 缓冲区大小int main() {int server_fd, client_fd; // 服务器和客户端的 socket 文件描述符struct sockaddr_in server_addr, client_addr; // 服务器和客户端的地址结构socklen_t addr_len = sizeof(client_addr); // 地址结构大小char buffer[BUFFER_SIZE]; // 消息缓冲区int bytes_read;// 1️⃣ 创建服务器套接字 (socket)server_fd = socket(AF_INET, SOCK_STREAM, 0);if (server_fd == -1) {perror("Socket 创建失败");exit(EXIT_FAILURE);}// 2️⃣ 绑定服务器地址和端口 (bind)server_addr.sin_family = AF_INET; // 使用 IPv4server_addr.sin_addr.s_addr = INADDR_ANY; // 监听所有 IPserver_addr.sin_port = htons(PORT); // 设置端口(网络字节序)if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("绑定失败");close(server_fd);exit(EXIT_FAILURE);}// 3️⃣ 监听客户端连接 (listen)if (listen(server_fd, 5) < 0) { // 最多允许 5 个客户端排队等待perror("监听失败");close(server_fd);exit(EXIT_FAILURE);}printf("⚡ TCP 服务器已启动,监听端口 %d...\n", PORT);while (1) { // 无限循环,处理客户端请求printf("\n🔄 等待客户端连接...\n");// 4️⃣ 接受客户端连接 (accept)client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &addr_len);if (client_fd < 0) {perror("接受客户端连接失败");continue; // 继续等待下一个客户端}printf("✅ 客户端连接成功!IP: %s, 端口: %d\n",inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));// 5️⃣ 处理客户端请求while (1) {memset(buffer, 0, BUFFER_SIZE); // 清空缓冲区bytes_read = read(client_fd, buffer, BUFFER_SIZE);if (bytes_read <= 0) {printf("❌ 客户端断开连接\n");break; // 退出该客户端处理}printf("📩 收到消息: %s\n", buffer);// 6️⃣ 发送回显消息 (echo)write(client_fd, buffer, bytes_read);}// 7️⃣ 关闭客户端连接close(client_fd);}// 8️⃣ 关闭服务器(通常不会执行到这里)close(server_fd);return 0;
}
代码运行步骤:
- 编译:(假设文件名为
tcp_server.c
)
gcc tcp_server.c -o tcp_server
- 运行服务器
./tcp_server
输出示例:
TCP 服务器已启动,监听端口 8080...
等待客户端连接...
✅ 连接测试:
方式 1:使用 telnet 连接
telnet 127.0.0.1 8080
# 输入消息后按 Enter,服务器会返回相同的消息。
方式 2:使用 nc(Netcat)测试
nc 127.0.0.1 8080
输入内容,服务器会回显,如:
Hello Server
Hello Server # 服务器返回相同内容
该代码是一个最基本的 TCP 循环服务器,适用于简单的 回显服务器 或 单客户端应用。建议进一步优化为多线程或多进程服务器以支持并发(下面会介绍):代码优化后可新增内容:
- 多线程并发处理:目前 一次只能处理一个客户端,可以使用 多线程 让服务器同时处理多个客户端。
- 日志记录:服务器可以使用
syslog()
或文件写入方式,记录 客户端连接信息。 - 超时处理:服务器可以设置
setsockopt()
来 限制客户端连接时间,防止长时间占用资源。
✅ 二、UDP 循环服务器
UDP 是 无连接的协议,服务器无需 accept()
,直接 接收客户端数据 并 回传响应。
工作流程:
- 创建套接字(
socket()
)--socket(AF_INET, SOCK_DGRAM, 0)
创建 UDP 服务器 - 绑定 IP 和端口(
bind()
)-- 监听 8080 端口 - 循环接收客户端数据(
recvfrom()
)-- 等待客户端消息 - 处理数据(
process()
) - 返回响应数据(
sendto()
)-- 把数据发回客户端 - 关闭服务器(
close()
)-- 释放资源
代码功能
- 监听指定端口(8080)
- 接收客户端消息
- 回显(Echo)消息
- 循环处理多个客户端请求
- 无需建立连接,支持并发
#include <stdio.h> // 标准输入输出
#include <stdlib.h> // exit()、malloc()等
#include <string.h> // 字符串操作
#include <unistd.h> // read(), write(), close()
#include <arpa/inet.h> // sockaddr_in, inet_addr()
#include <sys/socket.h> // 套接字 API
#include <netinet/in.h> // sockaddr_in 结构体#define PORT 8080 // 服务器监听端口
#define BUFFER_SIZE 1024 // 缓冲区大小int main() {int server_fd; // 服务器 socket 文件描述符struct sockaddr_in server_addr, client_addr; // 服务器 & 客户端地址结构socklen_t addr_len = sizeof(client_addr); // 地址结构大小char buffer[BUFFER_SIZE]; // 消息缓冲区int bytes_read;// 1️⃣ 创建 UDP 套接字 (socket)server_fd = socket(AF_INET, SOCK_DGRAM, 0);if (server_fd == -1) {perror("❌ Socket 创建失败");exit(EXIT_FAILURE);}// 2️⃣ 绑定服务器地址和端口 (bind)server_addr.sin_family = AF_INET; // IPv4server_addr.sin_addr.s_addr = INADDR_ANY; // 监听所有 IPserver_addr.sin_port = htons(PORT); // 设置端口(网络字节序)if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("❌ 绑定失败");close(server_fd);exit(EXIT_FAILURE);}printf("UDP 服务器已启动,监听端口 %d...\n", PORT);while (1) { // 无限循环,处理客户端请求memset(buffer, 0, BUFFER_SIZE); // 清空缓冲区// 3️⃣ 接收客户端消息 (recvfrom)bytes_read = recvfrom(server_fd, buffer, BUFFER_SIZE, 0,(struct sockaddr*)&client_addr, &addr_len);if (bytes_read < 0) {perror("❌ 接收数据失败");continue; // 继续等待下一个请求}printf("📩 收到来自 %s:%d 的消息: %s\n",inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer);// 4️⃣ 发送回显消息 (sendto)sendto(server_fd, buffer, bytes_read, 0,(struct sockaddr*)&client_addr, addr_len);}// 5️⃣ 关闭服务器(通常不会执行到这里)close(server_fd);return 0;
}
代码运行步骤:
- 编译:(假设文件名为
udp_server.c
)
gcc udp_server.c -o udp_server
- 运行服务器
./udp_server
输出示例:
UDP 服务器已启动,监听端口 8080...
✅ 连接测试:
方式 1:使用 nc(Netcat)
➤ 启动服务器
./udp_server
➤ 运行客户端发送消息
echo "Hello Server" | nc -u 127.0.0.1 8080
➤ 服务器输出
📩 收到来自 127.0.0.1:xxxxx 的消息: Hello Server
# (xxxxx 为随机端口)
方式 2:使用 Python UDP 客户端
➤ 运行服务器
./udp_server
➤ 运行 Python 代码
import socketclient = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ("127.0.0.1", 8080)message = "Hello from Python UDP Client"
client.sendto(message.encode(), server_address)data, _ = client.recvfrom(1024)
print("服务器回显:", data.decode())client.close()
➤ 服务器输出
收到来自 127.0.0.1:xxxxx 的消息: Hello from Python UDP Client
➤ 客户端输出
服务器回显: Hello from Python UDP Client
✅ 代码优化
- 非阻塞模式
- 使用
fcntl()
设置 非阻塞模式,防止recvfrom()
阻塞:
- 使用
#include <fcntl.h>
fcntl(server_fd, F_SETFL, O_NONBLOCK);
- 多线程处理
- 每个客户端请求可以在 新线程 中处理,防止阻塞主进程:
pthread_create(&thread_id, NULL, handle_client, (void*)&client_addr);
- 超时设置
- 通过
setsockopt()
设置 超时时间,避免客户端长期占用:
- 通过
struct timeval timeout = {5, 0}; // 5 秒超时
setsockopt(server_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
📌 2. 并发服务器模型
由于只有在当前客户的所有请求都完成后,服务器才能处理下一个客户的连接/服务请求。如果某个客户端一直占用服务器资源,那么其它的客户端都不能被处理。所以TCP服务器一般很少采用循环服务器模型。
为了弥补TCP循环服务器的缺陷,人们又设计了并发服务器的模型。
并发服务器的设计思想是服务器接受客户端的连接请求后创建子进程来为客户端服务; TCP并发服务器可以避免TCP循环服务器中客户端独占服务器的情况。为了响应客户机的请求,服务器要创建子进程来处理。如果有多个客户端的话,服务器端需要创建多个子进程。过多的子进程会影响服务器端的运行效率。
特点:
- 同时处理多个客户端,不会因为一个客户端的请求而阻塞其他客户端。
- 适用于高并发场景,如 Web 服务器、数据库服务器。
- 服务器通过 多进程、多线程或 I/O 复用 实现并发。
✅ TCP 并发服务器(多进程)
工作流程:
-
创建套接字(
socket()
) -
绑定 IP 和端口(
bind()
) -
监听连接(
listen()
) -
接受客户端连接(
accept()
) -
创建子进程(
fork()
)处理客户端请求 -
父进程继续监听新的客户端连接
-
子进程处理完请求后关闭连接
socket(...);bind(...);listen(...);while(1){accept(...);if (fork() = = 0) { {while(1) { recv(...); process(...); send(...); }close(...); exit(...); }close(...);}
完整代码:
#include <stdio.h> // 标准输入输出
#include <stdlib.h> // exit()、malloc() 等
#include <string.h> // 字符串操作
#include <unistd.h> // read(), write(), close()
#include <arpa/inet.h> // sockaddr_in, inet_addr()
#include <sys/socket.h> // 套接字 API
#include <netinet/in.h> // sockaddr_in 结构体
#include <sys/types.h> // pid_t
#include <sys/wait.h> // waitpid()
#include <signal.h> // 信号处理#define PORT 8080 // 服务器监听端口
#define BUFFER_SIZE 1024 // 缓冲区大小// 处理 SIGCHLD 信号,避免僵尸进程
void sigchld_handler(int signo) {while (waitpid(-1, NULL, WNOHANG) > 0); // 处理所有已终止的子进程
}int main() {int server_fd, client_fd; // 服务器和客户端的 socket 文件描述符struct sockaddr_in server_addr, client_addr; // 服务器 & 客户端地址结构socklen_t addr_len = sizeof(client_addr); // 地址结构大小char buffer[BUFFER_SIZE]; // 消息缓冲区int bytes_read;pid_t child_pid;// 1️⃣ 处理 SIGCHLD 以清理僵尸进程signal(SIGCHLD, sigchld_handler);// 2️⃣ 创建服务器套接字 (socket)server_fd = socket(AF_INET, SOCK_STREAM, 0);if (server_fd == -1) {perror("❌ Socket 创建失败");exit(EXIT_FAILURE);}// 3️⃣ 绑定服务器地址和端口 (bind)server_addr.sin_family = AF_INET; // IPv4server_addr.sin_addr.s_addr = INADDR_ANY; // 监听所有 IPserver_addr.sin_port = htons(PORT); // 设置端口(网络字节序)if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("❌ 绑定失败");close(server_fd);exit(EXIT_FAILURE);}// 4️⃣ 监听客户端连接 (listen)if (listen(server_fd, 5) < 0) { // 最多允许 5 个客户端排队等待perror("❌ 监听失败");close(server_fd);exit(EXIT_FAILURE);}printf("⚡ TCP 并发服务器已启动,监听端口 %d...\n", PORT);while (1) { // 无限循环,处理客户端请求printf("\n 等待客户端连接...\n");// 5️⃣ 接受客户端连接 (accept)client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &addr_len);if (client_fd < 0) {perror("❌ 接受客户端连接失败");continue; // 继续等待下一个客户端}printf("✅ 客户端连接成功!IP: %s, 端口: %d\n",inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));// 6️⃣ 创建子进程处理客户端child_pid = fork();if (child_pid == 0) { // 子进程close(server_fd); // 关闭监听 socket(子进程不需要)while (1) {memset(buffer, 0, BUFFER_SIZE); // 清空缓冲区bytes_read = read(client_fd, buffer, BUFFER_SIZE);if (bytes_read <= 0) {printf("❌ 客户端断开连接\n");break; // 退出该客户端处理}printf("📩 收到来自 %s:%d 的消息: %s\n",inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer);// 7️⃣ 发送回显消息 (echo)write(client_fd, buffer, bytes_read);}// 8️⃣ 关闭客户端连接并退出子进程close(client_fd);exit(0);}// 父进程关闭已连接的 socket(由子进程处理)close(client_fd);}// 9️⃣ 关闭服务器(通常不会执行到这里)close(server_fd);return 0;
}
代码功能:监听指定端口(8080)支持多个客户端同时连接每个客户端连接后,服务器创建子进程进行处理回显(Echo)客户端发送的消息支持 SIGCHLD 处理僵尸进程
✅ 代码运行步骤
- 编译:(假设文件名为
tcp_server_fork.c
)
gcc tcp_server_fork.c -o tcp_server_fork
- 运行服务器
./tcp_server_fork
输出示例:
TCP 并发服务器已启动,监听端口 8080...
等待客户端连接...
✅ 连接测试
方式 1:使用 telnet
连接
telnet 127.0.0.1 8080
# 输入消息后按 Enter,服务器会返回相同的消息。
方式 2:使用 nc(Netcat)
测试
nc 127.0.0.1 8080
输入内容,服务器会回显,如:
Hello Server
Hello Server # 服务器返回相同内容
详细步骤:
1. 处理 SIGCHLD -- signal(SIGCHLD, handler) -- 避免子进程变成僵尸进程
2. 创建 TCP 套接字 -- socket() -- 创建服务器 socket
3. 绑定 IP 和端口 -- bind() -- 监听 8080 端口
4. 监听连接 -- listen() -- 允许最多 5 个客户端排队
5. 等待客户端连接 -- accept() -- 接受一个客户端连接
6. 创建子进程 -- fork() -- 让子进程处理客户端请求
7. 处理客户端请求 -- read() -- 读取客户端发送的数据
8. 发送回显数据 -- write() -- 把数据发回客户端
9. 关闭连接 -- close() -- 释放资源
代码可优化部分:
多线程替代 fork()fork() 开销较大,可用 pthread(多线程) 替代,提高性能。
使用 I/O 复用select() / epoll() 可提高并发性能,避免大量进程消耗资源。
日志记录服务器可以使用 syslog() 或 文件写入 方式记录 客户端连接信息。
超时处理服务器可以设置 setsockopt() 限制客户端连接时间:
struct timeval timeout = {5, 0}; // 5 秒超时
setsockopt(client_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
备注:
fork()
创建子进程,每个客户端由单独的进程处理。- 使用
signal(SIGCHLD, handler)
处理僵尸进程。 - 处理僵尸进程的
handler()
函数:
void handler(int signo) {while (waitpid(-1, NULL, WNOHANG) > 0);
}
该代码是一个最基本的 TCP 并发服务器(多进程),适用于 中等并发负载。适合 fork()
并发模型,这里一般建议进一步优化为 epoll + 线程池高效服务器(后续会继续详细介绍)。
✅ UDP 并发服务器(多进程)
UDP 是 无连接 的协议,服务器不需要 accept()
,可以直接 接收多个客户端的数据 并 回传响应。
由于 UDP 服务器在处理某个客户端请求时可能会 阻塞,我们可以使用 多进程 方式,让每个请求都由 子进程 处理,实现并发。
完整代码
#include <stdio.h> // 标准输入输出
#include <stdlib.h> // exit()、malloc() 等
#include <string.h> // 字符串操作
#include <unistd.h> // read(), write(), close()
#include <arpa/inet.h> // sockaddr_in, inet_addr()
#include <sys/socket.h> // 套接字 API
#include <netinet/in.h> // sockaddr_in 结构体
#include <sys/types.h> // pid_t
#include <sys/wait.h> // waitpid()
#include <signal.h> // 信号处理#define PORT 8080 // 服务器监听端口
#define BUFFER_SIZE 1024 // 缓冲区大小// 处理 SIGCHLD 信号,避免僵尸进程
void sigchld_handler(int signo) {while (waitpid(-1, NULL, WNOHANG) > 0); // 清理所有僵尸进程
}int main() {int server_fd; // 服务器 socket 文件描述符struct sockaddr_in server_addr, client_addr; // 服务器 & 客户端地址结构socklen_t addr_len = sizeof(client_addr); // 地址结构大小char buffer[BUFFER_SIZE]; // 消息缓冲区int bytes_read;pid_t child_pid;// 1️⃣ 处理 SIGCHLD 以清理僵尸进程signal(SIGCHLD, sigchld_handler);// 2️⃣ 创建 UDP 套接字 (socket)server_fd = socket(AF_INET, SOCK_DGRAM, 0);if (server_fd == -1) {perror("❌ Socket 创建失败");exit(EXIT_FAILURE);}// 3️⃣ 绑定服务器地址和端口 (bind)server_addr.sin_family = AF_INET; // IPv4server_addr.sin_addr.s_addr = INADDR_ANY; // 监听所有 IPserver_addr.sin_port = htons(PORT); // 设置端口(网络字节序)if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("❌ 绑定失败");close(server_fd);exit(EXIT_FAILURE);}printf("⚡ UDP 并发服务器已启动,监听端口 %d...\n", PORT);while (1) { // 无限循环,处理客户端请求memset(buffer, 0, BUFFER_SIZE); // 清空缓冲区// 4️⃣ 接收客户端消息 (recvfrom)bytes_read = recvfrom(server_fd, buffer, BUFFER_SIZE, 0,(struct sockaddr*)&client_addr, &addr_len);if (bytes_read < 0) {perror("❌ 接收数据失败");continue; // 继续等待下一个请求}printf("📩 收到来自 %s:%d 的消息: %s\n",inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer);// 5️⃣ 创建子进程处理请求child_pid = fork();if (child_pid == 0) { // 子进程// 6️⃣ 发送回显消息 (sendto)sendto(server_fd, buffer, bytes_read, 0,(struct sockaddr*)&client_addr, addr_len);printf("🔄 处理完毕,发送回显消息: %s\n", buffer);// 7️⃣ 退出子进程exit(0);}}// 8️⃣ 关闭服务器(通常不会执行到这里)close(server_fd);return 0;
}
代码功能监听指定端口(8080)接收多个客户端的消息使用 fork() 创建子进程处理每个请求回显(Echo)客户端发送的消息支持 SIGCHLD 处理僵尸进程
✅ 代码运行步骤:
- 编译:(假设文件名为
udp_server_fork.c
)
gcc udp_server_fork.c -o udp_server_fork
- 运行服务器
./udp_server_fork
输出示例:
UDP 并发服务器已启动,监听端口 8080...
✅ 连接测试:
方式 1:使用 nc(Netcat)
➤ 启动服务器
./udp_server_fork
➤ 运行客户端发送消息
echo "Hello Server" | nc -u 127.0.0.1 8080
➤ 服务器输出
收到来自 127.0.0.1:xxxxx 的消息: Hello Server
处理完毕,发送回显消息: Hello Server
# (xxxxx 为随机端口)
方式 2:使用 Python UDP 客户端
➤ 运行服务器
./udp_server_fork
➤ 运行 Python 代码
import socketclient = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ("127.0.0.1", 8080)message = "Hello from Python UDP Client"
client.sendto(message.encode(), server_address)data, _ = client.recvfrom(1024)
print("服务器回显:", data.decode())client.close()
➤ 服务器输出
收到来自 127.0.0.1:xxxxx 的消息: Hello from Python UDP Client
处理完毕,发送回显消息: Hello from Python UDP Client
➤ 客户端输出
服务器回显: Hello from Python UDP Client
详细步骤:1. 处理 SIGCHLD -- signal(SIGCHLD, handler) -- 避免子进程变成僵尸进程2. 创建 UDP 套接字 -- socket() -- 创建服务器 socket3. 绑定 IP 和端口 -- bind() -- 监听 8080 端口4. 接收数据 -- recvfrom() -- 等待客户端消息5. 创建子进程 -- fork() -- 让子进程处理客户端请求6. 发送回显数据 -- sendto() -- 把数据发回客户端7. 退出子进程 -- exit(0) -- 释放资源,防止占用内存
服务器模型对比
模型 | 适用协议 | 特点 | 优缺点 |
---|---|---|---|
循环服务器 | TCP / UDP | 单线程处理客户端 | 简单但不支持并发 |
多进程并发服务器 | TCP / UDP | fork() 创建子进程 | 稳定,但进程开销大 |
多线程并发服务器 | TCP | pthread 处理多个客户端 | 资源消耗较低,但线程管理复杂 |
I/O 复用服务器(select / epoll )(重点:后面详细开一篇单独详细解析) | TCP / UDP | 监听多个客户端 | 适合高并发,但实现复杂 |
服务器优化
- 使用 I/O 复用(select() / epoll())
- 适用于 高并发 场景,如 Web 服务器。
select()
适用于 小规模并发,而epoll()
适用于 大规模并发。
- 使用线程池
- 线程池可以 复用线程,减少
fork()
/pthread_create()
的开销。 - 适用于 中等并发 场景,如 聊天室、数据库服务器。
- 线程池可以 复用线程,减少
- 使用异步 I/O(
aio_*()
)- 适用于 超高并发 场景,如 消息队列、异步 API 服务器。
- 依赖 操作系统支持(如
Linux libaio
)。
循环服务器 适用于 低并发,但性能有限。多进程 / 多线程服务器 适用于 中等并发,但资源开销较大。I/O 复用(epoll)或异步 I/O 适用于高并发服务器,如 Nginx、Redis。如果要开发高性能服务器,推荐使用 epoll + 线程池。
由于篇幅有限,多线程实现并发服务器、I/O 复用(epoll)或异步 I/O 、epoll + 线程池在后续的文章中会依次介绍!
以上。仅供学习与分享交流,请勿用于商业用途!转载需提前说明。
我是一个十分热爱技术的程序员,希望这篇文章能够对您有帮助,也希望认识更多热爱程序开发的小伙伴。
感谢!