Reactor模型的幾個重要組件:Event事件、Reactor反應堆、Demultiplex事件分發(fā)器、Evanthandler事件處理器
接上節(jié)課,上節(jié)課中,我們使用了epoll實現(xiàn)了同時監(jiān)聽多個文件描述符,是對IO的管理,也提到了reactor是對事件的管理,那具體來說是怎樣的呢?reactor是事件驅動模型,也就是EPOLLIN/EPOLLOUT,同時,我們應該維護一種結構,對于每個fd,都應該有這樣一種記錄該fd相關的結構。
對于其中的fd小塊,存儲的都是該fd相關的內容,比如該fd的讀寫緩存區(qū),對應的回調函數(shù)等等:
結構可以用代碼這樣表示:
typedef int (*ZVCALLBACK)(int fd, int events, void *arg);
typedef struct zv_connect_s {
int fd;
ZVCALLBACK cb;
char rbuffer[BUFFER_LENGTH];
int rc;
char wbuffer[BUFFER_LENGTH];
int wc;
int count;
} zv_connect_t;
typedef struct zv_connblock_s {
zv_connect_t *block;
struct zv_connblock_s *next;
} zv_connblock_t;
typedef struct zv_reactor_s {
int epfd;
zv_connblock_t *blockheader;
} zv_reactor_t;
這樣,對于listenfd
,我們設置它的accept_cb
,對于clientfd
,設置它的recv_cb
或send_cb
。
具體來說,我們以fd
為下標,唯一標識該fd
相關的塊,對于listenfd
,通過listenfd
設置相關的accept_cb
回調:
int accept_cb(int fd, int events, void *arg)
{
...
int clientfd = accept(fd, (struct sockaddr*)&clientaddr, &len);
if (clientfd < 0) {
printf("accept errno: %d\n", errno);
return -1;
}
zv_reactor_t *reactor = (zv_reactor_t*)arg;
zv_connect_t *conn = &reactor->blockheader->block[clientfd];
conn->fd = clientfd;
conn->cb = recv_cb;
...
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = clientfd;
epoll_ctl(reactor->epfd, EPOLL_CTL_ADD, clientfd, &ev);
}
reactor->blockheader->block[listenfd].fd = listenfd;
reactor->blockheader->block[listenfd].cb = accpet_cb;
接收和發(fā)送回調同理。
并且,當我們使用上節(jié)課提到的epoll
將IO管理起來后,整體代碼就會顯得非常簡潔,因為當有EPOLLIN/EPOLLOUT
事件來臨時,我們只需要根據(jù)fd
找到對應的回調函數(shù)執(zhí)行即可:
while (1) {//mainloop, event driver
int nready = epoll_wait(reactor.epfd, events, 1024, -1);
if (nready < 0) continue;
int i = 0;
for (i = 0; i < nready; i++) {
int connfd = events[i].data.fd;
zv_connect_t *conn = &reactor.blockheader->block[connfd];
if (events[i].events & EPOLLIN) {
conn->cb(connfd, events[i].events, &reactor);
}
if (events[i].events & EPOLLOUT) {
conn->cb(connfd, events[i].events, &reactor);
}
}
}
這便是reactor
對事件管理的方式,這樣一來,我們可以將網(wǎng)絡與業(yè)務分離,業(yè)務人員只需要在回調函數(shù)中讀寫相應的buffer
即可,無需關注網(wǎng)絡細節(jié)!
再往后,為了提高處理能力,我們可以將clientfd
相關的讀寫操作放到子線程去做,而主線程只負責appect
等等,這就涉及到不同的網(wǎng)絡編程模型,之后再談。
1.并發(fā):服務器同時承載的客戶端數(shù)量
2.qps:每一秒處理的請求數(shù)量
3.最大時延:
4.新建(建鏈):每秒建立的鏈接數(shù)
5.吞吐量
ulimit -a
查看每個進程可以打開的文件描述符個數(shù)
可以看到這里open files最大是1024,有兩種方式可以修改:
1.命令:ulimit -n 1048576
(這是臨時修改)
2.修改文件/etc/security/limits.conf
(注意中間是tab鍵)
gaoyuelong@ubuntu:~/23040voice/06$ sudo sysctl -p
gaoyuelong@ubuntu:~/23040voice/06$ sudo modprobe nf_conntrack
(目前虛擬機網(wǎng)絡沒有調試好,導致網(wǎng)絡通信有些問題,后續(xù)再寫百萬并發(fā)部分,先挖個坑)文章來源:http://www.zghlxwxcb.cn/news/detail-422084.html
文章參考與<零聲教育>的C/C++linux服務期高級架構系統(tǒng)教程學習:https://ke.qq.com/course/417774?flowToken=1020253文章來源地址http://www.zghlxwxcb.cn/news/detail-422084.html
到了這里,關于2.2.1服務器百萬并發(fā)實現(xiàn)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!