日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

基于半同步/半反应堆线程池实现的HTTP解析服务端程序

發(fā)布時(shí)間:2023/12/10 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于半同步/半反应堆线程池实现的HTTP解析服务端程序 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

簡(jiǎn)介:

? ? ?半同步/半反應(yīng)堆線程池是通過(guò)一個(gè)線程往工作隊(duì)列添加任務(wù)T,然后工作線程競(jìng)爭(zhēng)工作隊(duì)列獲得任務(wù)T。HTTP請(qǐng)求解析服務(wù)端程序:逐行解析客戶端發(fā)送來(lái)的HTTP請(qǐng)求然后作出HTTP回答。采用線程池就是:服務(wù)端創(chuàng)建一個(gè)線程池,然后有HTTP請(qǐng)求到達(dá)就將HTTP請(qǐng)求的處理添加到線程池任務(wù)隊(duì)列中去,線程池工作線程通過(guò)競(jìng)態(tài)機(jī)制(信號(hào)量)競(jìng)爭(zhēng)任務(wù)T(HTTP請(qǐng)求處理)。

? ?HTTP請(qǐng)求內(nèi)容:

? ? ? GET http://www.baidu.com/index.html HTTP/1.1 ? ? ? //該行是HTTP請(qǐng)求行,GET是請(qǐng)求方法表示以只讀方式獲取資源 ?http那一串是url ? HTTP那個(gè)是客戶端HTTP版本

? ? ? User-Agent:Wget/1.12 (linux-gnu) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //客戶端使用的程序

? ? ? Host: www.baidu.com?? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ? ? ? ? ? ?//目的主機(jī)名,必須有

? ? ? Connection: close?? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //用于告訴服務(wù)器處理完這個(gè)請(qǐng)求后關(guān)閉連接,可選其它

? ? ? 注意:第一行為請(qǐng)求行,后面3行是HTTP頭部,HTTP請(qǐng)求每行均以回車符和換行符結(jié)束,所有頭部字段結(jié)束后必須包含一個(gè)空行,該空行只能有一個(gè) 回車和換行符。HTTP回答類似。可見(jiàn)HTTP解析分為請(qǐng)求行和頭部,每行按照\(chéng)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"//簡(jiǎn)單封裝了互斥量和信號(hào)量的接口??
  • ??
  • template<?typename?T?>??
  • class?threadpool//線程池類模板參數(shù)T是任務(wù)類型,T中必須有接口process??
  • {??
  • public:??
  • ????threadpool(?int?thread_number?=?8,?int?max_requests?=?10000?);//線程數(shù)目和最大連接處理數(shù)??
  • ????~threadpool();??
  • ????bool?append(?T*?request?);??
  • ??
  • private:??
  • ????static?void*?worker(?void*?arg?);//線程工作函數(shù)??
  • ????void?run();//啟動(dòng)線程池??
  • ??
  • private:??
  • ????int?m_thread_number;//線程數(shù)量??
  • ????int?m_max_requests;//最大連接數(shù)目??
  • ????pthread_t*?m_threads;//線程id??
  • ????std::list<?T*?>?m_workqueue;//工作隊(duì)列:各線程競(jìng)爭(zhēng)該隊(duì)列并處理相應(yīng)的任務(wù)邏輯T??
  • ????locker?m_queuelocker;//工作隊(duì)列互斥量??
  • ????sem?m_queuestat;//信號(hào)量:用于工作隊(duì)列??
  • ????bool?m_stop;//終止標(biāo)志??
  • };??
  • ??
  • 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?];//工作線程數(shù)組??
  • ????if(?!?m_threads?)??
  • ????{??
  • ????????throw?std::exception();??
  • ????}??
  • ??
  • ????for?(?int?i?=?0;?i?<?thread_number;?++i?)//創(chuàng)建工作線程??
  • ????{??
  • ????????printf(?"create?the?%dth?thread\n",?i?);??
  • ????????if(?pthread_create(?m_threads?+?i,?NULL,?worker,?this?)?!=?0?)//注意C++調(diào)用pthread_create函數(shù)的第三個(gè)參數(shù)必須是一個(gè)靜態(tài)函數(shù),一個(gè)靜態(tài)成員使用動(dòng)態(tài)成員的方式:通過(guò)類靜態(tài)對(duì)象、將類對(duì)象作為參數(shù)傳給靜態(tài)函數(shù)。這里使用了后者所以有this??
  • ????????{??
  • ????????????delete?[]?m_threads;??
  • ????????????throw?std::exception();??
  • ????????}??
  • ????????if(?pthread_detach(?m_threads[i]?)?)//線程分離后其它線程無(wú)法pthread_join等待??
  • ????????{??
  • ????????????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?)//向工作隊(duì)列添加任務(wù)T??
  • {??
  • ????m_queuelocker.lock();//非原子操作需要互斥量保護(hù)??
  • ????if?(?m_workqueue.size()?>?m_max_requests?)//任務(wù)隊(duì)列滿了??
  • ????{??
  • ????????m_queuelocker.unlock();??
  • ????????return?false;??
  • ????}??
  • ????m_workqueue.push_back(?request?);??
  • ????m_queuelocker.unlock();??
  • ????m_queuestat.post();//信號(hào)量的V操作,即信號(hào)量+1多了個(gè)工作任務(wù)T??
  • ????return?true;??
  • }??
  • ??
  • template<?typename?T?>??
  • void*?threadpool<?T?>::worker(?void*?arg?)//工作線程函數(shù)??
  • {??
  • ????threadpool*?pool?=?(?threadpool*?)arg;//獲取進(jìn)程池對(duì)象??
  • ????pool->run();//調(diào)用線程池run函數(shù)??
  • ????return?pool;??
  • }??
  • ??
  • template<?typename?T?>??
  • void?threadpool<?T?>::run()//工作線程真正工作邏輯:從任務(wù)隊(duì)列領(lǐng)取任務(wù)T并執(zhí)行任務(wù)T??
  • {??
  • ????while?(?!?m_stop?)??
  • ????{??
  • ????????m_queuestat.wait();//信號(hào)量P操作,申請(qǐng)信號(hào)量獲取任務(wù)T??
  • ????????m_queuelocker.lock();//互斥量保護(hù)任務(wù)隊(duì)列,和前面的信號(hào)量順序不能呼喚。。。你懂的??
  • ????????if?(?m_workqueue.empty()?)??
  • ????????{??
  • ????????????m_queuelocker.unlock();//任務(wù)隊(duì)列空那就沒(méi)任務(wù)唄??
  • ????????????continue;??
  • ????????}??
  • ????????T*?request?=?m_workqueue.front();//獲取任務(wù)T??
  • ????????m_workqueue.pop_front();??
  • ????????m_queuelocker.unlock();??
  • ????????if?(?!?request?)??
  • ????????{??
  • ????????????continue;??
  • ????????}??
  • ????????request->process();//執(zhí)行任務(wù)T的相應(yīng)邏輯,任務(wù)T中必須有process接口??
  • ????}??
  • }??
  • ??
  • #endif??

  • HTTP請(qǐng)求任務(wù)T:http_conn.h接收到一個(gè)HTTP請(qǐng)求后解析該請(qǐng)求,然后作出應(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"//互斥量和信號(hào)量的簡(jiǎn)單封裝??
  • ??
  • class?http_conn//HTTP連接任務(wù)類型,用于線程池工作隊(duì)列的任務(wù)類型T??
  • {??
  • public:??
  • ????static?const?int?FILENAME_LEN?=?200;//文件名最大長(zhǎng)度,文件是HTTP請(qǐng)求的資源頁(yè)文件??
  • ????static?const?int?READ_BUFFER_SIZE?=?2048;//讀緩沖區(qū),用于讀取HTTP請(qǐng)求??
  • ????static?const?int?WRITE_BUFFER_SIZE?=?1024;//寫緩沖區(qū),用于HTTP回答??
  • ????enum?METHOD?{?GET?=?0,?POST,?HEAD,?PUT,?DELETE,?TRACE,?OPTIONS,?CONNECT,?PATCH?};//HTTP請(qǐng)求方法,本程序只定義了GET邏輯??
  • ????enum?CHECK_STATE?{?CHECK_STATE_REQUESTLINE?=?0,?CHECK_STATE_HEADER,?CHECK_STATE_CONTENT?};//HTTP請(qǐng)求狀態(tài):正在解析請(qǐng)求行、正在解析頭部、解析中??
  • ????enum?HTTP_CODE?{?NO_REQUEST,?GET_REQUEST,?BAD_REQUEST,?NO_RESOURCE,?FORBIDDEN_REQUEST,?FILE_REQUEST,?INTERNAL_ERROR,?CLOSED_CONNECTION?};//HTTP請(qǐng)求結(jié)果:未完整的請(qǐng)求(客戶端仍需要提交請(qǐng)求)、完整的請(qǐng)求、錯(cuò)誤請(qǐng)求...只用了前三個(gè)??
  • ????enum?LINE_STATUS?{?LINE_OK?=?0,?LINE_BAD,?LINE_OPEN?};//HTTP每行解析狀態(tài):改行解析完畢、錯(cuò)誤的行、正在解析行??
  • ??
  • public:??
  • ????http_conn(){}??
  • ????~http_conn(){}??
  • ??
  • public:??
  • ????void?init(?int?sockfd,?const?sockaddr_in&?addr?);//初始化新的HTTP連接??
  • ????void?close_conn(?bool?real_close?=?true?);??
  • ????void?process();//處理客戶請(qǐng)求??
  • ????bool?read();//讀取客戶發(fā)送來(lái)的數(shù)據(jù)(HTTP請(qǐng)求)??
  • ????bool?write();//將請(qǐng)求結(jié)果返回給客戶端??
  • ??
  • private:??
  • ????void?init();//重載init初始化連接,用于內(nèi)部調(diào)用??
  • ????HTTP_CODE?process_read();//解析HTTP請(qǐng)求,內(nèi)部調(diào)用parse_系列函數(shù)??
  • ????bool?process_write(?HTTP_CODE?ret?);//填充HTTP應(yīng)答,通常是將客戶請(qǐng)求的資源頁(yè)發(fā)送給客戶,內(nèi)部調(diào)用add_系列函數(shù)??
  • ??
  • ????HTTP_CODE?parse_request_line(?char*?text?);//解析HTTP請(qǐng)求的請(qǐng)求行??
  • ????HTTP_CODE?parse_headers(?char*?text?);//解析HTTP頭部數(shù)據(jù)??
  • ????HTTP_CODE?parse_content(?char*?text?);//獲取解析結(jié)果??
  • ????HTTP_CODE?do_request();//處理HTTP連接:內(nèi)部調(diào)用process_read(),process_write()??
  • ????char*?get_line()?{?return?m_read_buf?+?m_start_line;?}//獲取HTTP請(qǐng)求數(shù)據(jù)中的一行數(shù)據(jù)??
  • ????LINE_STATUS?parse_line();//解析行內(nèi)部調(diào)用parse_request_line和parse_headers??
  • ????//下面的函數(shù)被process_write填充HTTP應(yīng)答?????
  • ????void?unmap();//解除內(nèi)存映射,這里內(nèi)存映射是指將客戶請(qǐng)求的資源頁(yè)文件映射通過(guò)mmap映射到內(nèi)存??
  • ????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;//所有socket上的事件都注冊(cè)到一個(gè)epoll事件表中所以用static??
  • ????static?int?m_user_count;//用戶數(shù)量??
  • ??
  • private:??
  • ????int?m_sockfd;//HTTP連接對(duì)應(yīng)的客戶在服務(wù)端的描述符m_sockfd和地址m_address??
  • ????sockaddr_in?m_address;??
  • ??
  • ????char?m_read_buf[?READ_BUFFER_SIZE?];//讀緩沖區(qū),讀取HTTP請(qǐng)求??
  • ????int?m_read_idx;//已讀入的客戶數(shù)據(jù)最后一個(gè)字節(jié)的下一個(gè)位置,即未讀數(shù)據(jù)的第一個(gè)位置??
  • ????int?m_checked_idx;//當(dāng)前已經(jīng)解析的字節(jié)(HTTP請(qǐng)求需要逐個(gè)解析)??
  • ????int?m_start_line;//當(dāng)前解析行的起始位置??
  • ????char?m_write_buf[?WRITE_BUFFER_SIZE?];//寫緩沖區(qū)??
  • ????int?m_write_idx;//寫緩沖區(qū)待發(fā)送的數(shù)據(jù)??
  • ??
  • ????CHECK_STATE?m_check_state;//HTTP解析的狀態(tài):請(qǐng)求行解析、頭部解析??
  • ????METHOD?m_method;//HTTP請(qǐng)求方法,只實(shí)現(xiàn)了GET??
  • ??
  • ????char?m_real_file[?FILENAME_LEN?];//HTTP請(qǐng)求的資源頁(yè)對(duì)應(yīng)的文件名稱,和服務(wù)端的路徑拼接就形成了資源頁(yè)的路徑??
  • ????char*?m_url;//請(qǐng)求的具體資源頁(yè)名稱,如:www.baidu.com/index.html??
  • ????char*?m_version;//HTTP協(xié)議版本號(hào),一般是:HTTP/1.1??
  • ????char*?m_host;//主機(jī)名,客戶端要在HTTP請(qǐng)求中的目的主機(jī)名??
  • ????int?m_content_length;//HTTP消息體的長(zhǎng)度,簡(jiǎn)單的GET請(qǐng)求這個(gè)為空??
  • ????bool?m_linger;//HTTP請(qǐng)求是否保持連接??
  • ??
  • ????char*?m_file_address;//資源頁(yè)文件內(nèi)存映射后的地址??
  • ????struct?stat?m_file_stat;//資源頁(yè)文件的狀態(tài),stat文件結(jié)構(gòu)體??
  • ????struct?iovec?m_iv[2];//調(diào)用writev集中寫函數(shù)需要m_iv_count表示被寫內(nèi)存塊的數(shù)量,iovec結(jié)構(gòu)體存放了一段內(nèi)存的起始位置和長(zhǎng)度,??
  • ????int?m_iv_count;//m_iv_count是指iovec結(jié)構(gòu)體數(shù)組的長(zhǎng)度即多少個(gè)內(nèi)存塊??
  • };??
  • ??
  • #endif??

  • 任務(wù)T:http_conn.cpp

    [cpp] view plaincopy
  • #include?"http_conn.h"??
  • //定義了HTTP請(qǐng)求的返回狀態(tài)信息,類似大家都熟悉的404??
  • 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";//服務(wù)端資源頁(yè)的路徑,將其和HTTP請(qǐng)求中解析的m_url拼接形成資源頁(yè)的位置??
  • ??
  • int?setnonblocking(?int?fd?)//將fd設(shè)置為非阻塞??
  • {??
  • ????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?)//將fd添加到事件表epollfd??
  • {??
  • ????epoll_event?event;??
  • ????event.data.fd?=?fd;??
  • ????event.events?=?EPOLLIN?|?EPOLLET?|?EPOLLRDHUP;??
  • ????if(?one_shot?)//采用EPOLLONESHOT事件避免了同一事件被多次觸發(fā),因?yàn)橐粋€(gè)事件只被觸發(fā)一次且需要重置事件才能偵聽(tīng)下次是否發(fā)生??
  • ????{??
  • ????????event.events?|=?EPOLLONESHOT;??
  • ????}??
  • ????epoll_ctl(?epollfd,?EPOLL_CTL_ADD,?fd,?&event?);??
  • ????setnonblocking(?fd?);??
  • }??
  • ??
  • void?removefd(?int?epollfd,?int?fd?)//將fd從事件表epollfd中移除??
  • {??
  • ????epoll_ctl(?epollfd,?EPOLL_CTL_DEL,?fd,?0?);??
  • ????close(?fd?);??
  • }??
  • ??
  • void?modfd(?int?epollfd,?int?fd,?int?ev?)//EPOLLONESHOT需要重置事件后事件才能進(jìn)行下次偵聽(tīng)??
  • {??
  • ????epoll_event?event;??
  • ????event.data.fd?=?fd;??
  • ????event.events?=?ev?|?EPOLLET?|?EPOLLONESHOT?|?EPOLLRDHUP;??
  • ????epoll_ctl(?epollfd,?EPOLL_CTL_MOD,?fd,?&event?);//注意是EPOLL_CTL_MOD修改??
  • }??
  • ??
  • int?http_conn::m_user_count?=?0;//連接數(shù)??
  • int?http_conn::m_epollfd?=?-1;//事件表,注意是static故所有http_con類對(duì)象共享一個(gè)事件表??
  • ??
  • void?http_conn::close_conn(?bool?real_close?)//關(guān)閉連接,從事件表中移除描述符??
  • {??
  • ????if(?real_close?&&?(?m_sockfd?!=?-1?)?)//m_sockfd是該HTTP連接對(duì)應(yīng)的描述符??
  • ????{??
  • ????????//modfd(?m_epollfd,?m_sockfd,?EPOLLIN?);??
  • ????????removefd(?m_epollfd,?m_sockfd?);??
  • ????????m_sockfd?=?-1;??
  • ????????m_user_count--;??
  • ????}??
  • }??
  • ??
  • void?http_conn::init(?int?sockfd,?const?sockaddr_in&?addr?)//初始化連接??
  • {??
  • ????m_sockfd?=?sockfd;//sockfd是http連接對(duì)應(yīng)的描述符用于接收http請(qǐng)求和http回答??
  • ????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?)?);//獲取描述符狀態(tài),可以在調(diào)試時(shí)用??
  • ????addfd(?m_epollfd,?sockfd,?true?);??
  • ????m_user_count++;//多了一個(gè)http用戶??
  • ??
  • ????init();//調(diào)用重載函數(shù)??
  • }??
  • ??
  • void?http_conn::init()//重載init函數(shù)進(jìn)行些連接前的初始化操作??
  • {??
  • ????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()//解析HTTP數(shù)據(jù):將HTTP數(shù)據(jù)的每行數(shù)據(jù)提取出來(lái),每行以回車\r和換行符\n結(jié)束??
  • {??
  • ????char?temp;??
  • ????for?(?;?m_checked_idx?<?m_read_idx;?++m_checked_idx?)//m_checked_idx是當(dāng)前正在解析的字節(jié),m_read_idx是讀緩沖區(qū)中已有的數(shù)據(jù)(客戶端發(fā)送了多少HTTP請(qǐng)求數(shù)據(jù)到來(lái)),解析到m_read_idx號(hào)字節(jié)??
  • ????{??
  • ????????temp?=?m_read_buf[?m_checked_idx?];//當(dāng)前解析字節(jié)??
  • ????????if?(?temp?==?'\r'?)//若為回車符:??
  • ????????{??
  • ????????????if?(?(?m_checked_idx?+?1?)?==?m_read_idx?)//若為回車符:若此回車符是已讀取數(shù)據(jù)的最后一個(gè)則仍需要解析改行(即該行數(shù)據(jù)還沒(méi)有接收完整)??
  • ????????????{??
  • ????????????????return?LINE_OPEN;??
  • ????????????}??
  • ????????????else?if?(?m_read_buf[?m_checked_idx?+?1?]?==?'\n'?)//若回車符的下一個(gè)是換行符\r則表明該行解析完畢(回車+換行是HTTP請(qǐng)求每行固定結(jié)束規(guī)則)??
  • ????????????{??
  • ????????????????m_read_buf[?m_checked_idx++?]?=?'\0';//將該行數(shù)據(jù)送給緩沖區(qū)??
  • ????????????????m_read_buf[?m_checked_idx++?]?=?'\0';??
  • ????????????????return?LINE_OK;//返回狀態(tài):該行解析成功??
  • ????????????}??
  • ??
  • ????????????return?LINE_BAD;//否則解析失敗??
  • ????????}??
  • ????????else?if(?temp?==?'\n'?)//解析的字符是換行符則前一個(gè)必須是回車才解析成功??
  • ????????{??
  • ????????????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;//正在解析,還有HTTP請(qǐng)求數(shù)據(jù)沒(méi)有接收到....??
  • }??
  • ??
  • bool?http_conn::read()//讀取HTTP請(qǐng)求數(shù)據(jù)??
  • {??
  • ????if(?m_read_idx?>=?READ_BUFFER_SIZE?)//讀緩沖區(qū)已滿??
  • ????{??
  • ????????return?false;??
  • ????}??
  • ??
  • ????int?bytes_read?=?0;//記錄接收的字節(jié)數(shù)??
  • ????while(?true?)//循環(huán)讀取的原因是EPOLLONESHOT一個(gè)事件只觸發(fā)一次所以需要一次性讀取完全否則數(shù)據(jù)丟失??
  • ????{??
  • ????????bytes_read?=?recv(?m_sockfd,?m_read_buf?+?m_read_idx,?READ_BUFFER_SIZE?-?m_read_idx,?0?);//接收客戶端的HTTP請(qǐng)求??
  • ????????if?(?bytes_read?==?-1?)??
  • ????????{??
  • ????????????if(?errno?==?EAGAIN?||?errno?==?EWOULDBLOCK?)//非阻塞描述符這兩個(gè)errno不是網(wǎng)絡(luò)出錯(cuò)而是設(shè)備當(dāng)前不可得,在這里就是一次事件的數(shù)據(jù)讀取完畢??
  • ????????????{??
  • ????????????????break;??
  • ????????????}??
  • ????????????return?false;//否則recv出錯(cuò)??
  • ????????}??
  • ????????else?if?(?bytes_read?==?0?)//客戶端關(guān)閉了連接??
  • ????????{??
  • ????????????return?false;??
  • ????????}??
  • ??
  • ????????m_read_idx?+=?bytes_read;//更新讀緩沖區(qū)的已讀大小(用于解析行函數(shù))??
  • ????}??
  • ????return?true;??
  • }??
  • ??
  • http_conn::HTTP_CODE?http_conn::parse_request_line(?char*?text?)//解析HTTP的請(qǐng)求行部分??
  • {??
  • ????m_url?=?strpbrk(?text,?"?\t"?);//在text搜索\t的位置??
  • ????if?(?!?m_url?)??
  • ????{??
  • ????????return?BAD_REQUEST;??
  • ????}??
  • ????*m_url++?=?'\0';??
  • ??
  • ????char*?method?=?text;??
  • ????if?(?strcasecmp(?method,?"GET"?)?==?0?)//忽略大小寫比較mehtod和GET的大小返回值和strcmp定義相同??
  • ????{??
  • ????????m_method?=?GET;??
  • ????}??
  • ????else??
  • ????{??
  • ????????return?BAD_REQUEST;??
  • ????}??
  • ??
  • ????m_url?+=?strspn(?m_url,?"?\t"?);//strspn函數(shù)是在m_url找到第一個(gè)\t位置,拼接資源頁(yè)文件路徑??
  • ????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?)//HTTP版本??
  • ????{??
  • ????????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;//將HTTP解析狀態(tài)更新為解析頭部,那么HTTP解析進(jìn)入解析HTTP頭部。這是有限狀態(tài)機(jī)??
  • ????return?NO_REQUEST;??
  • }??
  • ??
  • http_conn::HTTP_CODE?http_conn::parse_headers(?char*?text?)//解析HTTP頭部??
  • {??
  • ????if(?text[?0?]?==?'\0'?)??
  • ????{??
  • ????????if?(?m_method?==?HEAD?)??
  • ????????{??
  • ????????????return?GET_REQUEST;//已經(jīng)獲取了一個(gè)完整的HTTP請(qǐng)求??
  • ????????}??
  • ??
  • ????????if?(?m_content_length?!=?0?)//若HTTP請(qǐng)求消息長(zhǎng)度不為空??
  • ????????{??
  • ????????????m_check_state?=?CHECK_STATE_CONTENT;//則解析頭部后還要解析消息體,所以HTTP解析狀態(tài)仍為正在解析中...GET請(qǐng)求不會(huì)出現(xiàn)這個(gè)...??
  • ????????????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?)//解析結(jié)果??
  • {??
  • ????if?(?m_read_idx?>=?(?m_content_length?+?m_checked_idx?)?)//若解析到緩沖區(qū)的最后位置則獲得一個(gè)一個(gè)完整的連接請(qǐng)求??
  • ????{??
  • ????????text[?m_content_length?]?=?'\0';??
  • ????????return?GET_REQUEST;??
  • ????}??
  • ??
  • ????return?NO_REQUEST;//請(qǐng)求不完整??
  • }??
  • ??
  • http_conn::HTTP_CODE?http_conn::process_read()//完整的HTTP解析??
  • {??
  • ????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?)?){//滿足條件:正在進(jìn)行HTTP解析、讀取一個(gè)完整行??
  • ????????text?=?get_line();//從讀緩沖區(qū)(HTTP請(qǐng)求數(shù)據(jù))獲取一行數(shù)據(jù)??
  • ????????m_start_line?=?m_checked_idx;//行的起始位置等于正在每行解析的第一個(gè)字節(jié)??
  • ????????printf(?"got?1?http?line:?%s\n",?text?);??
  • ??
  • ????????switch?(?m_check_state?)//HTTP解析狀態(tài)跳轉(zhuǎn)??
  • ????????{??
  • ????????????case?CHECK_STATE_REQUESTLINE://正在分析請(qǐng)求行??
  • ????????????{??
  • ????????????????ret?=?parse_request_line(?text?);//分析請(qǐng)求行??
  • ????????????????if?(?ret?==?BAD_REQUEST?)??
  • ????????????????{??
  • ????????????????????return?BAD_REQUEST;??
  • ????????????????}??
  • ????????????????break;??
  • ????????????}??
  • ????????????case?CHECK_STATE_HEADER://正在分析請(qǐng)求頭部??
  • ????????????{??
  • ????????????????ret?=?parse_headers(?text?);//分析頭部??
  • ????????????????if?(?ret?==?BAD_REQUEST?)??
  • ????????????????{??
  • ????????????????????return?BAD_REQUEST;??
  • ????????????????}??
  • ????????????????else?if?(?ret?==?GET_REQUEST?)??
  • ????????????????{??
  • ????????????????????return?do_request();//當(dāng)獲得一個(gè)完整的連接請(qǐng)求則調(diào)用do_request分析處理資源頁(yè)文件??
  • ????????????????}??
  • ????????????????break;??
  • ????????????}??
  • ????????????case?CHECK_STATE_CONTENT://HTTP解析狀態(tài)仍為正在解析...沒(méi)有辦法只好繼續(xù)解析唄....解析消息體??
  • ????????????{??
  • ????????????????ret?=?parse_content(?text?);??
  • ????????????????if?(?ret?==?GET_REQUEST?)??
  • ????????????????{??
  • ????????????????????return?do_request();??
  • ????????????????}??
  • ????????????????line_status?=?LINE_OPEN;??
  • ????????????????break;??
  • ????????????}??
  • ????????????default:??
  • ????????????{??
  • ????????????????return?INTERNAL_ERROR;//內(nèi)部錯(cuò)誤??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??
  • ????return?NO_REQUEST;??
  • }??
  • ??
  • http_conn::HTTP_CODE?http_conn::do_request()//用于獲取資源頁(yè)文件的狀態(tài)??
  • {??
  • ????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;//若資源頁(yè)不存在則HTTP解析結(jié)果為:沒(méi)有資源...萬(wàn)惡的404??
  • ????}??
  • ??
  • ????if?(?!?(?m_file_stat.st_mode?&?S_IROTH?)?)??
  • ????{??
  • ????????return?FORBIDDEN_REQUEST;//資源沒(méi)有權(quán)限獲取??
  • ????}??
  • ??
  • ????if?(?S_ISDIR(?m_file_stat.st_mode?)?)??
  • ????{??
  • ????????return?BAD_REQUEST;//請(qǐng)求有錯(cuò)??
  • ????}??
  • ??
  • ????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?);//將資源頁(yè)文件映射到內(nèi)存??
  • ????close(?fd?);??
  • ????return?FILE_REQUEST;//資源頁(yè)請(qǐng)求成功??
  • }??
  • ??
  • void?http_conn::unmap()//解除資源頁(yè)文件映射的內(nèi)存??
  • {??
  • ????if(?m_file_address?)??
  • ????{??
  • ????????munmap(?m_file_address,?m_file_stat.st_size?);//解除映射??
  • ????????m_file_address?=?0;??
  • ????}??
  • }??
  • ??
  • bool?http_conn::write()//將資源頁(yè)文件發(fā)送給客戶端??
  • {??
  • ????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?);//EPOLLONESHOT事件每次需要重置事件??
  • ????????init();??
  • ????????return?true;??
  • ????}??
  • ??
  • ????while(?1?)//??
  • ????{??
  • ????????temp?=?writev(?m_sockfd,?m_iv,?m_iv_count?);//集中寫,m_sockfd是http連接對(duì)應(yīng)的描述符,m_iv是iovec結(jié)構(gòu)體數(shù)組表示內(nèi)存塊地址,m_iv_count是數(shù)組的長(zhǎng)度即多少個(gè)內(nèi)存塊將一次集中寫到m_sockfd??
  • ????????if?(?temp?<=?-1?)//集中寫失敗??
  • ????????{??
  • ????????????if(?errno?==?EAGAIN?)??
  • ????????????{??
  • ????????????????modfd(?m_epollfd,?m_sockfd,?EPOLLOUT?);//重置EPOLLONESHOT事件,注冊(cè)可寫事件表示若m_sockfd沒(méi)有寫失敗則關(guān)閉連接??
  • ????????????????return?true;??
  • ????????????}??
  • ????????????unmap();//解除內(nèi)存映射??
  • ????????????return?false;??
  • ????????}??
  • ??
  • ????????bytes_to_send?-=?temp;//待發(fā)送數(shù)據(jù)??
  • ????????bytes_have_send?+=?temp;//已發(fā)送數(shù)據(jù)??
  • ????????if?(?bytes_to_send?<=?bytes_have_send?)??
  • ????????{??
  • ????????????unmap();//該資源頁(yè)已經(jīng)發(fā)送完畢該解除映射??
  • ????????????if(?m_linger?)//若要保持該http連接??
  • ????????????{??
  • ????????????????init();//初始化http連接??
  • ????????????????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,?...?)//HTTP應(yīng)答主要是將應(yīng)答數(shù)據(jù)添加到寫緩沖區(qū)m_write_buf??
  • {??
  • ????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?);//將fromat內(nèi)容輸出到m_write_buf??
  • ????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?)//填充HTTP應(yīng)答??
  • {??
  • ????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://資源頁(yè)文件可用??
  • ????????{??
  • ????????????add_status_line(?200,?ok_200_title?);??
  • ????????????if?(?m_file_stat.st_size?!=?0?)??
  • ????????????{??
  • ????????????????add_headers(?m_file_stat.st_size?);//m_file_stat資源頁(yè)文件狀態(tài)??
  • ????????????????m_iv[?0?].iov_base?=?m_write_buf;//寫緩沖區(qū)??
  • ????????????????m_iv[?0?].iov_len?=?m_write_idx;//長(zhǎng)度??
  • ????????????????m_iv[?1?].iov_base?=?m_file_address;//資源頁(yè)數(shù)據(jù)內(nèi)存映射后在m_file_address地址??
  • ????????????????m_iv[?1?].iov_len?=?m_file_stat.st_size;//文件長(zhǎng)度就是該塊內(nèi)存長(zhǎng)度??
  • ????????????????m_iv_count?=?2;??
  • ????????????????return?true;??
  • ????????????}??
  • ????????????else??
  • ????????????{??
  • ????????????????const?char*?ok_string?=?"<html><body></body></html>";//請(qǐng)求頁(yè)位空白??
  • ????????????????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請(qǐng)求??
  • {??
  • ????HTTP_CODE?read_ret?=?process_read();//讀取HTTP請(qǐng)求數(shù)據(jù)??
  • ????if?(?read_ret?==?NO_REQUEST?)??
  • ????{??
  • ????????modfd(?m_epollfd,?m_sockfd,?EPOLLIN?);??
  • ????????return;??
  • ????}??
  • ??
  • ????bool?write_ret?=?process_write(?read_ret?);//發(fā)送資源頁(yè)給客戶端??
  • ????if?(?!?write_ret?)??
  • ????{??
  • ????????close_conn();??
  • ????}??
  • ??
  • ????modfd(?m_epollfd,?m_sockfd,?EPOLLOUT?);??
  • }??

  • 服務(wù)端程序:接收HTTP請(qǐng)求并交給線程池處理這些請(qǐng)求

    [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"//該頭文件封裝了信號(hào)量和互斥量??
  • #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?);//采用http_conn.h的addfd函數(shù)??
  • extern?int?removefd(?int?epollfd,?int?fd?);//這也是http_conn.h中的函數(shù)??
  • ??
  • void?addsig(?int?sig,?void(?handler?)(int),?bool?restart?=?true?)//安裝信號(hào),用于統(tǒng)一事件源(將信號(hào)和IO事件統(tǒng)一監(jiān)聽(tīng))??
  • {??
  • ????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?>;//創(chuàng)建線程池??
  • ????}??
  • ????catch(?...?)??
  • ????{??
  • ????????return?1;??
  • ????}??
  • ??
  • ????http_conn*?users?=?new?http_conn[?MAX_FD?];//創(chuàng)建超大的用戶HTTP連接任務(wù)數(shù)組,給定一個(gè)http連接的描述符作為下標(biāo)即可索引到這個(gè)任務(wù),空間換時(shí)間??
  • ????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?);//創(chuàng)建事件表??
  • ????assert(?epollfd?!=?-1?);??
  • ????addfd(?epollfd,?listenfd,?false?);//將監(jiān)聽(tīng)端口添加到事件表,false表示不注冊(cè)EPOLLONESHOT事件,注意不能將監(jiān)聽(tīng)端口注冊(cè)為EPOLLONESHOT事件因?yàn)樵撌录看伟l(fā)生只觸發(fā)一次,而accept每次只能連接一個(gè)客戶,那么多個(gè)客戶連接請(qǐng)求到來(lái),則必然丟失客戶連接請(qǐng)求??
  • ????http_conn::m_epollfd?=?epollfd;??
  • ??
  • ????while(?true?)??
  • ????{??
  • ????????int?number?=?epoll_wait(?epollfd,?events,?MAX_EVENT_NUMBER,?-1?);//無(wú)限期等待sockfd上的注冊(cè)事件??
  • ????????if?(?(?number?<?0?)?&&?(?errno?!=?EINTR?)?)//若epoll_wait不是因中斷EINTR是出錯(cuò)??
  • ????????{??
  • ????????????printf(?"epoll?failure\n"?);??
  • ????????????break;??
  • ????????}??
  • ??
  • ????????for?(?int?i?=?0;?i?<?number;?i++?)??
  • ????????{??
  • ????????????int?sockfd?=?events[i].data.fd;//獲取就緒事件描述符??
  • ????????????if(?sockfd?==?listenfd?)//監(jiān)聽(tīng)端口有可讀事件則表明有HTTP請(qǐng)求??
  • ????????????{??
  • ????????????????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?)//HTTP客戶數(shù)超過(guò)MAX_FD??
  • ????????????????{??
  • ????????????????????show_error(?connfd,?"Internal?server?busy"?);??
  • ????????????????????continue;??
  • ????????????????}??
  • ??????????????????
  • ????????????????users[connfd].init(?connfd,?client_address?);//利用connfd快速索引到http_conn任務(wù)類??
  • ????????????}??
  • ????????????else?if(?events[i].events?&?(?EPOLLRDHUP?|?EPOLLHUP?|?EPOLLERR?)?)??
  • ????????????{??
  • ????????????????users[sockfd].close_conn();??
  • ????????????}??
  • ????????????else?if(?events[i].events?&?EPOLLIN?)//數(shù)據(jù)可讀:??
  • ????????????{??
  • ????????????????if(?users[sockfd].read()?)??
  • ????????????????{??
  • ????????????????????pool->append(?users?+?sockfd?);??
  • ????????????????}??
  • ????????????????else??
  • ????????????????{??
  • ????????????????????users[sockfd].close_conn();??
  • ????????????????}??
  • ????????????}??
  • ????????????else?if(?events[i].events?&?EPOLLOUT?)//數(shù)據(jù)可寫,哪里注冊(cè)了可寫EPOLLOUT事件?http_conn工作任務(wù)類中write函數(shù)將那個(gè)http連接的描述符m_sockfd注冊(cè)了可寫事件??
  • ????????????{??
  • ????????????????if(?!users[sockfd].write()?)//若該http_conn任務(wù)對(duì)應(yīng)的http連接寫失敗了則關(guān)閉該http連接??
  • ????????????????{??
  • ????????????????????users[sockfd].close_conn();??
  • ????????????????}??
  • ????????????}??
  • ????????????else??
  • ????????????{}??
  • ????????}??
  • ????}??
  • ??
  • ????close(?epollfd?);??
  • ????close(?listenfd?);//這里要提醒的是listenfd由創(chuàng)建它的函數(shù)關(guān)閉,誰(shuí)污染誰(shuí)治理的原則??
  • ????delete?[]?users;??
  • ????delete?pool;??
  • ????return?0;??
  • }??

  • 互斥量和信號(hào)量的簡(jiǎn)單封裝: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??

  • 壓力測(cè)試程序:通常有IO復(fù)用、多線程、多進(jìn)程實(shí)現(xiàn)壓力測(cè)試,其中IO復(fù)用施壓程度最高其它的要切換CPU

    本程序是客戶端通過(guò)命令行參數(shù)指定num個(gè)客戶連接,并向服務(wù)端發(fā)送HTTP請(qǐng)求,服務(wù)端HTTP應(yīng)答,客戶端輸出是請(qǐ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>??
  • //向服務(wù)器發(fā)送HTTP請(qǐng)求內(nèi)容??
  • static?const?char*?request?=?"GET?http://localhost/index.html?HTTP/1.1\r\nConnection:?keep-alive\r\n\r\nxxxxxxxxxxxx";??
  • ??
  • int?setnonblocking(?int?fd?)//設(shè)置非阻塞描述符??
  • {??
  • ????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?)//向服務(wù)器寫函數(shù)即發(fā)送HTTP請(qǐng)求??
  • {??
  • ????int?bytes_write?=?0;??
  • ????printf(?"write?out?%d?bytes?to?socket?%d\n",?len,?sockfd?);??
  • ????while(?1?)?//循環(huán)寫直至寫完一次buffer也就是HTTP?requst??
  • ????{?????
  • ????????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?)//讀一次,接收服務(wù)器發(fā)送來(lái)的HTTP應(yīng)答??
  • {??
  • ????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?)//發(fā)起num個(gè)連接??
  • {??
  • ????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?);//初始注冊(cè)為可寫事件??
  • ????????}??
  • ????}??
  • }??
  • ??
  • void?close_conn(?int?epoll_fd,?int?sockfd?)//關(guān)閉連接??
  • {??
  • ????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?);//2000ms內(nèi)等待最多10000個(gè)事件??
  • ????????for?(?int?i?=?0;?i?<?fds;?i++?)??
  • ????????{?????
  • ????????????int?sockfd?=?events[i].data.fd;??
  • ????????????if?(?events[i].events?&?EPOLLIN?)//HTTP連接上可讀事件即服務(wù)端發(fā)送給客戶端HTTP回答報(bào)文??
  • ????????????{?????
  • ????????????????if?(?!?read_once(?sockfd,?buffer,?2048?)?)//讀取HTTP應(yīng)答??
  • ????????????????{??
  • ????????????????????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?)?)?)//向服務(wù)端發(fā)送HTTP請(qǐng)求??
  • ????????????????{??
  • ????????????????????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?);//這樣做的目的是客戶端發(fā)送HTTP請(qǐng)求和服務(wù)端HTTP回答交替出現(xiàn)??
  • ????????????}??
  • ????????????else?if(?events[i].events?&?EPOLLERR?)??
  • ????????????{??
  • ????????????????close_conn(?epoll_fd,?sockfd?);??
  • ????????????}??
  • ????????}??
  • ????}??
  • }??
  • 總結(jié)

    以上是生活随笔為你收集整理的基于半同步/半反应堆线程池实现的HTTP解析服务端程序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 男女啊啊啊视频 | 波多野结衣女同 | 无码精品人妻一区二区三区湄公河 | 久久爱一区二区 | av777777| 黄色一级大片在线免费看国产一 | 蜜桃av色偷偷av老熟女 | 91久久超碰| 一区二区三区午夜 | 国产三级在线 | 久草欧美 | av在线片 | 国产一区二区色 | 欧美日韩毛片 | 9l视频自拍蝌蚪9l视频 | 久久婷婷色综合 | wwwwyoujizzcom| aaa一区二区三区 | 制服诱惑一区二区 | 日韩三级国产精品 | 成人av毛片 | 中文字幕日韩精品亚洲一区小树林 | 亚洲免费大全 | 日韩av一区在线观看 | 日本在线视频www色 国产在线视频网址 | 欧美夜夜夜 | 玖玖在线精品 | 久久久在线免费观看 | 超碰在线中文字幕 | 韩国不卡av| 91网址在线 | 日韩国产三级 | 人人爱爱人人 | 欧美肉大捧一进一出免费视频 | 风韵多水的老熟妇 | 久操视频免费在线观看 | 色一区二区三区四区 | 777在线视频 | 日韩大片免费 | 亚洲午夜精品一区 | av一二三 | 色综合久久久久久 | 日日夜夜艹 | 美女av在线播放 | 色黄大色黄女片免费中国 | 香蕉视频毛片 | 久久福利国产 | 亚洲91网站 | 97在线精品 | 丰满大肥婆肥奶大屁股 | 黄色大片网站在线观看 | 一区二区三区在线观看免费 | 日韩综合网站 | 麻豆黄色片| 一区二区三区四区久久 | 麻豆视频网站入口 | 久久系列 | 亚洲精品国产精品乱码不卡 | 天天曰天天射 | 午夜精品免费 | 欧美做爰性生交视频 | 乖疼润滑双性初h | 青娱乐最新视频 | 国产哺乳奶水91在线播放 | 国产精品swag | 日韩熟女一区二区 | 亚洲国产精品一区 | 欧美18一20男同69gay | 免费在线色视频 | aa黄色片 | 西西44rtwww国产精品 | 欧美精品电影一区二区 | 亚洲综合激情小说 | 日韩精品视频一区二区在线观看 | 亚洲人成电影在线 | 亚洲视频999 | 日韩久久一区 | 青娱乐在线免费视频 | 日韩中文字幕亚洲精品欧美 | 色多多污| 久久久艹 | 成人资源站| 在线免费观看麻豆 | 亚洲一区欧美一区 | 制服丝袜av在线播放 | 日韩av色图 | 日日摸夜夜 | 亚洲精品乱码久久久久久蜜桃不卡 | 九色国产| 亚洲乱码国产乱码精品天美传媒 | 亚洲欧美日韩系列 | 亚洲男女一区二区三区 | 精品九九在线 | 国产最新自拍视频 | 操操操插插插 | 九九久久精品视频 | 黄色三级免费网站 | 男男成人高潮片免费网站 | 精品少妇人妻一区二区黑料社区 |