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 ...
随机推荐
- IOS-百度地图API用点生成线路、导航、自定义标注 2013年11月更新
IOS百度地图API开发自定义气泡,点击气泡自动生成路线,以及拖拽IOS百度地图开发POISearch搜索附近停车场,附近加油站IOS百度地图视角跳到用户当前位置IOS百度地图开发实时路况IOS开发百 ...
- 工作流引擎activiti入门
眼下最新的版本号是5.17 1.下载:activiti-5.17.0.zip http://activiti.org/download.html 2.解压activiti-5.17.0.zip 3.打 ...
- 【spring cloud】一个ms微服务想要给注册中心eureka发现,需要满足这些条件,微服务不能被eureka注册中心发现的解决方案
在spring cloud中,一个新的微服务想要被注册中心发现,需要注意几个地方: 1.pom.xml文件依赖中需要有这个依赖 spring boot 2.x 需要这个依赖 <dependenc ...
- 用 Redis 实现分布式锁(分析)
文章转自:http://www.jeffkit.info/2011/07/1000/ Redis有一系列的命令,特点是以NX结尾,NX是Not eXists的缩写,如SETNX命令就应该理解为:SET ...
- matlab 图像常用函数
Canny function [ canny ] = canny( rgb ) temp=rgb2gray(rgb); canny=edge(temp,'canny'); end 灰度 temp=rg ...
- ExtJS ComboBox 录入智能提示
ExtJS ComboBox非常复杂,有很多的属性:其中有的属性是针对某一种特定的方案而设计的,不是所有情况下都有效.我想下拉选择能支持录入,并且录入时能智能提示,弄了半天可以了,但是只能是mode= ...
- 高性能CSS
避免使用@import 有两种方式加载样式文件,一种是link元素,另一种是CSS 2.1加入@import.而在外部的CSS文件中使用@import会使得页面在加载时增加额外的延迟.虽然规则允许在样 ...
- MySQL服务器安装完之后如何调节性能
原文作者: Peter Zaitsev原文来源: http://www.mysqlperformanceblog.com/2006/09/29/what-to-tune-in-mysql-server ...
- Hive配置与操作实践
Hive配置与操作实践 @(Hadoop) 安装hive hive的安装十分简单,只需要在一台服务器上部署即可. 上传hive安装包,解压缩,将其配入环境变量. mysql的设置 在要作为元数据库的m ...
- System.Windows.Forms
File: winforms\Managed\System\WinForms\DataGridView.cs Project: ndp\fx\src\System.Windows.Forms.cspr ...