EMQ ---websocket
简介
近年来随着 Web 前端的快速发展,浏览器新特性层出不穷,越来越多的应用可以在浏览器端或通过浏览器渲染引擎实现,Web 应用的即时通信方式 WebSocket 得到了广泛的应用。
WebSocket 是一种在单个 TCP 连接上进行全双工通讯的协议。WebSocket 通信协议于2011年被 IETF 定为标准 RFC 6455,并由 RFC 7936 补充规范。WebSocket API 也被 W3C 定为标准。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。 —— 摘自 维基百科 WebSocket
MQTT 协议第 6 章详细约定了 MQTT 在 WebSocket [RFC6455] 连接上传输需要满足的条件
我们可以使用emq自带的Dashboard插件,进行websocket调试,打开谷歌浏览器输入网址,其中192.168.83.128是emq所在的IP地址:
http://192.168.83.128:18083/#/websocket
用户名:admin,密码:public
WebSocket URI:ws(s)://192.168.83.128:8083/mqtt
TCP URI:tcp://192.168.83.128:1883
一、测试实践
测试环境:使用MQTT 3.1.1版本协议,Wireshark 2.4.1版本,使用wireshark抓包分析(如果是虚拟机,要抓VMnet8虚拟网卡)。
clientid:861694030142473
username:libaineu2004
password:12345678
cleanSession:true
keepalive:60s
1、测试方案1,使用普通的tcp连接,TCP URI:tcp://192.168.83.128:1883,wireshark过滤条件tcp.port == 1883。
(1)、MQTT Connect Command
鼠标点击wireshark的Frame页面,右键菜单,复制,选中树的所有可见项目
MQ Telemetry Transport Protocol, Connect Command
Header Flags: 0x10 (Connect Command)
Msg Len: 51
Protocol Name Length: 4
Protocol Name: MQTT
Version: 4
Connect Flags: 0xc2
Keep Alive: 60
Client ID Length: 15
Client ID: 861694030142473
User Name Length: 12
User Name: libaineu2004
Password Length: 8
Password: 12345678
右键菜单,复制,字节为HEX + ASCII转储
0000 10 33 00 04 4d 51 54 54 04 c2 00 3c 00 0f 38 36 .3..MQTT...<..86
0010 31 36 39 34 30 33 30 31 34 32 34 37 33 00 0c 6c 1694030142473..l
0020 69 62 61 69 6e 65 75 32 30 30 34 00 08 31 32 33 ibaineu2004..123
0030 34 35 36 37 38 45678
(2)、MQTT Connect Ack
MQ Telemetry Transport Protocol, Connect Ack
Header Flags: 0x20 (Connect Ack)
Msg Len: 2
Acknowledge Flags: 0x00
Return Code: Connection Accepted (0)
0000 20 02 00 00 ...
2、测试方案2,使用websocket连接,WebSocket URI:ws(s)://192.168.83.128:8083/mqtt,wireshark过滤条件tcp.port == 8083。我们可以观察到mqtt连接的过程,websocket协议,完整的数据被拆分了好几帧传输。每一帧报文,都有WebSocket和Data字段。我们仅仅需要关注Data字段即可。我们发现,把所有Data字段组合拼接起来,就是和测试方案1完全相同的数据。MQTT Connect Command和Ack都完全相同。说明了即使使用了Websocket方式来传输,仍然遵循mqtt协议。
从本质上来讲,Websocket也是基于 TCP 协议的,同时借用了HTTP的协议来完成一部分握手。
主要解决 HTTP 协议中一个 request 对应一个 response 的尴尬。(http server 不能主动发送消息给 http client) 。通过 HTTP 完成 websocket 的握手过程,接着按照 websocket 协议进行通讯。
websocket 也有他自己的数据帧格式: http://blog.csdn.net/u010487568/article/details/20569027
(1)MQTT Connect Command
0000 10 .
0000 33 3
0000 00 04 ..
0000 4d 51 54 54 MQTT
0000 04 .
0000 c2 .
0000 00 3c .<
0000 00 0f ..
0000 38 36 31 36 39 34 30 33 30 31 34 32 34 37 33 861694030142473
0000 00 0c ..
0000 6c 69 62 61 69 6e 65 75 32 30 30 34 libaineu2004
0000 00 08 ..
0000 31 32 33 34 35 36 37 38 12345678
(2)MQTT Connect Ack
Data (4 bytes)
Data: 20020000
[Length: 4]
0000 20 02 00 00 ...
二、以下是源码分析,先来看emq v1.1.3版本的源码:
1、-module(emqttd_app).
%%--------------------------------------------------------------------
%% Start Servers
%%--------------------------------------------------------------------
start_servers(Sup) ->
Servers = [
{"emqttd wsclient supervisor", {supervisor, emqttd_ws_client_sup}},
%% Start http listener
start_listener({http, ListenOn, Opts}) ->
mochiweb:start_http(http, ListenOn, Opts, {emqttd_http, handle_request, []});
打开8083端口,开启http服务器。Websocket也是基于 TCP 协议的,同时借用了HTTP的协议来完成一部分握手。
2、-module(emqttd_http).
%%--------------------------------------------------------------------
%% MQTT Over WebSocket
%%--------------------------------------------------------------------
handle_request('GET', "/mqtt", Req) ->
lager:info("WebSocket Connection from: ~s", [Req:get(peer)]),
Upgrade = Req:get_header_value("Upgrade"),
Proto = Req:get_header_value("Sec-WebSocket-Protocol"),
case {is_websocket(Upgrade), Proto} of
{true, "mqtt" ++ _Vsn} ->
emqttd_ws:handle_request(Req);
{false, _} ->
lager:error("Not WebSocket: Upgrade = ~s", [Upgrade]),
Req:respond({400, [], <<"Bad Request">>});
{_, Proto} ->
lager:error("WebSocket with error Protocol: ~s", [Proto]),
Req:respond({400, [], <<"Bad WebSocket Protocol">>})
end;
websocket的入口函数。重点关注emqttd_ws:handle_request(Req);
3、-module(emqttd_ws).
ws_loop(Data, State = #wsocket_state{peer = Peer, client_pid = ClientPid,
parser_fun = ParserFun}, ReplyChannel) ->
?WSLOG(debug, Peer, "RECV ~p", [Data]),
case catch ParserFun(iolist_to_binary(Data)) of
{more, NewParser} ->
State#wsocket_state{parser_fun = NewParser};
{ok, Packet, Rest} ->
gen_server:cast(ClientPid, {received, Packet}),
ws_loop(Rest, reset_parser(State), ReplyChannel);
{error, Error} ->
?WSLOG(error, Peer, "Frame error: ~p", [Error]),
exit({shutdown, Error});
{'EXIT', Reason} ->
?WSLOG(error, Peer, "Frame error: ~p", [Reason]),
?WSLOG(error, Peer, "Error data: ~p", [Data]),
exit({shutdown, parser_error})
end.
gen_server:cast(ClientPid, {received, Packet}), 接收来自客户端的消息。
4、-module(emqttd_ws_client).
handle_cast({received, Packet}, State = #wsclient_state{peer = Peer, proto_state = ProtoState}) ->
case emqttd_protocol:received(Packet, ProtoState) of
{ok, ProtoState1} ->
noreply(State#wsclient_state{proto_state = ProtoState1});
{error, Error} ->
?WSLOG(error, Peer, "Protocol error - ~p", [Error]),
shutdown(Error, State);
{error, Error, ProtoState1} ->
shutdown(Error, State#wsclient_state{proto_state = ProtoState1});
{stop, Reason, ProtoState1} ->
stop(Reason, State#wsclient_state{proto_state = ProtoState1})
end;
emqttd_protocol:received(Packet, ProtoState)。接收处理消息。
5、-module(emqttd_protocol).
process(Packet = ?CONNECT_PACKET(Var), State0) ->
#mqtt_packet_connect{proto_ver = ProtoVer,
proto_name = ProtoName,
username = Username,
password = Password,
clean_sess = CleanSess,
keep_alive = KeepAlive,
client_id = ClientId} = Var,
State1 = State0#proto_state{proto_ver = ProtoVer,
proto_name = ProtoName,
username = Username,
client_id = ClientId,
clean_sess = CleanSess,
keepalive = KeepAlive,
will_msg = willmsg(Var),
connected_at = os:timestamp()},
trace(recv, Packet, State1),
{ReturnCode1, SessPresent, State3} =
case validate_connect(Var, State1) of
validate_connect(Var, State1),校验clientid,username和password的有效性
EMQ ---websocket的更多相关文章
- EMQ、Websocket、MQTT
mqtt.fx的安装和使用 https://blog.csdn.net/nicholaszao/article/details/79211965 EMO 使用说明 http://emqtt.com/d ...
- 使用EMQ搭建MQTT服务器
前言寒假的时候开始搭建mqtt服务器,一开始使用的是RabbitMQ,基于Erlang语言.但是RabbitMQ的本职工作是AMQP,MQTT只是他的一个插件功能,似乎有些大材小用,很多MQTT的功能 ...
- 使用 WebSocket 客户端连接 MQTT 服务器
简介 近年来随着 Web 前端的快速发展,浏览器新特性层出不穷,越来越多的应用可以在浏览器端或通过浏览器渲染引擎实现,Web 应用的即时通信方式 WebSocket 得到了广泛的应用. WebSock ...
- 物联网架构成长之路(6)-EMQ权限控制
1. 前言 EMQTT属于一个比较小众的开源软件,很多资料不全,很麻烦,很多功能都是靠猜测,还有就是看官方提供的那几个插件,了解. 2. 说明 上一小节的插件 emq_plugin_wunaozai ...
- EMQ ---问题集
1)emqttd 使用 SSL遇到的问题:服务器直接布了一份emqttd ,然后什么都没管,端口默认的ws 8083,wss8084,mqtt 1883,mqtt(ssl) 8883. 结果跑起来之后 ...
- centos7(vmware install) 安装EMQ注意事项 ---控制台远程访问
若想远端访问控制台,需打开对于端口 TCP 服务端口占用 EMQ 2.0 消息服务器默认占用的 TCP 端口包括: 1883 MQTT 协议端口 8883 MQTT/SSL 端口 8083 MQTT/ ...
- emq(centos 7) 使用
配置文件: EMQ 配置文件: /etc/emqttd/emq.conf 插件配置文件: /etc/emqttd/plugins/*.conf 日志文件 日志文件目录: /var/log/emqttd ...
- [emqttd] (EMQ)
[emqttd] (EMQ)是采用Erlang语言开发,全面支持MQTT V3.1.1协议,支持集群和大规模连接的开源MQTT消息服务器. [emqttd]致力于发布一个基于Erlang/OTP语言平 ...
- 转:EMQ(emqttd) 2.x 安装和使用(物联网传输控制协议的Broker)
支持下国产开源. MQTT物联网传输控制协议:<MQTT-3.1.1-CN.pdf> 下载:emqttd-centos64-v2.0-rc.2-20161019.zip 安装: $ unz ...
随机推荐
- SDRAM interface slashes pin count
Many designs need deep buffering but don't require ultrahigh-memory bandwidth. Examples include imag ...
- Linux命令-添加新硬盘,分区及挂载[转]
http://www.cnblogs.com/qiyebao/p/4484370.html 转自:http://blog.chinaunix.net/uid-25829053-id-3067619.h ...
- mysql -h localhost和mysql -h 127.0.0.1的区别
今天早上同事说MySQL root账号登录不上了.我试了一下 #mysql -u root -p 提示”Access denied for user ‘root’@’localhost’ (using ...
- OOW 2015 MYSQL
https://events.rainfocus.com/oow15/catalog/oracle.jsp?search.event=openworldEvent&search.mysql=d ...
- 关于心理的二十五种倾向(查理·芒格)-5
17)压力影响倾向人在遇到突然的压力.比方遭遇危急时.会导致人体内部的肾上腺素激增,推动更快,更极端的反应. A)人在压力的情况下会使得社会认同倾向更加强大.B)人在压力的情况下会使得避免怀疑倾向更加 ...
- hdu 2176 取石子游戏
http://acm.hdu.edu.cn/showproblem.php?pid=2176 提示:尼姆博弈,异或 #include <iostream> #include <cst ...
- FastStone Capture 8.4 注册码
原文:https://blog.csdn.net/mlin_123/article/details/51557079 name:bluman serial/序列号/注册码:VPISCJULXUFGDD ...
- linux开放关闭防火墙端口
原文:http://blog.csdn.net/fengspg/article/details/21337617 1) 重启后生效 开启: chkconfig iptables on 关闭: chkc ...
- git hub的GUI软件配置与使用
1. 安装两个软件 1. git的命令行程序--git for windows:http://git-scm.com/download/win 2. git的GUI程序--tortoisegit:ht ...
- Android 交叉编译程序提示(not found)
原因是缺少库文件, 解决办法:arm-linux-readelf -a helloword | grep NEEDED 拷贝so文件到安卓下 或者 arm-linux-gcc hello.c -o h ...