当前位置:   article > 正文

c/c++ webserver项目(linux 高性能服务器编程,游双)

游双

项目介绍:最近在阅读游双的《linux高性能服务器编程》,看到后面跟着里面的代码敲了一个webserver。该项目采用同步模拟的proactor框架,采用半同步半异步的并法模式,用epoll实现io多路复用。

(1)locker.h文件是一个线程同步机制包装类,封装了sem_tpthread_mutex_tpthread_cond_t 三个用于线程同步的机制。

(2)threadpool.h 为线程池类,成员变量主要有任务队列m_workqueue 和线程数组 m_threads。各个线程通过竞争sem_t 信号量来从 任务队列获得任务,执行任务对象的process()函数来处理http请求与写http响应。

(3)http_conn.h 为任务类,主要封装了如何处理http请求 与 如何写http响应,主要流程为将读入的http请求写入缓存区m_read_buf,通过对m_read_buf 的操作来获得请求的信息。在对请求的信息判断正确后,将http响应报文写入 m_write_buf ,然后发送该响应报文来完成与浏览器的交互。 

http_conn.cpp文件中的doc_root为网站根目录,将文件放入该根目录中即可被访问。

编译:先在终端输入如下指令生成 server 可执行文件

g++ -o server main.cpp http_conn.cpp -lpthread -g

 运行

./server ip地址 端口号

Locker.h 

  1. /线程同步机制包装类
  2. #ifndef LOCKER_H
  3. #define LOCKER_H
  4. #include <exception>
  5. #include <pthread.h>
  6. #include <semaphore.h>
  7. //封装信号量的类
  8. class sem
  9. {
  10. public:
  11. sem()
  12. {
  13. if(sem_init(&m_sem, 0, 0) != 0)
  14. {
  15. throw std::exception();
  16. }
  17. }
  18. //销毁信号量
  19. ~sem()
  20. {
  21. sem_destroy(&m_sem);
  22. }
  23. //等待信号量
  24. bool wait()
  25. {
  26. return sem_wait(&m_sem) == 0;
  27. }
  28. bool post()
  29. {
  30. return sem_post(&m_sem) == 0;
  31. }
  32. private:
  33. sem_t m_sem;
  34. };
  35. class locker
  36. {
  37. public:
  38. locker()
  39. {
  40. if(pthread_mutex_init(&m_mutex, NULL) != 0)
  41. {
  42. throw std::exception();
  43. }
  44. }
  45. ~locker()
  46. {
  47. pthread_mutex_destroy(&m_mutex);
  48. }
  49. bool lock()
  50. {
  51. return pthread_mutex_lock(&m_mutex) == 0;
  52. }
  53. bool unlock()
  54. {
  55. return pthread_mutex_unlock(&m_mutex) == 0;
  56. }
  57. private:
  58. pthread_mutex_t m_mutex;
  59. };
  60. //phtread
  61. class cond
  62. {
  63. public:
  64. cond()
  65. {
  66. if(pthread_mutex_init(&m_mutex, NULL) != 0)
  67. {
  68. throw std::exception();
  69. }
  70. if(pthread_cond_init(&m_cond, NULL) != 0)
  71. {
  72. //出现问题得释放已经分配的资源
  73. pthread_mutex_destroy(&m_mutex);
  74. throw std::exception();
  75. }
  76. }
  77. ~cond()
  78. {
  79. pthread_mutex_destroy(&m_mutex);
  80. pthread_cond_destroy(&m_cond);
  81. }
  82. bool wait()
  83. {
  84. int ret = 0;
  85. pthread_mutex_lock(&m_mutex);
  86. ret = pthread_cond_wait(&m_cond, &m_mutex);
  87. pthread_mutex_unlock(&m_mutex);
  88. return ret == 0;
  89. }
  90. bool signal()
  91. {
  92. return pthread_cond_signal(&m_cond) == 0;
  93. }
  94. private:
  95. pthread_mutex_t m_mutex;
  96. pthread_cond_t m_cond;
  97. };
  98. #endif

threadpool.h

  1. #ifndef THREADPOOL_H
  2. #define THREADPOOL_H
  3. #include<list>
  4. #include<cstdio>
  5. #include<exception>
  6. #include<pthread.h>
  7. #include"locker.h"
  8. template<typename T>
  9. class threadpool
  10. {
  11. private:
  12. std::list<T*> m_workequeue;
  13. pthread_t* m_threads;
  14. int m_thread_number;
  15. int m_max_requests;
  16. locker m_queuelocker;
  17. sem m_queuestat;
  18. bool m_stop;
  19. private:
  20. static void* worker(void* arg);
  21. void run();
  22. public:
  23. threadpool(int thread_number = 8 , int max_requests = 10000);
  24. ~threadpool();
  25. bool append(T* request);
  26. };
  27. template<typename T>
  28. threadpool<T>::threadpool(int thread_number,int max_requests):m_thread_number(thread_number),m_max_requests(max_requests),m_threads(NULL),m_stop(false)
  29. {
  30. if((thread_number<=0) || (max_requests<=0)){
  31. throw std::exception();
  32. }
  33. m_threads = new pthread_t[m_thread_number];
  34. if(!m_threads){
  35. throw std::exception();
  36. }
  37. for(int i=0;i<thread_number;++i){
  38. printf("create the %dth thread\n",i+1);
  39. pthread_create(m_threads+i,NULL,worker,this);
  40. pthread_detach(m_threads[i]);
  41. }
  42. }
  43. template<typename T>
  44. threadpool<T>::~threadpool()
  45. {
  46. delete[] m_threads;
  47. m_stop = true;
  48. }
  49. template<typename T>
  50. bool threadpool<T>::append(T* request){
  51. m_queuelocker.lock();
  52. if(m_workequeue.size()>=m_max_requests){
  53. m_queuelocker.unlock();
  54. return false;
  55. }
  56. m_workequeue.push_back(request);
  57. m_queuelocker.unlock();
  58. m_queuestat.post();
  59. return true;
  60. }
  61. template<typename T>
  62. void* threadpool<T>::worker(void* arg){
  63. threadpool* pool = (threadpool*)arg;
  64. pool->run();
  65. return pool;
  66. }
  67. template<typename T>
  68. void threadpool<T>::run(){
  69. while(!m_stop){
  70. m_queuestat.wait();
  71. m_queuelocker.lock();
  72. if(m_workequeue.empty()){
  73. m_queuelocker.unlock();
  74. continue;
  75. }
  76. T* request = m_workequeue.front();
  77. m_workequeue.pop_front();
  78. m_queuelocker.unlock();
  79. if(!request){
  80. continue;
  81. }
  82. request->process();
  83. }
  84. }
  85. #endif

http_conn.h

  1. #ifndef HTTP_CONN_h
  2. #define HTTP_CONN_h
  3. #include <unistd.h>
  4. #include <signal.h>
  5. #include <sys/types.h>
  6. #include <sys/epoll.h>
  7. #include <fcntl.h>
  8. #include <sys/socket.h>
  9. #include <netinet/in.h>
  10. #include <arpa/inet.h>
  11. #include <assert.h>
  12. #include <sys/stat.h>
  13. #include <string.h>
  14. #include <pthread.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <sys/mman.h>
  18. #include <stdarg.h>
  19. #include <errno.h>
  20. #include <sys/uio.h>
  21. #include "locker.h"
  22. class http_conn
  23. {
  24. public:
  25. static const int FILENAME_LEN = 200;//文件名的最大长度
  26. static const int READ_BUFFER_SIZE = 2048;//缓冲区的大小
  27. static const int WRITE_BUFFER_SIZE = 1024;//写缓冲区的大小
  28. //HTTP请求方法
  29. //HTTP请求方法,但本代码中仅仅支持GET
  30. enum METHOD{
  31. GET = 0,
  32. POST,
  33. HEAD,
  34. PUT,
  35. DELETE,
  36. TRACE,
  37. OPTIONS,
  38. CONNECT,
  39. PATCH
  40. };
  41. //主状态机可能的状态
  42. enum CHECK_STATE
  43. {
  44. CHECK_STATE_REQUESTION = 0,//正在分析当前请求行
  45. CHECK_STATE_HEADER,//正在分析头部字段
  46. CHECK_STATE_CONTENT
  47. };
  48. //从状态机可能的状态
  49. enum LINE_STATUS
  50. {
  51. LINE_OK = 0,//读取到一个完整的行
  52. LINE_BAD,//行出错
  53. LINE_OPEN//行数据尚且不完整
  54. };
  55. //服务器处理http请求的结果
  56. enum HTTP_CODE
  57. {
  58. NO_REQUEST,//请求不完整需要继续读取
  59. GET_REQUEST,//得到了一个完整的请求
  60. BAD_REQUEST,//请求有语法错误
  61. NO_RESOURCE,//没有资源
  62. FORBIDDEN_REQUEST,//没有足够的权限
  63. FILE_REQUEST,//文件已被请求
  64. INTERNAL_ERROR,//服务器内部错误
  65. CLOSED_CONNECTION//客户端连接已关闭
  66. };
  67. public:
  68. http_conn(){}
  69. ~http_conn(){}
  70. public:
  71. void init(int sockfd,const sockaddr_in& addr);
  72. void close_conn(bool real_close = true);
  73. bool read();
  74. bool write();
  75. void process();
  76. private:
  77. void init();
  78. HTTP_CODE process_read();
  79. bool process_write(HTTP_CODE ret);
  80. //下面一组函数被process_read调用以分析HTTP请求
  81. HTTP_CODE parse_request_line(char* text);
  82. HTTP_CODE parse_header(char* text);
  83. HTTP_CODE parse_content(char* text);
  84. HTTP_CODE do_request();
  85. char* get_line(){ return m_read_buf + m_start_line; }
  86. LINE_STATUS parse_line();
  87. //下面一组函数被process_write调用以填充HTTP应答
  88. void unmap();
  89. bool add_response(const char* format, ...);
  90. bool add_content(const char* content);
  91. bool add_status_line(int status, const char* title);
  92. bool add_headers(int content_length);
  93. bool add_content_length(int content_length);
  94. bool add_linger();
  95. bool add_blank_line();
  96. public:
  97. static int m_epollfd;
  98. static int m_user_count;
  99. private:
  100. int m_sockfd;
  101. sockaddr_in m_address;
  102. char m_read_buf[READ_BUFFER_SIZE];
  103. int m_read_idx;
  104. int m_check_idx;
  105. int m_start_line;
  106. char m_write_buf[WRITE_BUFFER_SIZE];
  107. int m_write_idx;
  108. CHECK_STATE m_check_state;
  109. METHOD m_method;
  110. char m_real_file[FILENAME_LEN];
  111. char* m_url;
  112. char* m_version;
  113. char* m_host;
  114. int m_content_length;
  115. bool m_linger;
  116. char* m_file_address;
  117. struct stat m_file_stat;
  118. struct iovec m_iv[2];
  119. int m_iv_count;
  120. };
  121. #endif

http_conn.cpp

  1. #include"http_conn.h"
  2. //定义一些HTTP响应的状态信息
  3. const char* ok_200_title = "OK";
  4. const char* error_400_title = "Bad Request";
  5. const char* error_400_form = "Your request has bad syntax or is inherently impossible to satisfy.\n";
  6. const char* error_403_title = "Forbidden";
  7. const char* error_403_form = "you do not have permisson to get file from this server.\n";
  8. const char* error_404_title = "Not Found";
  9. const char* error_404_form = "The requested file was not found on this server.\n";
  10. const char* error_500_title = "Internal Error";
  11. const char* error_500_form = "There was an unusual problem serving the requested file.\n";
  12. //网站的根目录
  13. const char* doc_root = "/home/ross/Documents";
  14. int setnonblocking(int fd){
  15. int old_option = fcntl(fd,F_GETFL);
  16. int new_option = old_option | O_NONBLOCK;
  17. fcntl(fd,F_SETFL,new_option);
  18. return old_option;
  19. }
  20. void addfd(int epollfd,int fd,bool one_shot){
  21. epoll_event event;
  22. event.data.fd = fd;
  23. event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
  24. if(one_shot){
  25. event.events |= EPOLLONESHOT;
  26. }
  27. epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&event);
  28. setnonblocking(fd);
  29. }
  30. void removefd(int epollfd,int fd){
  31. epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,0);
  32. close(fd);
  33. }
  34. void modfd(int epollfd,int fd,int ev){
  35. epoll_event event;
  36. event.data.fd = fd;
  37. event.events = ev | EPOLLET | EPOLLONESHOT | EPOLLRDHUP;
  38. epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&event);
  39. }
  40. int http_conn::m_user_count = 0;
  41. int http_conn::m_epollfd = -1;
  42. void http_conn::close_conn(bool real_close){
  43. if(real_close && (m_sockfd != -1)){
  44. removefd(m_epollfd,m_sockfd);
  45. m_sockfd = -1;
  46. m_user_count --;
  47. }
  48. }
  49. void http_conn::init(int sockfd,const sockaddr_in& addr){
  50. m_sockfd = sockfd;
  51. m_address = addr;
  52. addfd(m_epollfd,sockfd,true);
  53. m_user_count ++;
  54. init();
  55. }
  56. void http_conn::init(){
  57. m_check_state = CHECK_STATE_REQUESTION;
  58. m_linger = false;
  59. m_method = GET;
  60. m_url = 0;
  61. m_version = 0;
  62. m_content_length = 0;
  63. m_host = 0;
  64. m_start_line = 0;
  65. m_check_idx = 0;
  66. m_read_idx = 0;
  67. m_write_idx = 0;
  68. memset(m_read_buf,'\0',READ_BUFFER_SIZE);
  69. memset(m_write_buf,'\0',WRITE_BUFFER_SIZE);
  70. memset(m_real_file,'\0',FILENAME_LEN);
  71. }
  72. http_conn::LINE_STATUS http_conn::parse_line(){
  73. char temp;
  74. for(;m_check_idx<m_read_idx;++m_check_idx){
  75. temp = m_read_buf[m_check_idx];
  76. if(temp == '\r'){
  77. if(m_read_buf[m_check_idx+1] == '\n'){
  78. m_read_buf[m_check_idx++] = '\0';
  79. m_read_buf[m_check_idx++] = '\0';
  80. return LINE_OK;
  81. }
  82. else if( (m_check_idx+1) == m_read_idx){
  83. return LINE_OPEN;
  84. }
  85. else
  86. return LINE_BAD;
  87. }
  88. else if(temp == '\n'){
  89. if((m_check_idx>1) && (m_read_buf[m_check_idx-1] == '\r'))
  90. {
  91. m_read_buf[m_check_idx-1] = '\0';
  92. m_read_buf[m_check_idx++] = '\0';
  93. return LINE_OK;
  94. }
  95. else{
  96. return LINE_BAD;
  97. }
  98. }
  99. }
  100. return LINE_OPEN;
  101. }
  102. bool http_conn::read(){
  103. if(m_read_idx >= READ_BUFFER_SIZE){
  104. return false;
  105. }
  106. int bytes_read = 0;
  107. while(true){
  108. bytes_read = recv(m_sockfd,m_read_buf,READ_BUFFER_SIZE-m_read_idx,0);
  109. if(bytes_read == -1){
  110. if( errno == EAGAIN || errno == EWOULDBLOCK){
  111. break;
  112. }
  113. return false;
  114. }
  115. else if(bytes_read == 0){
  116. return false;
  117. }
  118. m_read_idx += bytes_read;
  119. }
  120. return true;
  121. }
  122. http_conn::HTTP_CODE http_conn::parse_request_line(char* text){
  123. m_url = strpbrk(text," \t");
  124. if(!m_url){
  125. return BAD_REQUEST;
  126. }
  127. *m_url++ = '\0';
  128. m_url += strspn(m_url," \t");
  129. char* method = text;
  130. if(strcasecmp(method,"GET") == 0){
  131. m_method = GET;
  132. }
  133. else{
  134. return BAD_REQUEST;
  135. }
  136. m_version = strpbrk(m_url," \t");
  137. if(!m_version){
  138. return BAD_REQUEST;
  139. }
  140. *m_version++ = '\0';
  141. m_version+=strspn(m_version," \t");
  142. if(strcasecmp(m_version,"HTTP/1.1") != 0){
  143. return BAD_REQUEST;
  144. }
  145. if(strncasecmp(m_url,"http://",7)==0){
  146. m_url+=7;
  147. m_url = strchr(m_url,'/');
  148. }
  149. if(!m_url || m_url[0]!= '/'){
  150. return BAD_REQUEST;
  151. }
  152. m_check_state = CHECK_STATE_HEADER;
  153. return NO_REQUEST;
  154. }
  155. http_conn::HTTP_CODE http_conn::parse_header(char* text){
  156. if(text[0] == '\0'){
  157. if(m_content_length != 0){
  158. m_check_state = CHECK_STATE_CONTENT;
  159. return NO_REQUEST;
  160. }
  161. printf("parse_header OK\n");
  162. return GET_REQUEST;
  163. }
  164. else if(strncasecmp(text,"Connection:",11) == 0){
  165. text+=11;
  166. text += strspn(text," \t");
  167. if(strcasecmp(text,"keep-alive") == 0){
  168. m_linger = true;
  169. }
  170. }
  171. else if(strncasecmp(text,"Content-Length",15)==0){
  172. text += 15;
  173. text += strspn(text," \t");
  174. m_content_length += atol(text);
  175. }
  176. else if(strncasecmp(text,"Host:",5) == 0){
  177. text+=5;
  178. text+=strspn(text," \t");
  179. m_host = text;
  180. }
  181. else{
  182. printf("oh no! I can't handle this header %s\n",text);
  183. }
  184. return NO_REQUEST;
  185. }
  186. http_conn::HTTP_CODE http_conn::parse_content(char* text){
  187. if(m_read_idx >= m_content_length+m_check_idx){
  188. text[m_content_length] = '\0';
  189. return GET_REQUEST;
  190. }
  191. return NO_REQUEST;
  192. }
  193. http_conn::HTTP_CODE http_conn::process_read(){
  194. LINE_STATUS line_status = LINE_OK;
  195. HTTP_CODE ret = NO_REQUEST;
  196. char* text = 0;
  197. while(((m_check_state == CHECK_STATE_CONTENT) && (line_status == LINE_OK)) || ((line_status=parse_line()) ==LINE_OK) ){
  198. text = get_line();
  199. m_start_line = m_check_idx;
  200. printf("I got 1 line %s\n",text);
  201. switch(m_check_state)
  202. {
  203. case CHECK_STATE_REQUESTION:{
  204. ret = parse_request_line(text);
  205. if(ret == BAD_REQUEST){
  206. return BAD_REQUEST;
  207. }
  208. break;
  209. }
  210. case CHECK_STATE_HEADER:{
  211. ret = parse_header(text);
  212. if(ret == BAD_REQUEST){
  213. return BAD_REQUEST;
  214. }
  215. else if(ret == GET_REQUEST){
  216. return do_request();
  217. }
  218. break;
  219. }
  220. case CHECK_STATE_CONTENT:{
  221. ret = parse_content(text);
  222. if(ret == GET_REQUEST){
  223. return do_request();
  224. }
  225. line_status = LINE_OPEN;
  226. break;
  227. }
  228. default:
  229. return INTERNAL_ERROR;
  230. }
  231. }
  232. return NO_REQUEST;
  233. }
  234. http_conn::HTTP_CODE http_conn::do_request(){
  235. strcpy(m_real_file,doc_root);
  236. int len = strlen(doc_root);
  237. strncpy(m_real_file+len,m_url,FILENAME_LEN-len-1);
  238. if(stat(m_real_file,&m_file_stat) < 0){
  239. return NO_RESOURCE;
  240. }
  241. if(!(m_file_stat.st_mode & S_IROTH)){
  242. return FORBIDDEN_REQUEST;
  243. }
  244. if(S_ISDIR(m_file_stat.st_mode)){
  245. return BAD_REQUEST;
  246. }
  247. int fd = open(m_real_file,O_RDONLY);
  248. m_file_address = (char*)mmap(0,m_file_stat.st_size,PROT_READ,MAP_PRIVATE,fd,0);
  249. close(fd);
  250. return FILE_REQUEST;
  251. }
  252. void http_conn::unmap(){
  253. if(m_file_address){
  254. munmap(m_file_address,m_file_stat.st_size);
  255. m_file_address = 0;
  256. }
  257. }
  258. bool http_conn::add_response(const char* format, ...){
  259. if(m_write_idx>WRITE_BUFFER_SIZE){
  260. return false;
  261. }
  262. va_list arg_list;
  263. va_start(arg_list,format);
  264. int len = vsnprintf(m_write_buf+m_write_idx,WRITE_BUFFER_SIZE-1-m_write_idx,format,arg_list);
  265. if(len >= (WRITE_BUFFER_SIZE-1-m_write_idx)){
  266. return false;
  267. }
  268. m_write_idx+=len;
  269. va_end(arg_list);
  270. return true;
  271. }
  272. bool http_conn::add_status_line(int status,const char* title){
  273. return add_response("%s %d %s\r\n","HTTP/1.1",status,title);
  274. }
  275. bool http_conn::add_headers(int content_len){
  276. add_content_length(content_len);
  277. add_linger();
  278. add_blank_line();
  279. return true;
  280. }
  281. bool http_conn::add_content_length(int content_len){
  282. return add_response("Content-Length: %d\r\n",content_len);
  283. }
  284. bool http_conn::add_linger(){
  285. return add_response("Connection: %s\r\n",(m_linger == true)?"keep-alive":"close");
  286. }
  287. bool http_conn::add_blank_line(){
  288. return add_response("%s","\r\n");
  289. }
  290. bool http_conn::add_content(const char* content){
  291. return add_response("%s",content);
  292. }
  293. bool http_conn::process_write(HTTP_CODE ret){
  294. switch ((ret))
  295. {
  296. case INTERNAL_ERROR:
  297. {
  298. add_status_line(500,error_500_title);
  299. add_headers(strlen(error_500_form));
  300. if(!add_content(error_500_form)){
  301. return false;
  302. }
  303. break;
  304. }
  305. case BAD_REQUEST:
  306. {
  307. add_status_line(400,error_400_title);
  308. add_headers(strlen(error_400_form));
  309. if(! add_content(error_500_form)){
  310. return false;
  311. }
  312. break;
  313. }
  314. case NO_RESOURCE:
  315. {
  316. add_status_line(404,error_404_title);
  317. add_headers(strlen(error_404_form));
  318. if(! add_content(error_404_form)){
  319. return false;
  320. }
  321. break;
  322. }
  323. case FORBIDDEN_REQUEST:
  324. {
  325. add_status_line(403,error_403_title);
  326. add_headers(strlen(error_403_form));
  327. if(! add_content(error_403_form)){
  328. return false;
  329. }
  330. break;
  331. }
  332. case FILE_REQUEST:
  333. {
  334. add_status_line(200,ok_200_title);
  335. if(m_file_stat.st_size !=0){
  336. add_headers(m_file_stat.st_size);
  337. m_iv[0].iov_base = m_write_buf;
  338. m_iv[0].iov_len = m_write_idx;
  339. m_iv[1].iov_base = m_file_address;
  340. m_iv[1].iov_len = m_file_stat.st_size;
  341. m_iv_count = 2;
  342. printf("process_write ok\n");
  343. return true;
  344. }
  345. else{
  346. const char* ok_string = "<html><body></body></html>";
  347. add_headers(strlen(ok_string));
  348. if(! add_content(ok_string)){
  349. return false;
  350. }
  351. break;
  352. }
  353. }
  354. default:
  355. {
  356. return false;
  357. }
  358. }
  359. m_iv[0].iov_base = m_write_buf;
  360. m_iv[0].iov_len = m_write_idx;
  361. m_iv_count = 1;
  362. return true;
  363. }
  364. bool http_conn::write(){
  365. int temp = 0;
  366. int bytes_have_send = 0;
  367. int bytes_to_send = m_write_idx;
  368. if(bytes_to_send == 0){
  369. modfd(m_epollfd,m_sockfd,EPOLLOUT);
  370. init();
  371. return true;
  372. }
  373. while(1)
  374. {
  375. temp = writev(m_sockfd,m_iv,m_iv_count);
  376. if(temp < 0){
  377. if(errno == EAGAIN){
  378. modfd(m_epollfd,m_sockfd,EPOLLOUT);
  379. return true;
  380. }
  381. unmap();
  382. return false;
  383. }
  384. bytes_have_send+=temp;
  385. bytes_to_send-= temp;
  386. if(bytes_to_send<=bytes_have_send){
  387. unmap();
  388. if(m_linger){
  389. init();
  390. modfd(m_epollfd,m_sockfd,EPOLLIN);
  391. return true;
  392. }
  393. else{
  394. modfd(m_epollfd,m_sockfd,EPOLLIN);
  395. return false;
  396. }
  397. }
  398. }
  399. }
  400. void http_conn::process()
  401. {
  402. HTTP_CODE read_ret = process_read();
  403. if(read_ret == NO_REQUEST){
  404. modfd(m_epollfd,m_sockfd,EPOLLIN);
  405. return;
  406. }
  407. bool write_ret = process_write(read_ret);
  408. if(!write_ret){
  409. close_conn();
  410. }
  411. modfd(m_epollfd,m_sockfd,EPOLLOUT);
  412. }

main.cpp

  1. #include <unistd.h>
  2. #include <signal.h>
  3. #include <sys/types.h>
  4. #include <sys/epoll.h>
  5. #include <fcntl.h>
  6. #include <sys/socket.h>
  7. #include <netinet/in.h>
  8. #include <arpa/inet.h>
  9. #include <assert.h>
  10. #include <sys/stat.h>
  11. #include <string.h>
  12. #include <pthread.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <sys/mman.h>
  16. #include <stdarg.h>
  17. #include <errno.h>
  18. #include "locker.h"
  19. #include "threadpool.h"
  20. #include "http_conn.h"
  21. #define MAX_FD 65536
  22. #define MAX_EVENT_NUMBER 10000
  23. extern int addfd(int epollfd, int fd, bool one_shot);
  24. extern int removefd(int epollfd, int fd);
  25. void addsig(int sig,void(handler)(int),bool restart = true){
  26. struct sigaction sa;
  27. memset(&sa,'\0',sizeof(sa));
  28. sa.sa_handler = handler;
  29. if(restart){
  30. sa.sa_flags |= SA_RESTART;
  31. }
  32. sigfillset(&sa.sa_mask);
  33. assert(sigaction(sig,&sa,NULL) != -1);
  34. }
  35. void show_error(int sockfd,const char* info){
  36. printf("%s\n",info);
  37. send(sockfd,info,strlen(info),0);
  38. close(sockfd);
  39. }
  40. int main(int argc,char* argv[]){
  41. if(argc <= 2){
  42. printf("usage:%s ip port\n",basename(argv[0]));
  43. return 1;
  44. }
  45. const char* ip = argv[1];
  46. int port = atoi(argv[2]);
  47. addsig(SIGPIPE,SIG_IGN);
  48. threadpool<http_conn>* pool = NULL;
  49. try
  50. {
  51. pool = new threadpool<http_conn>;
  52. }
  53. catch(...)
  54. {
  55. printf("error\n");
  56. return 1;
  57. }
  58. printf("creat a threadpool\n");
  59. http_conn* users = new http_conn[MAX_FD];
  60. assert(users);
  61. int user_count = 0;
  62. printf("create some users\n");
  63. sockaddr_in addr;
  64. bzero(&addr,sizeof(addr));
  65. addr.sin_family = AF_INET;
  66. inet_pton(AF_INET6,ip,&addr.sin_addr);
  67. addr.sin_port = htons(port);
  68. int listenfd = socket(PF_INET,SOCK_STREAM,0);
  69. assert(listenfd>=0);
  70. linger tmp = {1,0};
  71. setsockopt(listenfd,SOL_SOCKET,SO_LINGER,&tmp,sizeof(tmp));
  72. int ret = bind(listenfd,(sockaddr*)&addr,sizeof(addr));
  73. assert(ret != -1);
  74. ret = listen(listenfd,5);
  75. assert(ret != -1);
  76. printf("listening\n");
  77. int epollfd = epoll_create(5);
  78. assert(epollfd != -1);
  79. epoll_event events[MAX_EVENT_NUMBER];
  80. addfd(epollfd,listenfd,false);
  81. http_conn::m_epollfd = epollfd;
  82. while(true){
  83. int number = epoll_wait(epollfd,events,MAX_EVENT_NUMBER,-1);
  84. if((number < 0) && (errno!=EAGAIN)){
  85. printf("epoll failure\n");
  86. break;
  87. }
  88. for(int i=0;i<number;++i){
  89. int sockfd = events[i].data.fd;
  90. if(sockfd == listenfd){
  91. sockaddr_in clientAddr;
  92. socklen_t len = sizeof(clientAddr);
  93. int connfd = accept(listenfd,(sockaddr*)&clientAddr,&len);
  94. if(connfd < 0){
  95. printf("accept errno\n");
  96. continue;
  97. }
  98. if(http_conn::m_user_count >= MAX_FD){
  99. show_error(connfd,"Internal server busy\n");
  100. continue;
  101. }
  102. users[connfd].init(connfd,clientAddr);
  103. }
  104. else if(events[i].events & (EPOLLRDBAND | EPOLLHUP | EPOLLERR)){
  105. users[sockfd].close_conn();
  106. }
  107. else if(events[i].events & EPOLLIN){
  108. if(users[sockfd].read()){
  109. pool->append(users + sockfd);
  110. }
  111. else{
  112. users[sockfd].close_conn();
  113. }
  114. }
  115. else if(events[i].events & EPOLLOUT){
  116. if(!users[sockfd].write()){
  117. users[sockfd].close_conn();
  118. }
  119. printf("write ok\n");
  120. }
  121. else{}
  122. }
  123. }
  124. close(epollfd);
  125. close(listenfd);
  126. delete[] users;
  127. delete pool;
  128. return 0;
  129. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/889292
推荐阅读
相关标签
  

闽ICP备14008679号