通信服务模型

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 <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

猜你喜欢

转载自www.cnblogs.com/w-x-me/p/6414543.html