高并发模型是服务器处理大量客户端连接的核心架构。Linux下主要有以下几种经典模型:
每个新连接fork一个子进程处理,父进程继续监听。
#include <unistd.h>
pid_t fork(void);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/wait.h>
void handle_client(int client_fd) {
char buf[1024];
ssize_t n;
while ((n = recv(client_fd, buf, sizeof(buf), 0)) > 0) {
send(client_fd, buf, n, 0);
}
close(client_fd);
exit(0);
}
int main() {
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(8080),
.sin_addr.s_addr = INADDR_ANY
};
bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
listen(server_fd, 128);
signal(SIGCHLD, SIG_IGN); // 自动回收子进程
while (1) {
int client_fd = accept(server_fd, NULL, NULL);
if (fork() == 0) {
close(server_fd);
handle_client(client_fd);
}
close(client_fd);
}
return 0;
}
编译命令:
gcc -o fork_server fork_server.c
./fork_server
每个连接创建一个新线程处理,共享进程地址空间。
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void*), void *arg);
void pthread_exit(void *retval);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
void* handle_client(void* arg) {
int client_fd = *(int*)arg;
free(arg);
char buf[1024];
ssize_t n;
while ((n = recv(client_fd, buf, sizeof(buf), 0)) > 0) {
send(client_fd, buf, n, 0);
}
close(client_fd);
return NULL;
}
int main() {
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(8080),
.sin_addr.s_addr = INADDR_ANY
};
bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
listen(server_fd, 128);
while (1) {
int client_fd = accept(server_fd, NULL, NULL);
int *fd = malloc(sizeof(int));
*fd = client_fd;
pthread_t tid;
pthread_create(&tid, NULL, handle_client, fd);
pthread_detach(tid);
}
return 0;
}
编译命令:
gcc -o thread_server thread_server.c -lpthread
./thread_server
预创建固定数量线程,任务队列分发连接。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define THREAD_POOL_SIZE 4
#define TASK_QUEUE_SIZE 128
typedef struct {
int client_fd;
} task_t;
typedef struct {
task_t queue[TASK_QUEUE_SIZE];
int front, rear, count;
pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_t threads[THREAD_POOL_SIZE];
} thread_pool_t;
void* worker(void* arg) {
thread_pool_t *pool = (thread_pool_t*)arg;
while (1) {
pthread_mutex_lock(&pool->mutex);
while (pool->count == 0) {
pthread_cond_wait(&pool->cond, &pool->mutex);
}
task_t task = pool->queue[pool->front];
pool->front = (pool->front + 1) % TASK_QUEUE_SIZE;
pool->count--;
pthread_mutex_unlock(&pool->mutex);
char buf[1024];
ssize_t n;
while ((n = recv(task.client_fd, buf, sizeof(buf), 0)) > 0) {
send(task.client_fd, buf, n, 0);
}
close(task.client_fd);
}
return NULL;
}
void pool_init(thread_pool_t *pool) {
pool->front = pool->rear = pool->count = 0;
pthread_mutex_init(&pool->mutex, NULL);
pthread_cond_init(&pool->cond, NULL);
for (int i = 0; i < THREAD_POOL_SIZE; i++) {
pthread_create(&pool->threads[i], NULL, worker, pool);
}
}
void pool_add_task(thread_pool_t *pool, int client_fd) {
pthread_mutex_lock(&pool->mutex);
pool->queue[pool->rear].client_fd = client_fd;
pool->rear = (pool->rear + 1) % TASK_QUEUE_SIZE;
pool->count++;
pthread_cond_signal(&pool->cond);
pthread_mutex_unlock(&pool->mutex);
}
int main() {
thread_pool_t pool;
pool_init(&pool);
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(8080),
.sin_addr.s_addr = INADDR_ANY
};
bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
listen(server_fd, 128);
while (1) {
int client_fd = accept(server_fd, NULL, NULL);
pool_add_task(&pool, client_fd);
}
return 0;
}
编译命令:
gcc -o thread_pool_server thread_pool_server.c -lpthread
./thread_pool_server
epoll监听所有fd,事件触发后分发给工作线程池处理。
#include <sys/epoll.h>
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#define MAX_EVENTS 128
#define THREAD_POOL_SIZE 4
typedef struct {
int client_fd;
} task_t;
typedef struct {
task_t queue[128];
int front, rear, count;
pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_t threads[THREAD_POOL_SIZE];
} thread_pool_t;
void* worker(void* arg) {
thread_pool_t *pool = (thread_pool_t*)arg;
while (1) {
pthread_mutex_lock(&pool->mutex);
while (pool->count == 0) {
pthread_cond_wait(&pool->cond, &pool->mutex);
}
task_t task = pool->queue[pool->front];
pool->front = (pool->front + 1) % 128;
pool->count--;
pthread_mutex_unlock(&pool->mutex);
char buf[1024];
ssize_t n;
while ((n = recv(task.client_fd, buf, sizeof(buf), 0)) > 0) {
send(task.client_fd, buf, n, 0);
}
close(task.client_fd);
}
return NULL;
}
void pool_init(thread_pool_t *pool) {
pool->front = pool->rear = pool->count = 0;
pthread_mutex_init(&pool->mutex, NULL);
pthread_cond_init(&pool->cond, NULL);
for (int i = 0; i < THREAD_POOL_SIZE; i++) {
pthread_create(&pool->threads[i], NULL, worker, pool);
}
}
void pool_add_task(thread_pool_t *pool, int client_fd) {
pthread_mutex_lock(&pool->mutex);
pool->queue[pool->rear].client_fd = client_fd;
pool->rear = (pool->rear + 1) % 128;
pool->count++;
pthread_cond_signal(&pool->cond);
pthread_mutex_unlock(&pool->mutex);
}
int main() {
thread_pool_t pool;
pool_init(&pool);
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(8080),
.sin_addr.s_addr = INADDR_ANY
};
bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
listen(server_fd, 128);
int epfd = epoll_create1(0);
struct epoll_event ev = {
.events = EPOLLIN,
.data.fd = server_fd
};
epoll_ctl(epfd, EPOLL_CTL_ADD, server_fd, &ev);
struct epoll_event events[MAX_EVENTS];
while (1) {
int nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
for (int i = 0; i < nfds; i++) {
if (events[i].data.fd == server_fd) {
int client_fd = accept(server_fd, NULL, NULL);
ev.events = EPOLLIN;
ev.data.fd = client_fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, client_fd, &ev);
} else {
epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
pool_add_task(&pool, events[i].data.fd);
}
}
}
return 0;
}
编译命令:
gcc -o epoll_thread_server epoll_thread_server.c -lpthread
./epoll_thread_server
| 模型 | 资源占用 | 并发数 | 实现复杂度 | 适用场景 |
|---|---|---|---|---|
| fork多进程 | 高(独立地址空间) | 低(进程数限制) | 低 | 小型服务、连接数少 |
| 多线程 | 中(共享地址空间) | 中(线程数限制) | 中 | 中等并发、CPU密集 |
| 线程池 | 中(复用线程) | 中高 | 中 | 连接数多但处理快 |
| IO多路复用+多线程 | 低(事件驱动) | 高(万级连接) | 高 | 高并发、IO密集 |