WebSocket实时消息推送

一、消息推送的实现原理与方式

1.1 实时性较强的场景

  • 在线聊天
  • 监控报警
  • 视频弹幕

1.2 基于HTTP的实时消息方案

  • AJAX轮询(polling) //客户端不断发送请求到服务器
  • 长轮询(longplling) //一般30s超时
  • 异步streaing
  • iframe数据量

全双工
数据发送和接收可以同时进行

HTTP协议是不具备全双工的。

1.3 软件运行原理

WebSocket协议是一种全双工的通讯方式,并且支持跨域

《WebSocket实时消息推送》

二、消息推送服务器的搭建

我们利用nginxnginx-push-stream-module模块来实现消息推送服务。

2.1 环境搭建

首先需要下载模块源码,这里在git上直接克隆

git clone http://github.com/wandenberg/nginx-push-stream-module.git

将欲增加的模块路径定义为一个变量(此步骤非必要步骤,且定义的变量只能当前会话可用,只是为了后续操作方便)

NGINX_PUSH_STREAM_MODULE_PATH=$PWD/nginx-push-stream-module

以下是nginx已经安装过的情况下增加模块,因为以前nginx安装在/usr/local/nginx目录下,所以下面的操作都是以此目录为路径进行操作,如果安装到其他目录有些命令需要做对应的更改。

先查看原有nginx的配置参数并拷贝出来备用

/usr/local/nginx/sbin/nginx -V

《WebSocket实时消息推送》

解压相同版本nginx源码包(以前安装时的源码包),如果已经删除了课重新下载,版本相同即可(这里以1.12.1版本为例)
nginx官网

wget  http://nginx.org/download/nginx-1.12.1.tar.gz

tar zxvf nginx-1.12.2.tar.gz
进入nginx的目录

cd nginx-1.12.1

进行配置(其中***是前面记录的nginx原始的配置,也就是刚才拷贝出来配置,这个务必加上)

./configure --add-module=$NGINX_PUSH_STREAM_MODULE_PATH ***

编译:

make

不要执行make install避免覆盖,备份原来的nginx可执行文件

备份:

mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx_bak

将编译好的nginx复制到原始nginxsbin目录

cp objs/nginx /usr/local/nginx/sbin/

到此为止已经安装完毕,可以再执行/usr/local/nginx/sbin/nginx -V查看一下nginx的模块情况。

《WebSocket实时消息推送》

2.3 nginx配置

安装后需要在nginx的配置文件nginx.conf或者其他包含的配置文件中做如下配置:
1. 在http段加入:

#最大共享内存
push_stream_shared_memory_size                100m;
#频道最大长度
push_stream_max_channel_id_length             200;
#每个频道缓存的最大消息数量
push_stream_max_messages_stored_per_channel   20;
#消息生命周期(分钟)
push_stream_message_ttl                       5m;

《WebSocket实时消息推送》

2. 添加一个虚拟主机(server)配置如下:

server {
    listen 8080;
    server_name     127.0.0.1;
    location /pub {
        push_stream_publisher admin;
        push_stream_channels_path $arg_id;
        push_stream_store_messages on;
    }
    location ~ /sub/(.*) {
        push_stream_subscriber;
        push_stream_channels_path $1;
        push_stream_last_received_message_time      "$arg_time";
        push_stream_last_received_message_tag       "$arg_tag";
        push_stream_header_template "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\r\n<meta http-equiv=\"Cache-Control\" content=\"no-store\">\r\n<meta http-equiv=\"Cache-Control\" content=\"no-cache\">\r\n<meta http-equiv=\"Pragma\" content=\"no-cache\">\r\n<meta http-equiv=\"Expires\" content=\"Thu, 1 Jan 1970 00:00:00 GMT\">\r\n<script type=\"text/javascript\">\r\nwindow.onError = null;\r\ntry{ document.domain = (window.location.hostname.match(/^(\d{1,3}\.){3}\d{1,3}$/)) ? window.location.hostname : window.location.hostname.split('.').slice(-1 * Math.max(window.location.hostname.split('.').length - 1, (window.location.hostname.match(/(\w{4,}\.\w{2}|\.\w{3,})$/) ? 2 : 3))).join('.');}catch(e){}\r\nparent.PushStream.register(this);\r\n</script>\r\n</head>\r\n<body>";
            push_stream_message_template "<script>p(~id~,'~channel~','~text~');</script>";
        push_stream_footer_template "</body></html>";
        default_type "text/html; charset=utf-8";
        push_stream_ping_message_interval 10s;
    }
    location ~ /ev/(.*) {
        push_stream_subscriber eventsource;
        push_stream_channels_path $1;
        push_stream_last_received_message_time      "$arg_time";
        push_stream_last_received_message_tag       "$arg_tag";
        push_stream_message_template "{\"id\":~id~,\"channel\":\"~channel~\",\"text\":\"~text~\",\"tag\":\"~tag~\",\"time\":\"~time~\"}";
        push_stream_ping_message_interval 10s;
    }
    location ~ /ws/(.*) {
        push_stream_subscriber websocket;
        push_stream_channels_path $1;
        push_stream_last_received_message_time      "$arg_time";
        push_stream_last_received_message_tag       "$arg_tag";
        push_stream_message_template "{\"id\":~id~,\"channel\":\"~channel~\",\"text\":\"~text~\",\"tag\":\"~tag~\",\"time\":\"~time~\"}";
        push_stream_ping_message_interval 10s;
    }
    location ~ /lp/(.*) {
        push_stream_subscriber long-polling;
        push_stream_channels_path $1;
        push_stream_last_received_message_time      "$arg_time";
        push_stream_last_received_message_tag       "$arg_tag";
        push_stream_message_template "{\"id\":~id~,\"channel\":\"~channel~\",\"text\":\"~text~\",\"tag\":\"~tag~\",\"time\":\"~time~\"}";
        push_stream_longpolling_connection_ttl 30s;
    }

  }

3. 然后重新载入nginx的配置

检查配置文件是否有语法错误:

/usr/local/nginx/sbin/nginx -t

出现以下提示表示正确:

nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

重新载入:

/usr/local/nginx/sbin/nginx -s reload 或 nginx -s reload 

查看端口:netstat -tnl

《WebSocket实时消息推送》

2.3 测试订阅/发布

Linux命令下使用curl做如下测试(其中ch1代表频道)

#发布信息:
curl http://localhost:8080/pub?id=ch1 -d "发布消息测试"
#订阅信息:
curl http://localhost:8080/lp/ch1

《WebSocket实时消息推送》

参考学习视频:消息推送服务器构建实时聊天室视频教程

    原文作者:唐成勇
    原文地址: https://segmentfault.com/a/1190000013391750
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞