通訊服務模型

13.1 前言

高性能服務器方面的討論,主要面對TCP。linux

13.2 使用多進程

優勢:好理解/簡單
缺點:每一個客戶端對應一個進程,資源消耗大
適合:少許客戶端
應用:早期的apache服務器nginx

13.3 使用多線程

優勢:好理解/簡單
缺點:每一個客戶端對應一個線程,資源消耗大
適合:少許客戶端
應用:優化過的apache服務器git

13.4 使用多路IO複用技術

select(跨平臺) epoll(linux) pselect(x) poll(unix) kqueue(freeBSD) iocp(windows平臺)github

13.4.1 select

優勢:跨平臺,在少許文件描述符集合中,效率高
缺點:只能監聽最多1024文件描述符apache

13.4.2 epoll

優勢:支持大規模網絡服務
缺點:只支持linuxwindows

13.5 使用多路IO服用技術和線程池

特色:兩個線程,一個線程負責epoll_wait和accept,另一個線程負責接收和處理數據
優勢:支持大規模網絡服務,而且支持高併發。安全

13.6 使用多進程併發和多路IO複用技術

特色:多個進程同時監聽一個端口,若是外部有鏈接,多個進程經過內核實現的競爭機制,會有一個進程被喚醒。
優勢:效率很是高,nginx就是用這種方式實現的。服務器

13.7 使用現有通訊庫xs

13.8 使用現有通訊庫libevent

libevent libev ace ASIO xs網絡

瞭解:聽過這個詞,知道它是幹嗎的。
熟悉:把它代碼下載下來,編譯一下,寫一個C用libevent實現hello world
掌握:把libevent大部分的功能使用一遍
精通:使用libevent開發一個產品
大牛:你能找到libevent bug,甚至修改它的bug,並提交。多線程

  • libevent代碼下載

git clone https://github.com/libevent/libevent.git

  • 編譯

sudo apt-get install automake libtool
cd libevent
git checkout 2.0.23-stable-rc
./autogen.sh
./configure
make
sudo make install

安裝位置:
頭文件:/usr/local/include
庫文件:/usr/local/lib

openssl:加密安全
ffmpeg:音視頻處理
iconv:文本轉換

  • 編寫代碼

/*==================================
*   Copyright (C) 2016 All rights reserved.
*   
*   文件名稱:t01_libevent_hello_world.c
*   創 建 者:薛國良
*   建立日期:2016年11月02日
*   描    述:
*
================================================================*/
 
// /usr/local/include/event2/event.h
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <inttypes.h>
 
 
// socket has data in bufferevent
void readcb(struct bufferevent *bev, void *ctx)
{
    // read data from bufferevent...
    char buf[1024];
    // 從bufferevent中抽取數據
    int ret = bufferevent_read(bev, buf, sizeof(buf));
    if(ret < 0)
    {
        // error
        printf("error");
    }
 
    printf("%s\n", buf);
}
 
void eventcb(struct bufferevent *bev, short what, void *ctx)
{
    if((what & BEV_EVENT_EOF)  > 0)
    {
        printf("delete event\n");
        bufferevent_free(bev);
    }
}
 
// listener: 監聽器
// newfd:accept返回的socket
// addr:是對端的網絡地址
// socklen:對段的網絡地址結構體的長度
// ptr:額外參數
void listen_cb(struct evconnlistener *listener, evutil_socket_t newfd, struct sockaddr *addr, int socklen, void *ptr)
{
    struct event_base* evbase = evconnlistener_get_base(listener);
 
    /* add newfd to evbase */
    struct bufferevent* bev = bufferevent_socket_new(evbase, newfd, BEV_OPT_CLOSE_ON_FREE);
 
    /* setup read and event callback function */
    bufferevent_setcb(bev, readcb, NULL, eventcb, NULL);
 
    bufferevent_enable(bev, EV_READ|EV_WRITE);
}
 
int main()
{
    // 相似建立一個epoll或者select對象,默認下linux下應該epoll
    // event_base是一個事件的集合
    struct event_base* evbase = event_base_new();
    // 在libevent中,事件指一件即將要發生事情,evbase就是用來監控這些事件的
    // 發生(激活)的條件的
 
    struct sockaddr_in addr;
    addr.sin_port = htons(9988);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
 
    // 建立一個監聽器事件,該監聽器事件是初始化狀態
    struct evconnlistener* listener =
            evconnlistener_new_bind(evbase,
                                    listen_cb,
                                    NULL,
                                    LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
                                    250,
                                    (struct sockaddr*)&addr,
                                    sizeof(addr));
 
    // 進入未決狀態
    evconnlistener_enable(listener);
 
    // evbase監聽它的全部未決狀態的事件,進入死循環
    event_base_dispatch(evbase);
 
 
    // 釋放event_base
    event_base_free(evbase);
 
    return 0;
}
  • 編譯
    g++ t01_libevent_hello_world.c -levent_core

注意連接相應的庫

  • 運行

export LD_LIBRARY_PATH=/usr/local/lib
./a.out
相關文章
相關標籤/搜索