通信服务模型


13.1 前言

高性能服务器方面的讨论,主要面对TCP。

13.2 使用多进程

优点:好理解/简单
缺点:每个客户端对应一个进程,资源消耗大
适合:少量客户端
应用:早期的apache服务器

13.3 使用多线程

优点:好理解/简单
缺点:每个客户端对应一个线程,资源消耗大
适合:少量客户端
应用:优化过的apache服务器

13.4 使用多路IO复用技术

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

13.4.1 select

优点:跨平台,在少量文件描述符集合中,效率高
缺点:只能监听最多1024文件描述符

13.4.2 epoll

优点:支持大规模网络服务
缺点:只支持linux

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  #include  #include  #include      // 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