聶永的博客

          記錄工作/學(xué)習(xí)的點(diǎn)點(diǎn)滴滴。

          MQTT協(xié)議筆記之mqtt.io項(xiàng)目Websocket協(xié)議支持

          前言

          MQTT協(xié)議專注于網(wǎng)絡(luò)、資源受限環(huán)境,建立之初不曾考慮WEB環(huán)境,倒也正常。雖然如此,但不代表它不適合HTML5環(huán)境。

          HTML5 Websocket是建立在TCP基礎(chǔ)上的雙通道通信,和TCP通信方式很類似,適用于WEB瀏覽器環(huán)境。雖然MQTT基因?qū)用孢x擇了TCP作為通信通道,但我們添加個(gè)編解碼方式,MQTT Over Websocket也可以的。

          這樣做的好處,MQTT的使用范疇被擴(kuò)展到HTML5、桌面端瀏覽器、移動(dòng)端WebApp、Hybrid等,多了一些想像空間。這樣看來(lái),無(wú)論是移動(dòng)端,還是WEB端,MQTT都會(huì)有自己的使用空間。

          瀏覽器支持

          話說(shuō),現(xiàn)代化瀏覽器都已經(jīng)支持Websocket,這里有一個(gè)所有瀏覽器支持列表:

          b84feb4f-ff91-45fc-9798-ce6f44e76af9

          更詳細(xì)列表,請(qǐng)直接訪問(wèn):http://caniuse.com/websockets

          毫無(wú)疑問(wèn),火狐和谷歌瀏覽器帶動(dòng)了現(xiàn)代瀏覽器的發(fā)展,對(duì)HTML5標(biāo)準(zhǔn)的支持也是如此。支持Websocket的瀏覽器單純從上面數(shù)字來(lái)講,73.88%的支持率。但實(shí)際上還得參考瀏覽器市場(chǎng)占有率:

          1[1]

          上圖數(shù)據(jù),來(lái)源于: 2014年4月份全球主流瀏覽器市場(chǎng)份額排行榜

          超過(guò)60%用戶機(jī)器上瀏覽器的支持Websocket,數(shù)據(jù)很可觀。

          移動(dòng)hybrid型應(yīng)用會(huì)很歡迎Websocket

          • 內(nèi)置瀏覽器支持HTML5,Javascript操作Websocket連接MQTT
          • 借助于原生TCP socket通道連接MQTT服務(wù)器,暴露JavaScript接口,間接使用

          不支持Websocket的桌面瀏覽器,可以考慮Flash socket來(lái)幫忙!

          針對(duì)不支持websocker的部分歷史瀏覽器,可以考慮一下Flash socket,雖然使用Flashsocket用以模擬Websocket就很容易理解,但條件如下: - 需要單獨(dú)占用一個(gè)端口專用于安全跨域訪問(wèn)策略 - 需要瀏覽器支持二進(jìn)制Blob 支持二進(jìn)制操作的瀏覽器現(xiàn)狀:

          xhr2

          來(lái)源于:http://caniuse.com/xhr2

          比較一下支持Websocket和XHR2的桌面瀏覽器,重疊率很高,使用Flash Socket用以模擬Websocket必要性不大,在類似于IE平臺(tái)上,不如直接使用Flash版本的

          https://github.com/yangboz/as3MQTT/tree/master/MQTTClient_AS3

          不支持Websocket瀏覽器怎么辦

          不是所有瀏覽器都支持Websocket,尤其是阻礙歷史發(fā)展的IE6/IE7/IE8/IE9。MQTT協(xié)議為二進(jìn)制協(xié)議壓根和HTTP純文本不兼容,尤其瀏覽器端JavaScript處理文本很合適,但二進(jìn)制就顯得笨手笨角,除非支持XHR2。

          1. 單獨(dú)使用Flash MQTT Client,這這方面見(jiàn)解不深,實(shí)踐很少,不便多說(shuō),您要是很了解,不妨告知一二。
          2. HTTP純文本方式進(jìn)行二進(jìn)制對(duì)接

          這部分后面專門(mén)會(huì)講到。

          服務(wù)器端支持

          現(xiàn)有一些解決方案可能是后面為MQTT Broker,前面是添加一層代理。比如:例如 mod_websocket ,對(duì)應(yīng)在線示范:http://test.mosquitto.org/ws.html

          表面上看著很解藕的,實(shí)際上模仿的還是傳統(tǒng)型的短連接反向代理架構(gòu):Nginx/Apache +Java/PHP/Python/Ruby。

          客戶端建立一條連接,服務(wù)器端需要使用到至少兩個(gè)文件句柄,中間多了一層路徑。優(yōu)雅的解決方案,可以向socket.io看起。一套服務(wù)端程序,同時(shí)提供若干種協(xié)議供終端選擇。其實(shí),一臺(tái)MQTT Broker中間件服務(wù)器,可以綁定多個(gè)端口,一個(gè)面向純TCP的1883端口,一個(gè)面向Websocket的80/8080端口,共享基礎(chǔ)邏輯,面向不同協(xié)議。

          Websocket協(xié)議適配

          服務(wù)器添加對(duì)Websocket支持,基本不用做多大改動(dòng)。對(duì)比Tcp的附加到單個(gè)Channel的處理器列表:

          public class TcpChannelInitializer extends ChannelInitializer<SocketChannel> {
          @Override
          public void initChannel(SocketChannel ch) throws Exception {
          ChannelPipeline pipeline = ch.pipeline();
          pipeline.addLast(
          new MqttMessageNewEncoder(),
          new MqttMessageNewDecoder(),
          new MqttMessageHandler());
          }
          }

          Websocket對(duì)應(yīng)單個(gè)Channel的處理器列表:

          import io.mqtt.handler.HttpRequestHandler;
          import io.mqtt.handler.MqttMessageHandler;
          import io.mqtt.handler.coder.MqttMessageWebSocketFrameDecoder;
          import io.mqtt.handler.coder.MqttMessageWebSocketFrameEncoder;
          import io.mqtt.handler.http.HttpJsonpTransport;
          import io.netty.channel.ChannelInitializer;
          import io.netty.channel.socket.SocketChannel;
          import io.netty.handler.codec.http.HttpObjectAggregator;
          import io.netty.handler.codec.http.HttpServerCodec;
          import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
          public class WebsocketChannelInitializer extends ChannelInitializer<SocketChannel> {
          private final static String websocketUri = "/websocket";
          private HttpRequestHandler httpRequestHandler = new HttpRequestHandler(
          websocketUri);
          static {
          HttpJsonpTransport httpJsonpTransport = new HttpJsonpTransport();
          HttpRequestHandler.registerTransport(httpJsonpTransport);
          }
          @Override
          public void initChannel(final SocketChannel ch) throws Exception {
          ch.pipeline().addLast(
          new HttpServerCodec(),
          new MqttMessageWebSocketFrameEncoder(),
          new HttpObjectAggregator(65536),
          httpRequestHandler,
          new WebSocketServerProtocolHandler(websocketUri),
          new MqttMessageWebSocketFrameDecoder(),
          new MqttMessageHandler());
          }
          }

          為了支持Websocket協(xié)議,僅僅額外增加了:

          @Sharable
          public class MqttMessageWebSocketFrameEncoder extends
          MessageToMessageEncoder<Message> {
          @Override
          protected void encode(ChannelHandlerContext ctx, Message msg,
          List<Object> out) throws Exception {
          if (msg == null)
          return;
          byte[] data = ((Message) msg).toBytes();
          out.add(new BinaryWebSocketFrame(Unpooled.wrappedBuffer(data)));
          }
          }
          public class MqttMessageWebSocketFrameDecoder extends
          MessageToMessageDecoder<BinaryWebSocketFrame> {
          private MqttMessageNewDecoder messageNewDecoder;
          public MqttMessageWebSocketFrameDecoder() {
          messageNewDecoder = new MqttMessageNewDecoder();
          }
          @Override
          protected void decode(ChannelHandlerContext ctx,
          BinaryWebSocketFrame wsFrame, List<Object> out) throws Exception {
          ByteBuf buf = wsFrame.content();
          this.messageNewDecoder.decode(ctx, buf, out);
          }
          }

          小結(jié)

          啰啰嗦嗦的講了一大通Websocket,總之對(duì)Websocket的支持還算容易。后面有時(shí)間寫(xiě)寫(xiě)如何使用HTTP協(xié)議達(dá)到MQTT OVER HTTP的效果。

          posted on 2014-05-26 19:14 nieyong 閱讀(11236) 評(píng)論(4)  編輯  收藏 所屬分類: MQTT

          評(píng)論

          # re: MQTT協(xié)議筆記之mqtt.io項(xiàng)目Websocket協(xié)議支持 2014-06-12 20:52 泡菜

          這些內(nèi)容對(duì)于我來(lái)說(shuō)真的是很深,一點(diǎn)頭緒都找不到啊!  回復(fù)  更多評(píng)論   

          # re: MQTT協(xié)議筆記之mqtt.io項(xiàng)目Websocket協(xié)議支持 2015-02-04 19:26 allankliu

          您好,我專注于硬件和物聯(lián)網(wǎng)。最近發(fā)現(xiàn)客戶此類要求越發(fā)急迫。

          許多嵌入式設(shè)備往往使用基礎(chǔ)的UDP/TCP通訊,客戶不愿意大規(guī)模改動(dòng),往往使用socketserver,比如Python socketserver/twisted以及相關(guān)小規(guī)模框架。但是這些框架往往缺乏商業(yè)化所必須的RBAC(權(quán)限管理)以及其他的必備組件。

          所以,我選用了web2py/Django作為WebAPP框架以實(shí)施WebServer。但是這樣,我的框架就變成了socket server,web server的兩個(gè)服務(wù)器。出于數(shù)據(jù)庫(kù)管理和安全考慮,從web server處引出API給socket server。

          感覺(jué)不優(yōu)雅,可能性能也會(huì)有問(wèn)題。你可能發(fā)現(xiàn)我喜歡使用Python,因?yàn)槲铱梢允褂猛徽Z(yǔ)言在嵌入式,服務(wù)器和客戶端。

          在調(diào)研過(guò)CoAP/MQTT等協(xié)議后,也發(fā)現(xiàn)了Python相關(guān)軟件包。但是看到您提到node.js/socket.io可以實(shí)施多種協(xié)議,是一個(gè)服務(wù)器實(shí)施多個(gè)端口監(jiān)聽(tīng)么?

          性能如何?此外,node.js/socket.io是否具備我們常見(jiàn)的服務(wù)器框架的必備功能,如路徑管理,RBAC。雖然使用jQuery時(shí)使用JS,但是我自認(rèn)為還不是很合格的JS開(kāi)發(fā)者。不知道使用node.js開(kāi)發(fā)服務(wù)器和Python/PHP開(kāi)發(fā)服務(wù)器難度上差別如何?  回復(fù)  更多評(píng)論   

          # re: MQTT協(xié)議筆記之mqtt.io項(xiàng)目Websocket協(xié)議支持 2015-02-05 14:51 nieyong

          @allankliu
          第一個(gè)問(wèn)題:一個(gè)服務(wù)器可以綁定多個(gè)端口,每一個(gè)端口各司其職即可,但需要應(yīng)用程序支持才行。但可能會(huì)造成功能耦合在了一起。
          第二個(gè)問(wèn)題:node.js我不熟,不好回答。

            回復(fù)  更多評(píng)論   

          # re: MQTT協(xié)議筆記之mqtt.io項(xiàng)目Websocket協(xié)議支持 2015-03-03 18:39 joeytian

          @allankliu
          很開(kāi)心看到你做的和我有很大的相似性。我目前還在嘗試用twisted來(lái)構(gòu)建網(wǎng)關(guān)服務(wù),主要是看中其異步和多協(xié)議支持。希望有機(jī)會(huì)交流(whatkao#gmail.com)  回復(fù)  更多評(píng)論   

          公告

          所有文章皆為原創(chuàng),若轉(zhuǎn)載請(qǐng)標(biāo)明出處,謝謝~

          新浪微博,歡迎關(guān)注:

          導(dǎo)航

          <2015年2月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          1234567

          統(tǒng)計(jì)

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個(gè)人收藏

          最新隨筆

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 东源县| 牟定县| 楚雄市| 梁平县| 无极县| 石门县| 甘谷县| 玉环县| 庆云县| 丰宁| 民和| 开原市| 景宁| 淅川县| 珠海市| 明溪县| 宁明县| 九江市| 台东市| 建宁县| 琼结县| 青阳县| 阳泉市| 涟源市| 科尔| 宿州市| 赤水市| 抚宁县| 阳曲县| 河池市| 南华县| 博乐市| 和平区| 南阳市| 竹山县| 孟津县| 绩溪县| SHOW| 民乐县| 墨竹工卡县| 大港区|