一、概述 
    发布:发布者将MSG post到某一特定通道上,channel将信息缓存 
在说明发布流程之前有必要说明下channel和msg的数据结构。 
二、数据结构 
2.1 MSG 
    发布时,模块先将消息转化为ngx_http_push_stream_msg_t的数据结构进行存储。

  1. // message queue
  2. typedef struct {
  3. ngx_queue_t                     queue; // this MUST be first
  4. time_t                          expires;//消息过期时间
  5. time_t                          time;//消息创建时间
  6. ngx_flag_t                      deleted;//是否已删除
  7. ngx_int_t                       id;
  8. ngx_str_t                      *raw;//纯文本
  9. ngx_int_t                       tag;
  10. ngx_str_t                      *event_id;//支持event source
  11. ngx_str_t                      *event_id_message;
  12. ngx_str_t                      *formatted_messages;//格式化后消息
  13. ngx_int_t                       workers_ref_count;//待发送该消息ngx worker计数
  14. } ngx_http_push_stream_msg_t;

@queue:每个channel会维护一个消息链表,每向channel发布一条消息,channel将其添加到自身的消息链表中。 
    @expires,@deleted:消息的过期时间,待介绍过订阅流程后,我会整理出一条消息的生产周期,到时会详细阐述该字段的意义。 
    @raw,@formatted_messages:该模块允许自定义三种消息模板——header模板:当收到订阅请求后发送模板消息;message模板:对消息体格式化;footer模板:断开连接时发送该模板。raw为消息原始内容,后者为应用message模板格式化后的信息

2.2 channel 
    channel作为发布订阅的中间载体,理解理解它的存储至关重要。

  1. typedef struct {
  2. ngx_rbtree_node_t                   node; // this MUST be first
  3. ngx_str_t                           id;
  4. ngx_uint_t                          last_message_id;
  5. time_t                              last_message_time;
  6. ngx_int_t                           last_message_tag;
  7. ngx_uint_t                          stored_messages;//# of messages
  8. ngx_uint_t                          subscribers;//# of subscribers
  9. ngx_http_push_stream_pid_queue_t    workers_with_subscribers;//处理该channel上订阅者的ngx worker进程链表
  10. ngx_http_push_stream_msg_t          message_queue;//消息链表
  11. time_t                              expires;//过期时间
  12. ngx_flag_t                          deleted;//是否已删除
  13. ngx_flag_t                          broadcast;//是否为广播通道
  14. ngx_http_push_stream_msg_t         *channel_deleted_message;//已删除消息链表
  15. } ngx_http_push_stream_channel_t;

2.3 worker msg

  1. // messages to worker processes
  2. typedef struct {
  3. ngx_queue_t                         queue;
  4. ngx_http_push_stream_msg_t         *msg; // ->shared memory
  5. ngx_pid_t                           pid;
  6. ngx_http_push_stream_channel_t     *channel; // ->shared memory
  7. ngx_http_push_stream_queue_elem_t  *subscribers_sentinel; // ->a worker's local pool
  8. } ngx_http_push_stream_worker_msg_t;

模块初始化时为每个ngx worker分配一片独立的工作区,工作区中维护一份消息链表。 
三、流程 
发布流程总的流程图如图所示: 
 
    对于删除channel和获取channel info的流程比较简单,不做阐述,具体说明下发布消息流程,流程图如图所示:

需要说明的是“向所有订阅者发送MSG”的过程:

  • 向每个有该channel订阅者的worker(workers_with_subscriber)的消息链表中插入一条消息
  • 向上述worker发送CHECK_MESSAGES指令,触发msg发送流程(ngx_http_push_stream_process_worker_message)

MSG发送(ngx_http_push_stream_process_worker_message):

  1. // now let's respond to some requests!
  2. //对于该channel上的所有订阅者
  3. while ((cur = (ngx_http_push_stream_queue_elem_t *) ngx_queue_next(&cur->queue)) != subscribers_sentinel) {
  4. ngx_http_push_stream_subscriber_t *subscriber = (ngx_http_push_stream_subscriber_t *) cur->value;
  5. //如果订阅者为longpolling模式
  6. if (subscriber->longpolling) {
  7. ngx_http_push_stream_queue_elem_t *prev = (ngx_http_push_stream_queue_elem_t *) ngx_queue_prev(&cur-
  8. >queue);
  9. //发送longpolling头(last Modified/Etag)
  10. ngx_http_push_stream_add_polling_headers(subscriber->request, msg->time, msg->tag, subscriber->reque
  11. st->pool);
  12. ngx_http_send_header(subscriber->request);
  13. //发送模块配置header模板
  14. ngx_http_push_stream_send_response_content_header(subscriber->request, ngx_http_get_module_loc_conf(
  15. subscriber->request, ngx_http_push_stream_module));
  16. //发送响应MSG
  17. ngx_http_push_stream_send_response_message(subscriber->request, channel, msg);
  18. //发送footer模板,last chunck("\0"CRLF CRLF)
  19. ngx_http_push_stream_send_response_finalize(subscriber->request);
  20. cur = prev;
  21. } else {//stream或polling模式
  22. if (ngx_http_push_stream_send_response_message(subscriber->request, channel, msg) == NGX_ERROR) {
  23. ngx_http_push_stream_queue_elem_t *prev = (ngx_http_push_stream_queue_elem_t *) ngx_queue_prev(&
  24. cur->queue);
  25. ngx_http_push_stream_send_response_finalize(subscriber->request);
  26. cur = prev;
  27. }
  28. }

说明: 
    可以看出push stream模块在发布过程中针对longpolling和stream两种模式的不同:

    • Longpolling模式下,每次发布消息时会发送longpolling头:last modified和etag,使得客户端下次请求时可据此判断服务端是否有更新的消息待发布。
    • longpolling模式下,订阅者每次请求都会在获得数据后断开重连,所以每次发布时都会发送header模板
    • ngx_http_push_stream_send_response_finalize同时会清理订阅者

nginx-push-stream模块源码学习(三)——发布的更多相关文章

  1. ngx-push-stream模块源码学习(四)——订阅

    一.概述 push stream模块允许三种模式的订阅者: longpolling:每收到服务端响应数据即断开连接然后迅速重连,连接耗时可以忽略 stream:与服务端保持长连接,持续不断的请求-&g ...

  2. nginx-push-stream模块源码学习(二)——模块初始化

    本文重点介绍push stream模块的构成,至于nginx如何启动.维护该模块不会详细阐述,以后有时间会做详细阐述. 一.模块定义 1.1.  模块配置 通用nginx模块的配置struct有三种, ...

  3. nginx健康检查模块源码分析

    nginx健康检查模块 本文所说的nginx健康检查模块是指nginx_upstream_check_module模块.nginx_upstream_check_module模块是Taobao定制的用 ...

  4. mybatis源码学习(三)-一级缓存二级缓存

    本文主要是个人学习mybatis缓存的学习笔记,主要有以下几个知识点 1.一级缓存配置信息 2.一级缓存源码学习笔记 3.二级缓存配置信息 4.二级缓存源码 5.一级缓存.二级缓存总结 1.一级缓存配 ...

  5. Vue源码学习三 ———— Vue构造函数包装

    Vue源码学习二 是对Vue的原型对象的包装,最后从Vue的出生文件导出了 Vue这个构造函数 来到 src/core/index.js 代码是: import Vue from './instanc ...

  6. 05.ElementUI源码学习:项目发布配置(github pages&npm package)

    0x00.前言 书接上文.项目第一个组件已经封装好,说明文档也已编写好.下面需要将说明文档发布到外网上,以此来展示和推广项目,使用 Github Pages功能实现.同时将组件发布之 npm 上,方便 ...

  7. ngx-push-stream模块源码学习(五)——内存清理

    1.定时器         采用nginx自身的定时器管理机制,具体细节待学习过nginx源码后加以补充 2.channel的生成周期 (0).初始(诞生)         发布.订阅均有可能产生ch ...

  8. spring源码学习(三)--spring循环引用源码学习

    在spring中,是支持单实例bean的循环引用(循环依赖)的,循环依赖,简单而言,就是A类中注入了B类,B类中注入了A类,首先贴出我的代码示例 @Component public class Add ...

  9. [spring源码学习]三、IOC源码——自定义配置文件读取

    一.环境准备 在文件读取的时候,第9步我们发现spring会根据标签的namespace来选择读取方式,联想spring里提供的各种标签,比如<aop:xxx>等应该会有不同的读取和解析方 ...

随机推荐

  1. JavaScript 奇技淫巧

    JavaScript 奇技淫巧 这里记录一下以前学习各种书籍和文章里边出现的JS的小技巧,分享给大家,也供自己查阅,同时感谢那些发现创造和分享这些技巧的前辈和大牛们. 1.遍历一个obj的属性到数组 ...

  2. 【百度地图API】如何进行地址解析与反地址解析?——模糊地址能搜索到精确地理信息!

    原文:[百度地图API]如何进行地址解析与反地址解析?--模糊地址能搜索到精确地理信息! 摘要: 什么是地址解析? 什么是反地址解析? 如何运用地址解析,和反地址解析? 可以同时运用地址解析,和反地址 ...

  3. Android锁定EditText内容和随机生成验证码

    昨天写了个小Demo,实现了随机生成验证码,和锁定EditText两个小功能,先看一下效果图: 锁定EditText在我们不须要用户编辑EditText内容的时候能够用到,实现还是非常easy的,一行 ...

  4. Windows系统下Redis的安装

    Redis是一个用的比较广泛的Key/Value的内存数据库,新浪微博.Github.StackOverflow 等大型应用中都用其作为缓存,Redis的官网为http://redis.io/. 最近 ...

  5. Oracle查字符集查版本号

    原文:Oracle查字符集查版本号 ---查字符集 select * from nls_database_parameters ---查版本 查看oracle的版本信息 (1)用客户端连接到数据库,执 ...

  6. SQL点滴3—一个简单的字符串分割函数

    原文:SQL点滴3-一个简单的字符串分割函数 偶然在电脑里看到以前保存的这个函数,是将一个单独字符串切分成一组字符串,这里分隔符是英文逗号“,”  遇到其他情况只要稍加修改就好了 CREATE FUN ...

  7. PDF解决方案(3)--PDF转SWF

    相关专题链接 PDF解决方案(1)--文件上传 PDF解决方案(2)--文件转PDF PDF解决方案(3)--PDF转SWF PDF解决方案(4)--在线浏览 前言:上一篇中介绍了上传的文件转PDF, ...

  8. Unity3D第三人称摄像机控制脚本

    好久没有敲Blog该.感谢您的留言.注意.私人信件和其他支持,但我似乎没有办法继续自己曾经写了一篇博客系列,因为我在网上找到有关unity3D太少的内容,U3D相关的文章!.. 第三人称视角 第三人称 ...

  9. 微软BI 之SSIS 系列 - 使用 Script Task 访问非 Windows 验证下的 SMTP 服务器发送邮件

    原文:微软BI 之SSIS 系列 - 使用 Script Task 访问非 Windows 验证下的 SMTP 服务器发送邮件 开篇介绍 大多数情况下我们的 SSIS 包都会配置在 SQL Agent ...

  10. 用HTML和javascript(JS)计算触屏手机手指滑动方向的演示

    移动终端的流行,程序员希望通过HTML+JS完成触屏动作的识别.下面给出具体实现的例子,供大家参考. 将下面的代码复制并保存,用手机访问,现在的手机浏览器一般都支持触屏,针对本演示来讲就是支持三个js ...