朋友问我:你现在年薪百万吗?我说:我没有,倒是并发量超百万的服务器可以有(坏笑)。
目标
实现一个并发量超一百万的TCP服务器
基本设计思路
使用epoll获取请求+线程池处理请求
环境介绍
四台虚拟机(一个服务端以及三个服务端)
服务端硬件配置要求:双核处理器,4G运行内存
客服端硬件配置要求:单核处理器,2G运行内存
虚拟机运行操作系统:ubuntu server 64位
虚拟机软件:VMware Fusion
操作系统:macOS
代码实现
服务器端
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <stdbool.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/epoll.h>
#define COUNT_PORT 100
#define EPOLL_SIZE 2048
//任务队列中的任务数目
// #define COUNT_TASK 1024
//线程池中线程数量
#define COUNT_WORK 4
//缓存长度
#define BUFFER_LENGTH 1024
//双向链表的插入
#define LIST_INSERT(item,list) do \
{
\
item->next = list->next; \
if(list->next != NULL) \
list->next->pre = item; \
list->next = item; \
item->pre = list; \
} while (0);
//双向链表 删除节点
#define LIST_REMOVE(item,list) do \
{
\
if(item != NULL){
\
item->pre->next = item->next; \
if(item->next != NULL) \
item->next->pre = item->pre;\
} \
} while (0);
//任务队列
struct Task
{
//socket_fd
int socket_fd;
//epoll_fd
int epoll_fd;
//监听套接字数组
int *listen_socket;
//前驱节点
struct Task *pre;
//后继节点
struct Task *next;
//任务函数
void (*function_task)(int socket_fd, int epoll_fd, int *listen_socket);
};
//工作队列
struct Work
{
//进程ID
pthread_t thread_id;
//前驱节点
struct Work *pre;
//后继
struct Work *next;
};
//线程池
struct ThreadPool
{
//工作队列
struct Work *works;
//任务队列
struct Task *tasks;
//互斥锁
pthread_mutex_t mutex;
//条件变量
pthread_cond_t cond;
};
//推送任务
int task_push(struct Task *task,struct ThreadPool *thread_pool){
//上锁
int res = pthread_mutex_lock(&thread_pool->mutex);
if (res)
{
perror("pthread_mutex_lock\n");
return -1;
}
LIST_INSERT(task,thread_pool->tasks);
pthread_cond_signal(&thread_pool->cond);
//解锁
res =</