WebSocket实时消息推送
一、消息推送的实现原理与方式
1.1 实时性较强的场景
- 在线聊天
- 监控报警
- 视频弹幕
1.2 基于HTTP的实时消息方案
- AJAX轮询(polling) //客户端不断发送请求到服务器
- 长轮询(longplling) //一般
30s超时
- 异步streaing
- iframe数据量
全双工
:数据发送和接收可以同时进行
。
HTTP
协议是不具备全双工的。
1.3 软件运行原理
WebSocket协议是一种全双工的通讯方式,并且支持跨域
二、消息推送服务器的搭建
我们利用nginx
的nginx-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
解压相同版本
的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
复制到原始nginx
的sbin
目录
cp objs/nginx /usr/local/nginx/sbin/
到此为止已经安装完毕,可以再执行/usr/local/nginx/sbin/nginx -V
查看一下nginx
的模块情况。
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;
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
2.3 测试订阅/发布
在Linux
命令下使用curl
做如下测试(其中ch1
代表频道)
#发布信息: curl http://localhost:8080/pub?id=ch1 -d "发布消息测试" #订阅信息: curl http://localhost:8080/lp/ch1