生活随笔
收集整理的這篇文章主要介紹了
基于半同步/半反应堆线程池实现的HTTP解析服务端程序
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
簡介:
? ? ?半同步/半反應(yīng)堆線程池是通過一個線程往工作隊列添加任務(wù)T,然后工作線程競爭工作隊列獲得任務(wù)T。HTTP請求解析服務(wù)端程序:逐行解析客戶端發(fā)送來的HTTP請求然后作出HTTP回答。采用線程池就是:服務(wù)端創(chuàng)建一個線程池,然后有HTTP請求到達就將HTTP請求的處理添加到線程池任務(wù)隊列中去,線程池工作線程通過競態(tài)機制(信號量)競爭任務(wù)T(HTTP請求處理)。
? ?HTTP請求內(nèi)容:
? ? ? GET http://www.baidu.com/index.html HTTP/1.1 ? ? ? //該行是HTTP請求行,GET是請求方法表示以只讀方式獲取資源 ?http那一串是url ? HTTP那個是客戶端HTTP版本
? ? ? User-Agent:Wget/1.12 (linux-gnu) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //客戶端使用的程序
? ? ? Host: www.baidu.com?? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ? ? ? ? ? ?//目的主機名,必須有
? ? ? Connection: close?? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //用于告訴服務(wù)器處理完這個請求后關(guān)閉連接,可選其它
? ? ? 注意:第一行為請求行,后面3行是HTTP頭部,HTTP請求每行均以回車符和換行符結(jié)束,所有頭部字段結(jié)束后必須包含一個空行,該空行只能有一個 回車和換行符。HTTP回答類似??梢奌TTP解析分為請求行和頭部,每行按照\r\t提取
? 半同步/半異步線程池:threadpool.h
[cpp] view plaincopy
#ifndef?THREADPOOL_H??#define?THREADPOOL_H????#include?<list>??#include?<cstdio>??#include?<exception>??#include?<pthread.h>??#include?"locker.h"//簡單封裝了互斥量和信號量的接口????template<?typename?T?>??class?threadpool??{??public:??????threadpool(?int?thread_number?=?8,?int?max_requests?=?10000?);??????~threadpool();??????bool?append(?T*?request?);????private:??????static?void*?worker(?void*?arg?);??????void?run();????private:??????int?m_thread_number;??????int?m_max_requests;??????pthread_t*?m_threads;??????std::list<?T*?>?m_workqueue;??????locker?m_queuelocker;??????sem?m_queuestat;??????bool?m_stop;??};????template<?typename?T?>??threadpool<?T?>::threadpool(?int?thread_number,?int?max_requests?)?:???????????m_thread_number(?thread_number?),?m_max_requests(?max_requests?),?m_stop(?false?),?m_threads(?NULL?)??{??????if(?(?thread_number?<=?0?)?||?(?max_requests?<=?0?)?)??????{??????????throw?std::exception();??????}????????m_threads?=?new?pthread_t[?m_thread_number?];??????if(?!?m_threads?)??????{??????????throw?std::exception();??????}????????for?(?int?i?=?0;?i?<?thread_number;?++i?)??????{??????????printf(?"create?the?%dth?thread\n",?i?);??????????if(?pthread_create(?m_threads?+?i,?NULL,?worker,?this?)?!=?0?)??????????{??????????????delete?[]?m_threads;??????????????throw?std::exception();??????????}??????????if(?pthread_detach(?m_threads[i]?)?)??????????{??????????????delete?[]?m_threads;??????????????throw?std::exception();??????????}??????}??}????template<?typename?T?>??threadpool<?T?>::~threadpool()??{??????delete?[]?m_threads;??????m_stop?=?true;??}????template<?typename?T?>??bool?threadpool<?T?>::append(?T*?request?)??{??????m_queuelocker.lock();??????if?(?m_workqueue.size()?>?m_max_requests?)??????{??????????m_queuelocker.unlock();??????????return?false;??????}??????m_workqueue.push_back(?request?);??????m_queuelocker.unlock();??????m_queuestat.post();??????return?true;??}????template<?typename?T?>??void*?threadpool<?T?>::worker(?void*?arg?)??{??????threadpool*?pool?=?(?threadpool*?)arg;??????pool->run();??????return?pool;??}????template<?typename?T?>??void?threadpool<?T?>::run()??{??????while?(?!?m_stop?)??????{??????????m_queuestat.wait();??????????m_queuelocker.lock();??????????if?(?m_workqueue.empty()?)??????????{??????????????m_queuelocker.unlock();??????????????continue;??????????}??????????T*?request?=?m_workqueue.front();??????????m_workqueue.pop_front();??????????m_queuelocker.unlock();??????????if?(?!?request?)??????????{??????????????continue;??????????}??????????request->process();??????}??}????#endif??
HTTP請求任務(wù)T:http_conn.h接收到一個HTTP請求后解析該請求,然后作出應(yīng)答
[cpp] view plaincopy
#ifndef?HTTPCONNECTION_H??#define?HTTPCONNECTION_H????#include?<unistd.h>??#include?<signal.h>??#include?<sys/types.h>??#include?<sys/epoll.h>??#include?<fcntl.h>??#include?<sys/socket.h>??#include?<netinet/in.h>??#include?<arpa/inet.h>??#include?<assert.h>??#include?<sys/stat.h>??#include?<string.h>??#include?<pthread.h>??#include?<stdio.h>??#include?<stdlib.h>??#include?<sys/mman.h>??#include?<stdarg.h>??#include?<errno.h>??#include?"locker.h"//互斥量和信號量的簡單封裝????class?http_conn??{??public:??????static?const?int?FILENAME_LEN?=?200;??????static?const?int?READ_BUFFER_SIZE?=?2048;??????static?const?int?WRITE_BUFFER_SIZE?=?1024;??????enum?METHOD?{?GET?=?0,?POST,?HEAD,?PUT,?DELETE,?TRACE,?OPTIONS,?CONNECT,?PATCH?};??????enum?CHECK_STATE?{?CHECK_STATE_REQUESTLINE?=?0,?CHECK_STATE_HEADER,?CHECK_STATE_CONTENT?};??????enum?HTTP_CODE?{?NO_REQUEST,?GET_REQUEST,?BAD_REQUEST,?NO_RESOURCE,?FORBIDDEN_REQUEST,?FILE_REQUEST,?INTERNAL_ERROR,?CLOSED_CONNECTION?};??????enum?LINE_STATUS?{?LINE_OK?=?0,?LINE_BAD,?LINE_OPEN?};????public:??????http_conn(){}??????~http_conn(){}????public:??????void?init(?int?sockfd,?const?sockaddr_in&?addr?);??????void?close_conn(?bool?real_close?=?true?);??????void?process();??????bool?read();??????bool?write();????private:??????void?init();??????HTTP_CODE?process_read();??????bool?process_write(?HTTP_CODE?ret?);????????HTTP_CODE?parse_request_line(?char*?text?);??????HTTP_CODE?parse_headers(?char*?text?);??????HTTP_CODE?parse_content(?char*?text?);??????HTTP_CODE?do_request();??????char*?get_line()?{?return?m_read_buf?+?m_start_line;?}??????LINE_STATUS?parse_line();????????????void?unmap();??????bool?add_response(?const?char*?format,?...?);??????bool?add_content(?const?char*?content?);??????bool?add_status_line(?int?status,?const?char*?title?);??????bool?add_headers(?int?content_length?);??????bool?add_content_length(?int?content_length?);??????bool?add_linger();??????bool?add_blank_line();????public:??????static?int?m_epollfd;??????static?int?m_user_count;????private:??????int?m_sockfd;??????sockaddr_in?m_address;????????char?m_read_buf[?READ_BUFFER_SIZE?];??????int?m_read_idx;??????int?m_checked_idx;??????int?m_start_line;??????char?m_write_buf[?WRITE_BUFFER_SIZE?];??????int?m_write_idx;????????CHECK_STATE?m_check_state;??????METHOD?m_method;????????char?m_real_file[?FILENAME_LEN?];??????char*?m_url;??????char*?m_version;??????char*?m_host;??????int?m_content_length;??????bool?m_linger;????????char*?m_file_address;??????struct?stat?m_file_stat;??????struct?iovec?m_iv[2];??????int?m_iv_count;??};????#endif??
任務(wù)T:http_conn.cpp
[cpp] view plaincopy
#include?"http_conn.h"????const?char*?ok_200_title?=?"OK";??const?char*?error_400_title?=?"Bad?Request";??const?char*?error_400_form?=?"Your?request?has?bad?syntax?or?is?inherently?impossible?to?satisfy.\n";??const?char*?error_403_title?=?"Forbidden";??const?char*?error_403_form?=?"You?do?not?have?permission?to?get?file?from?this?server.\n";??const?char*?error_404_title?=?"Not?Found";??const?char*?error_404_form?=?"The?requested?file?was?not?found?on?this?server.\n";??const?char*?error_500_title?=?"Internal?Error";??const?char*?error_500_form?=?"There?was?an?unusual?problem?serving?the?requested?file.\n";??const?char*?doc_root?=?"/var/www/html";????int?setnonblocking(?int?fd?)??{??????int?old_option?=?fcntl(?fd,?F_GETFL?);??????int?new_option?=?old_option?|?O_NONBLOCK;??????fcntl(?fd,?F_SETFL,?new_option?);??????return?old_option;??}????void?addfd(?int?epollfd,?int?fd,?bool?one_shot?)??{??????epoll_event?event;??????event.data.fd?=?fd;??????event.events?=?EPOLLIN?|?EPOLLET?|?EPOLLRDHUP;??????if(?one_shot?)??????{??????????event.events?|=?EPOLLONESHOT;??????}??????epoll_ctl(?epollfd,?EPOLL_CTL_ADD,?fd,?&event?);??????setnonblocking(?fd?);??}????void?removefd(?int?epollfd,?int?fd?)??{??????epoll_ctl(?epollfd,?EPOLL_CTL_DEL,?fd,?0?);??????close(?fd?);??}????void?modfd(?int?epollfd,?int?fd,?int?ev?)??{??????epoll_event?event;??????event.data.fd?=?fd;??????event.events?=?ev?|?EPOLLET?|?EPOLLONESHOT?|?EPOLLRDHUP;??????epoll_ctl(?epollfd,?EPOLL_CTL_MOD,?fd,?&event?);??}????int?http_conn::m_user_count?=?0;??int?http_conn::m_epollfd?=?-1;????void?http_conn::close_conn(?bool?real_close?)??{??????if(?real_close?&&?(?m_sockfd?!=?-1?)?)??????{????????????????????removefd(?m_epollfd,?m_sockfd?);??????????m_sockfd?=?-1;??????????m_user_count--;??????}??}????void?http_conn::init(?int?sockfd,?const?sockaddr_in&?addr?)??{??????m_sockfd?=?sockfd;??????m_address?=?addr;??????int?error?=?0;??????socklen_t?len?=?sizeof(?error?);??????getsockopt(?m_sockfd,?SOL_SOCKET,?SO_ERROR,?&error,?&len?);??????int?reuse?=?1;??????setsockopt(?m_sockfd,?SOL_SOCKET,?SO_REUSEADDR,?&reuse,?sizeof(?reuse?)?);??????addfd(?m_epollfd,?sockfd,?true?);??????m_user_count++;????????init();??}????void?http_conn::init()??{??????m_check_state?=?CHECK_STATE_REQUESTLINE;??????m_linger?=?false;????????m_method?=?GET;??????m_url?=?0;??????m_version?=?0;??????m_content_length?=?0;??????m_host?=?0;??????m_start_line?=?0;??????m_checked_idx?=?0;??????m_read_idx?=?0;??????m_write_idx?=?0;??????memset(?m_read_buf,?'\0',?READ_BUFFER_SIZE?);??????memset(?m_write_buf,?'\0',?WRITE_BUFFER_SIZE?);??????memset(?m_real_file,?'\0',?FILENAME_LEN?);??}????http_conn::LINE_STATUS?http_conn::parse_line()??{??????char?temp;??????for?(?;?m_checked_idx?<?m_read_idx;?++m_checked_idx?)??????{??????????temp?=?m_read_buf[?m_checked_idx?];??????????if?(?temp?==?'\r'?)??????????{??????????????if?(?(?m_checked_idx?+?1?)?==?m_read_idx?)??????????????{??????????????????return?LINE_OPEN;??????????????}??????????????else?if?(?m_read_buf[?m_checked_idx?+?1?]?==?'\n'?)??????????????{??????????????????m_read_buf[?m_checked_idx++?]?=?'\0';??????????????????m_read_buf[?m_checked_idx++?]?=?'\0';??????????????????return?LINE_OK;??????????????}????????????????return?LINE_BAD;??????????}??????????else?if(?temp?==?'\n'?)??????????{??????????????if(?(?m_checked_idx?>?1?)?&&?(?m_read_buf[?m_checked_idx?-?1?]?==?'\r'?)?)??????????????{??????????????????m_read_buf[?m_checked_idx-1?]?=?'\0';??????????????????m_read_buf[?m_checked_idx++?]?=?'\0';??????????????????return?LINE_OK;??????????????}??????????????return?LINE_BAD;??????????}??????}????????return?LINE_OPEN;??}????bool?http_conn::read()??{??????if(?m_read_idx?>=?READ_BUFFER_SIZE?)??????{??????????return?false;??????}????????int?bytes_read?=?0;??????while(?true?)??????{??????????bytes_read?=?recv(?m_sockfd,?m_read_buf?+?m_read_idx,?READ_BUFFER_SIZE?-?m_read_idx,?0?);??????????if?(?bytes_read?==?-1?)??????????{??????????????if(?errno?==?EAGAIN?||?errno?==?EWOULDBLOCK?)??????????????{??????????????????break;??????????????}??????????????return?false;??????????}??????????else?if?(?bytes_read?==?0?)??????????{??????????????return?false;??????????}????????????m_read_idx?+=?bytes_read;??????}??????return?true;??}????http_conn::HTTP_CODE?http_conn::parse_request_line(?char*?text?)??{??????m_url?=?strpbrk(?text,?"?\t"?);??????if?(?!?m_url?)??????{??????????return?BAD_REQUEST;??????}??????*m_url++?=?'\0';????????char*?method?=?text;??????if?(?strcasecmp(?method,?"GET"?)?==?0?)??????{??????????m_method?=?GET;??????}??????else??????{??????????return?BAD_REQUEST;??????}????????m_url?+=?strspn(?m_url,?"?\t"?);??????m_version?=?strpbrk(?m_url,?"?\t"?);??????if?(?!?m_version?)??????{??????????return?BAD_REQUEST;??????}??????*m_version++?=?'\0';??????m_version?+=?strspn(?m_version,?"?\t"?);??????if?(?strcasecmp(?m_version,?"HTTP/1.1"?)?!=?0?)??????{??????????return?BAD_REQUEST;??????}????????if?(?strncasecmp(?m_url,?"http://",?7?)?==?0?)??????{??????????m_url?+=?7;??????????m_url?=?strchr(?m_url,?'/'?);??????}????????if?(?!?m_url?||?m_url[?0?]?!=?'/'?)??????{??????????return?BAD_REQUEST;??????}????????m_check_state?=?CHECK_STATE_HEADER;??????return?NO_REQUEST;??}????http_conn::HTTP_CODE?http_conn::parse_headers(?char*?text?)??{??????if(?text[?0?]?==?'\0'?)??????{??????????if?(?m_method?==?HEAD?)??????????{??????????????return?GET_REQUEST;??????????}????????????if?(?m_content_length?!=?0?)??????????{??????????????m_check_state?=?CHECK_STATE_CONTENT;??????????????return?NO_REQUEST;??????????}????????????return?GET_REQUEST;??????}??????else?if?(?strncasecmp(?text,?"Connection:",?11?)?==?0?)??????{??????????text?+=?11;??????????text?+=?strspn(?text,?"?\t"?);??????????if?(?strcasecmp(?text,?"keep-alive"?)?==?0?)??????????{??????????????m_linger?=?true;??????????}??????}??????else?if?(?strncasecmp(?text,?"Content-Length:",?15?)?==?0?)??????{??????????text?+=?15;??????????text?+=?strspn(?text,?"?\t"?);??????????m_content_length?=?atol(?text?);??????}??????else?if?(?strncasecmp(?text,?"Host:",?5?)?==?0?)??????{??????????text?+=?5;??????????text?+=?strspn(?text,?"?\t"?);??????????m_host?=?text;??????}??????else??????{??????????printf(?"oop!?unknow?header?%s\n",?text?);??????}????????return?NO_REQUEST;????}????http_conn::HTTP_CODE?http_conn::parse_content(?char*?text?)??{??????if?(?m_read_idx?>=?(?m_content_length?+?m_checked_idx?)?)??????{??????????text[?m_content_length?]?=?'\0';??????????return?GET_REQUEST;??????}????????return?NO_REQUEST;??}????http_conn::HTTP_CODE?http_conn::process_read()??{??????LINE_STATUS?line_status?=?LINE_OK;??????HTTP_CODE?ret?=?NO_REQUEST;??????char*?text?=?0;????????while?(?(?(?m_check_state?==?CHECK_STATE_CONTENT?)?&&?(?line_status?==?LINE_OK??)?)??????????????????||?(?(?line_status?=?parse_line()?)?==?LINE_OK?)?){??????????text?=?get_line();??????????m_start_line?=?m_checked_idx;??????????printf(?"got?1?http?line:?%s\n",?text?);????????????switch?(?m_check_state?)??????????{??????????????case?CHECK_STATE_REQUESTLINE:??????????????{??????????????????ret?=?parse_request_line(?text?);??????????????????if?(?ret?==?BAD_REQUEST?)??????????????????{??????????????????????return?BAD_REQUEST;??????????????????}??????????????????break;??????????????}??????????????case?CHECK_STATE_HEADER:??????????????{??????????????????ret?=?parse_headers(?text?);??????????????????if?(?ret?==?BAD_REQUEST?)??????????????????{??????????????????????return?BAD_REQUEST;??????????????????}??????????????????else?if?(?ret?==?GET_REQUEST?)??????????????????{??????????????????????return?do_request();??????????????????}??????????????????break;??????????????}??????????????case?CHECK_STATE_CONTENT:??????????????{??????????????????ret?=?parse_content(?text?);??????????????????if?(?ret?==?GET_REQUEST?)??????????????????{??????????????????????return?do_request();??????????????????}??????????????????line_status?=?LINE_OPEN;??????????????????break;??????????????}??????????????default:??????????????{??????????????????return?INTERNAL_ERROR;??????????????}??????????}??????}????????return?NO_REQUEST;??}????http_conn::HTTP_CODE?http_conn::do_request()??{??????strcpy(?m_real_file,?doc_root?);??????int?len?=?strlen(?doc_root?);??????strncpy(?m_real_file?+?len,?m_url,?FILENAME_LEN?-?len?-?1?);??????if?(?stat(?m_real_file,?&m_file_stat?)?<?0?)??????{??????????return?NO_RESOURCE;??????}????????if?(?!?(?m_file_stat.st_mode?&?S_IROTH?)?)??????{??????????return?FORBIDDEN_REQUEST;??????}????????if?(?S_ISDIR(?m_file_stat.st_mode?)?)??????{??????????return?BAD_REQUEST;??????}????????int?fd?=?open(?m_real_file,?O_RDONLY?);??????m_file_address?=?(?char*?)mmap(?0,?m_file_stat.st_size,?PROT_READ,?MAP_PRIVATE,?fd,?0?);??????close(?fd?);??????return?FILE_REQUEST;??}????void?http_conn::unmap()??{??????if(?m_file_address?)??????{??????????munmap(?m_file_address,?m_file_stat.st_size?);??????????m_file_address?=?0;??????}??}????bool?http_conn::write()??{??????int?temp?=?0;??????int?bytes_have_send?=?0;??????int?bytes_to_send?=?m_write_idx;??????if?(?bytes_to_send?==?0?)??????{??????????modfd(?m_epollfd,?m_sockfd,?EPOLLIN?);??????????init();??????????return?true;??????}????????while(?1?)??????{??????????temp?=?writev(?m_sockfd,?m_iv,?m_iv_count?);??????????if?(?temp?<=?-1?)??????????{??????????????if(?errno?==?EAGAIN?)??????????????{??????????????????modfd(?m_epollfd,?m_sockfd,?EPOLLOUT?);??????????????????return?true;??????????????}??????????????unmap();??????????????return?false;??????????}????????????bytes_to_send?-=?temp;??????????bytes_have_send?+=?temp;??????????if?(?bytes_to_send?<=?bytes_have_send?)??????????{??????????????unmap();??????????????if(?m_linger?)??????????????{??????????????????init();??????????????????modfd(?m_epollfd,?m_sockfd,?EPOLLIN?);??????????????????return?true;??????????????}??????????????else??????????????{??????????????????modfd(?m_epollfd,?m_sockfd,?EPOLLIN?);??????????????????return?false;??????????????}???????????}??????}??}????bool?http_conn::add_response(?const?char*?format,?...?)??{??????if(?m_write_idx?>=?WRITE_BUFFER_SIZE?)??????{??????????return?false;??????}??????va_list?arg_list;??????va_start(?arg_list,?format?);??????int?len?=?vsnprintf(?m_write_buf?+?m_write_idx,?WRITE_BUFFER_SIZE?-?1?-?m_write_idx,?format,?arg_list?);??????if(?len?>=?(?WRITE_BUFFER_SIZE?-?1?-?m_write_idx?)?)??????{??????????return?false;??????}??????m_write_idx?+=?len;??????va_end(?arg_list?);??????return?true;??}????bool?http_conn::add_status_line(?int?status,?const?char*?title?)??{??????return?add_response(?"%s?%d?%s\r\n",?"HTTP/1.1",?status,?title?);??}????bool?http_conn::add_headers(?int?content_len?)??{??????add_content_length(?content_len?);??????add_linger();??????add_blank_line();??}????bool?http_conn::add_content_length(?int?content_len?)??{??????return?add_response(?"Content-Length:?%d\r\n",?content_len?);??}????bool?http_conn::add_linger()??{??????return?add_response(?"Connection:?%s\r\n",?(?m_linger?==?true?)???"keep-alive"?:?"close"?);??}????bool?http_conn::add_blank_line()??{??????return?add_response(?"%s",?"\r\n"?);??}????bool?http_conn::add_content(?const?char*?content?)??{??????return?add_response(?"%s",?content?);??}????bool?http_conn::process_write(?HTTP_CODE?ret?)??{??????switch?(?ret?)??????{??????????case?INTERNAL_ERROR:??????????{??????????????add_status_line(?500,?error_500_title?);??????????????add_headers(?strlen(?error_500_form?)?);??????????????if?(?!?add_content(?error_500_form?)?)??????????????{??????????????????return?false;??????????????}??????????????break;??????????}??????????case?BAD_REQUEST:??????????{??????????????add_status_line(?400,?error_400_title?);??????????????add_headers(?strlen(?error_400_form?)?);??????????????if?(?!?add_content(?error_400_form?)?)??????????????{??????????????????return?false;??????????????}??????????????break;??????????}??????????case?NO_RESOURCE:??????????{??????????????add_status_line(?404,?error_404_title?);??????????????add_headers(?strlen(?error_404_form?)?);??????????????if?(?!?add_content(?error_404_form?)?)??????????????{??????????????????return?false;??????????????}??????????????break;??????????}??????????case?FORBIDDEN_REQUEST:??????????{??????????????add_status_line(?403,?error_403_title?);??????????????add_headers(?strlen(?error_403_form?)?);??????????????if?(?!?add_content(?error_403_form?)?)??????????????{??????????????????return?false;??????????????}??????????????break;??????????}??????????case?FILE_REQUEST:??????????{??????????????add_status_line(?200,?ok_200_title?);??????????????if?(?m_file_stat.st_size?!=?0?)??????????????{??????????????????add_headers(?m_file_stat.st_size?);??????????????????m_iv[?0?].iov_base?=?m_write_buf;??????????????????m_iv[?0?].iov_len?=?m_write_idx;??????????????????m_iv[?1?].iov_base?=?m_file_address;??????????????????m_iv[?1?].iov_len?=?m_file_stat.st_size;??????????????????m_iv_count?=?2;??????????????????return?true;??????????????}??????????????else??????????????{??????????????????const?char*?ok_string?=?"<html><body></body></html>";??????????????????add_headers(?strlen(?ok_string?)?);??????????????????if?(?!?add_content(?ok_string?)?)??????????????????{??????????????????????return?false;??????????????????}??????????????}??????????}??????????default:??????????{??????????????return?false;??????????}??????}????????m_iv[?0?].iov_base?=?m_write_buf;??????m_iv[?0?].iov_len?=?m_write_idx;??????m_iv_count?=?1;??????return?true;??}????void?http_conn::process()??{??????HTTP_CODE?read_ret?=?process_read();??????if?(?read_ret?==?NO_REQUEST?)??????{??????????modfd(?m_epollfd,?m_sockfd,?EPOLLIN?);??????????return;??????}????????bool?write_ret?=?process_write(?read_ret?);??????if?(?!?write_ret?)??????{??????????close_conn();??????}????????modfd(?m_epollfd,?m_sockfd,?EPOLLOUT?);??}??
服務(wù)端程序:接收HTTP請求并交給線程池處理這些請求
[cpp] view plaincopy
#include?<sys/socket.h>??#include?<netinet/in.h>??#include?<arpa/inet.h>??#include?<stdio.h>??#include?<unistd.h>??#include?<errno.h>??#include?<string.h>??#include?<fcntl.h>??#include?<stdlib.h>??#include?<cassert>??#include?<sys/epoll.h>????#include?"locker.h"//該頭文件封裝了信號量和互斥量??#include?"threadpool.h"//半同步/半反應(yīng)堆線程池??#include?"http_conn.h"//HTTP連接任務(wù)類T????#define?MAX_FD?65536//最大文件數(shù)目??#define?MAX_EVENT_NUMBER?10000//最大事件數(shù)目????extern?int?addfd(?int?epollfd,?int?fd,?bool?one_shot?);??extern?int?removefd(?int?epollfd,?int?fd?);????void?addsig(?int?sig,?void(?handler?)(int),?bool?restart?=?true?)??{??????struct?sigaction?sa;??????memset(?&sa,?'\0',?sizeof(?sa?)?);??????sa.sa_handler?=?handler;??????if(?restart?)??????{??????????sa.sa_flags?|=?SA_RESTART;??????}??????sigfillset(?&sa.sa_mask?);??????assert(?sigaction(?sig,?&sa,?NULL?)?!=?-1?);??}????void?show_error(?int?connfd,?const?char*?info?)??{??????printf(?"%s",?info?);??????send(?connfd,?info,?strlen(?info?),?0?);??????close(?connfd?);??}??????int?main(?int?argc,?char*?argv[]?)??{??????if(?argc?<=?2?)??????{??????????printf(?"usage:?%s?ip_address?port_number\n",?basename(?argv[0]?)?);??????????return?1;??????}??????const?char*?ip?=?argv[1];??????int?port?=?atoi(?argv[2]?);????????addsig(?SIGPIPE,?SIG_IGN?);????????threadpool<?http_conn?>*?pool?=?NULL;??????try??????{??????????pool?=?new?threadpool<?http_conn?>;??????}??????catch(?...?)??????{??????????return?1;??????}????????http_conn*?users?=?new?http_conn[?MAX_FD?];??????assert(?users?);??????int?user_count?=?0;????????int?listenfd?=?socket(?PF_INET,?SOCK_STREAM,?0?);??????assert(?listenfd?>=?0?);??????struct?linger?tmp?=?{?1,?0?};??????setsockopt(?listenfd,?SOL_SOCKET,?SO_LINGER,?&tmp,?sizeof(?tmp?)?);????????int?ret?=?0;??????struct?sockaddr_in?address;??????bzero(?&address,?sizeof(?address?)?);??????address.sin_family?=?AF_INET;??????inet_pton(?AF_INET,?ip,?&address.sin_addr?);??????address.sin_port?=?htons(?port?);????????ret?=?bind(?listenfd,?(?struct?sockaddr*?)&address,?sizeof(?address?)?);??????assert(?ret?>=?0?);????????ret?=?listen(?listenfd,?5?);??????assert(?ret?>=?0?);????????epoll_event?events[?MAX_EVENT_NUMBER?];??????int?epollfd?=?epoll_create(?5?);??????assert(?epollfd?!=?-1?);??????addfd(?epollfd,?listenfd,?false?);??????http_conn::m_epollfd?=?epollfd;????????while(?true?)??????{??????????int?number?=?epoll_wait(?epollfd,?events,?MAX_EVENT_NUMBER,?-1?);??????????if?(?(?number?<?0?)?&&?(?errno?!=?EINTR?)?)??????????{??????????????printf(?"epoll?failure\n"?);??????????????break;??????????}????????????for?(?int?i?=?0;?i?<?number;?i++?)??????????{??????????????int?sockfd?=?events[i].data.fd;??????????????if(?sockfd?==?listenfd?)??????????????{??????????????????struct?sockaddr_in?client_address;??????????????????socklen_t?client_addrlength?=?sizeof(?client_address?);??????????????????int?connfd?=?accept(?listenfd,?(?struct?sockaddr*?)&client_address,?&client_addrlength?);??????????????????if?(?connfd?<?0?)??????????????????{??????????????????????printf(?"errno?is:?%d\n",?errno?);??????????????????????continue;??????????????????}??????????????????if(?http_conn::m_user_count?>=?MAX_FD?)??????????????????{??????????????????????show_error(?connfd,?"Internal?server?busy"?);??????????????????????continue;??????????????????}????????????????????????????????????users[connfd].init(?connfd,?client_address?);??????????????}??????????????else?if(?events[i].events?&?(?EPOLLRDHUP?|?EPOLLHUP?|?EPOLLERR?)?)??????????????{??????????????????users[sockfd].close_conn();??????????????}??????????????else?if(?events[i].events?&?EPOLLIN?)??????????????{??????????????????if(?users[sockfd].read()?)??????????????????{??????????????????????pool->append(?users?+?sockfd?);??????????????????}??????????????????else??????????????????{??????????????????????users[sockfd].close_conn();??????????????????}??????????????}??????????????else?if(?events[i].events?&?EPOLLOUT?)??????????????{??????????????????if(?!users[sockfd].write()?)??????????????????{??????????????????????users[sockfd].close_conn();??????????????????}??????????????}??????????????else??????????????{}??????????}??????}????????close(?epollfd?);??????close(?listenfd?);??????delete?[]?users;??????delete?pool;??????return?0;??}??
互斥量和信號量的簡單封裝:locker.h
[cpp] view plaincopy
#ifndef?LOCKER_H??#define?LOCKER_H????#include?<exception>??#include?<pthread.h>??#include?<semaphore.h>????class?sem??{??public:??????sem()??????{??????????if(?sem_init(?&m_sem,?0,?0?)?!=?0?)??????????{??????????????throw?std::exception();??????????}??????}??????~sem()??????{??????????sem_destroy(?&m_sem?);??????}??????bool?wait()??????{??????????return?sem_wait(?&m_sem?)?==?0;??????}??????bool?post()??????{??????????return?sem_post(?&m_sem?)?==?0;??????}????private:??????sem_t?m_sem;??};????class?locker??{??public:??????locker()??????{??????????if(?pthread_mutex_init(?&m_mutex,?NULL?)?!=?0?)??????????{??????????????throw?std::exception();??????????}??????}??????~locker()??????{??????????pthread_mutex_destroy(?&m_mutex?);??????}??????bool?lock()??????{??????????return?pthread_mutex_lock(?&m_mutex?)?==?0;??????}??????bool?unlock()??????{??????????return?pthread_mutex_unlock(?&m_mutex?)?==?0;??????}????private:??????pthread_mutex_t?m_mutex;??};????class?cond??{??public:??????cond()??????{??????????if(?pthread_mutex_init(?&m_mutex,?NULL?)?!=?0?)??????????{??????????????throw?std::exception();??????????}??????????if?(?pthread_cond_init(?&m_cond,?NULL?)?!=?0?)??????????{??????????????pthread_mutex_destroy(?&m_mutex?);??????????????throw?std::exception();??????????}??????}??????~cond()??????{??????????pthread_mutex_destroy(?&m_mutex?);??????????pthread_cond_destroy(?&m_cond?);??????}??????bool?wait()??????{??????????int?ret?=?0;??????????pthread_mutex_lock(?&m_mutex?);??????????ret?=?pthread_cond_wait(?&m_cond,?&m_mutex?);??????????pthread_mutex_unlock(?&m_mutex?);??????????return?ret?==?0;??????}??????bool?signal()??????{??????????return?pthread_cond_signal(?&m_cond?)?==?0;??????}????private:??????pthread_mutex_t?m_mutex;??????pthread_cond_t?m_cond;??};????#endif??
壓力測試程序:通常有IO復(fù)用、多線程、多進程實現(xiàn)壓力測試,其中IO復(fù)用施壓程度最高其它的要切換CPU
本程序是客戶端通過命令行參數(shù)指定num個客戶連接,并向服務(wù)端發(fā)送HTTP請求,服務(wù)端HTTP應(yīng)答,客戶端輸出是請求和應(yīng)答數(shù)據(jù)交替出現(xiàn)
[cpp] view plaincopy
#include?<stdlib.h>??#include?<stdio.h>??#include?<assert.h>??#include?<unistd.h>??#include?<sys/types.h>??#include?<sys/epoll.h>??#include?<fcntl.h>??#include?<sys/socket.h>??#include?<netinet/in.h>??#include?<arpa/inet.h>??#include?<string.h>????static?const?char*?request?=?"GET?http://localhost/index.html?HTTP/1.1\r\nConnection:?keep-alive\r\n\r\nxxxxxxxxxxxx";????int?setnonblocking(?int?fd?)??{??????int?old_option?=?fcntl(?fd,?F_GETFL?);??????int?new_option?=?old_option?|?O_NONBLOCK;??????fcntl(?fd,?F_SETFL,?new_option?);??????return?old_option;??}????void?addfd(?int?epoll_fd,?int?fd?)??{??????epoll_event?event;??????event.data.fd?=?fd;??????event.events?=?EPOLLOUT?|?EPOLLET?|?EPOLLERR;??????epoll_ctl(?epoll_fd,?EPOLL_CTL_ADD,?fd,?&event?);??????setnonblocking(?fd?);??}????bool?write_nbytes(?int?sockfd,?const?char*?buffer,?int?len?)??{??????int?bytes_write?=?0;??????printf(?"write?out?%d?bytes?to?socket?%d\n",?len,?sockfd?);??????while(?1?)???????{?????????????bytes_write?=?send(?sockfd,?buffer,?len,?0?);??????????if?(?bytes_write?==?-1?)??????????{?????????????????return?false;??????????}?????????????else?if?(?bytes_write?==?0?)???????????{?????????????????return?false;??????????}???????????????len?-=?bytes_write;??????????buffer?=?buffer?+?bytes_write;??????????if?(?len?<=?0?)???????????{?????????????????return?true;??????????}?????????}?????}????bool?read_once(?int?sockfd,?char*?buffer,?int?len?)??{??????int?bytes_read?=?0;??????memset(?buffer,?'\0',?len?);??????bytes_read?=?recv(?sockfd,?buffer,?len,?0?);??????if?(?bytes_read?==?-1?)??????{??????????return?false;??????}??????else?if?(?bytes_read?==?0?)??????{??????????return?false;??????}??????printf(?"read?in?%d?bytes?from?socket?%d?with?content:?%s\n",?bytes_read,?sockfd,?buffer?);????????return?true;??}????void?start_conn(?int?epoll_fd,?int?num,?const?char*?ip,?int?port?)??{??????int?ret?=?0;??????struct?sockaddr_in?address;??????bzero(?&address,?sizeof(?address?)?);??????address.sin_family?=?AF_INET;??????inet_pton(?AF_INET,?ip,?&address.sin_addr?);??????address.sin_port?=?htons(?port?);????????for?(?int?i?=?0;?i?<?num;?++i?)??????{??????????sleep(?1?);??????????int?sockfd?=?socket(?PF_INET,?SOCK_STREAM,?0?);??????????printf(?"create?1?sock\n"?);??????????if(?sockfd?<?0?)??????????{??????????????continue;??????????}????????????if?(??connect(?sockfd,?(?struct?sockaddr*?)&address,?sizeof(?address?)?)?==?0??)??????????{??????????????printf(?"build?connection?%d\n",?i?);??????????????addfd(?epoll_fd,?sockfd?);??????????}??????}??}????void?close_conn(?int?epoll_fd,?int?sockfd?)??{??????epoll_ctl(?epoll_fd,?EPOLL_CTL_DEL,?sockfd,?0?);??????close(?sockfd?);??}????int?main(?int?argc,?char*?argv[]?)??{??????assert(?argc?==?4?);??????int?epoll_fd?=?epoll_create(?100?);??????start_conn(?epoll_fd,?atoi(?argv[?3?]?),?argv[1],?atoi(?argv[2]?)?);??????epoll_event?events[?10000?];??????char?buffer[?2048?];??????while?(?1?)??????{??????????int?fds?=?epoll_wait(?epoll_fd,?events,?10000,?2000?);??????????for?(?int?i?=?0;?i?<?fds;?i++?)??????????{?????????????????int?sockfd?=?events[i].data.fd;??????????????if?(?events[i].events?&?EPOLLIN?)??????????????{?????????????????????if?(?!?read_once(?sockfd,?buffer,?2048?)?)??????????????????{??????????????????????close_conn(?epoll_fd,?sockfd?);??????????????????}??????????????????struct?epoll_event?event;??????????????????event.events?=?EPOLLOUT?|?EPOLLET?|?EPOLLERR;??????????????????event.data.fd?=?sockfd;??????????????????epoll_ctl(?epoll_fd,?EPOLL_CTL_MOD,?sockfd,?&event?);??????????????}??????????????else?if(?events[i].events?&?EPOLLOUT?)???????????????{??????????????????if?(?!?write_nbytes(?sockfd,?request,?strlen(?request?)?)?)??????????????????{??????????????????????close_conn(?epoll_fd,?sockfd?);??????????????????}??????????????????struct?epoll_event?event;??????????????????event.events?=?EPOLLIN?|?EPOLLET?|?EPOLLERR;??????????????????event.data.fd?=?sockfd;??????????????????epoll_ctl(?epoll_fd,?EPOLL_CTL_MOD,?sockfd,?&event?);??????????????}??????????????else?if(?events[i].events?&?EPOLLERR?)??????????????{??????????????????close_conn(?epoll_fd,?sockfd?);??????????????}??????????}??????}??}??
總結(jié)
以上是生活随笔為你收集整理的基于半同步/半反应堆线程池实现的HTTP解析服务端程序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。