首页 > 代码库 > 基于nginx_http_push_module模块让nginx变成Comet Server

基于nginx_http_push_module模块让nginx变成Comet Server

基于http协议搭建各种服务已经成为一种大势,但是基于http协议的客户端和服务器端的交互却是个难题,没办法http协议天生如此,其是无状态的协议,每次交互建立链接,结束断开.

客户端和服务器交互很简单,请求描述功能接口的url即可,带上参数.可是服务器要和客户端交互,那就有些困难.下面是几种方法.

1.客户端轮询,最差的一种,客服端和服务器端都在白忙活,浪费资源.

2.long-polling,长轮询,客户端和服务器端保持一个链接,客户端主动发起一个链接,没有如果服务器端没有数据发送給客户端,链接保持,直到服务器有数据发送給客户端,客户端接收数据,断开链接.客户端再链接服务器,进入下一个周期.这就是服务器push.

nginx是一款优秀的web服务器和反响代理服务器,其在同时并发连接方面性能优异,那么其作为hold住大量客服端服务器再合适不过.

nginx_http_push_module(NHPM)模块可以将你的nginx打造成一个Comet Server.

NHPM提供两个antor,一个是publisher,消息发布者,一个是subscriber,客户端,联系他们的关系是channel,频道.

技术分享

这是一个大致的简图.

安装NHPM,在编译nginx是使用add-module将下载的模块添加进来,官网为https://pushmodule.slact.net.

这是我的编译参数:

 ./configure --with-http_gzip_static_module --with-http_ssl_module --with-http_stub_status_module --with-http_gunzip_module --with-http_realip_module --add-module=/home/zhou/software/nginx-1.7.6/module/nginx_http_push_module-0.73
编译的过程中可以会报错,是编译的报警参数严格就会当成错误,主要是一个变量没有初始化.将ngx_http_push_module.c的673行的buf_use_count赋值为NULL就可以了.然后make && sudo make install,默认安装到/usr/local/nginx.

安装成功之后,我们就需要配置我们的NHPM.阅读模块的README文件,其有关于配置参数的详细的说明,protocl.txt有详细的关于其实现的long-polling的说明.test目录提供了相关的配置例子.

下面是我的配置:

在server 80下配置了两个location

 location /pub {
            set $push_channel_id $arg_id;
            push_publisher;#角色 
            push_store_messages on; #打开消息队列
            push_max_message_buffer_length 20;#长度
            push_message_timeout 2h;#过期时长
        }

        location /sub {
             push_subscriber;#角色
             push_subscriber_concurrency broadcast;#广播的形式
             set $push_channel_id $arg_id;
             default_type  text/plain;
        }

写了个python,脚本最为客户端,写了个页面作为消息发布

import httplib

def subscriber(**opts):
        while True:
                con = httplib.HTTPConnection("localhost")
                con.request('GET', '/sub?id=' + opts['channel'], headers = opts['head'])
                re = con.getresponse();
                print re.read()      print re.getheader('Last-Modified')                     opts['head']['If-Modified-Since'] = re.getheader('Last-Modified')

subscriber(channel = 'miss', head = {'If-Modified-Since':''})

接收到一条消息后,重新建立连接是将得到的回复中的
LAST_MODIFIED值传给发送头中的<pre><code class="language-ruby" data-lang="ruby"><span class="s1">If-Modified-Since'</span></code>

其是根据这个来判断消息新旧的时序.现在运行这个脚本其会报No channel id provided,我们的channel是miss,这是因为我们没有向这个频道push,其在第一次push会创建.push的页面

<form action="http://localhost/pub?id=miss" method="post">
Message:
<input name="a" type="text"/>
<input name="" type="submit" value=http://www.mamicode.com/"Push" />>
很简单.我们要firefox打开它

技术分享

然后按下push,提交,得到如下的返回

技术分享

说明miss channel创建成功,现在没有一个subscriber,现在运行python脚本

技术分享

其答应了一条消息,然后就阻塞等待回复,这是我们在push一条数据.

技术分享

其又接收一条然后阻塞等待,这样实现了服务器发送数据給客户端.基于这个我们可以搭建如下简单的一个控制系统.

技术分享


NHPM负责控制消息的发布,Logic server完成相应的业务功能.



基于nginx_http_push_module模块让nginx变成Comet Server