錢(qián)鑫博
摘要:瀏覽器里的Web應(yīng)用和計(jì)算機(jī)的串口硬件進(jìn)行通信時(shí),需要針對(duì)不同的瀏覽器開(kāi)發(fā)不同的插件。采用HTML5內(nèi)置的WebSocket技術(shù)和QT開(kāi)發(fā)框架,通過(guò)WebSocket協(xié)議連接本地服務(wù),并通過(guò)本地服務(wù)綁定串口完成全雙工通信的方案,實(shí)現(xiàn)了跨瀏覽器的Web應(yīng)用與客戶端計(jì)算機(jī)串口通信的技術(shù),解決了為不同瀏覽器產(chǎn)品及版本開(kāi)發(fā)多種插件的問(wèn)題。經(jīng)過(guò)測(cè)試驗(yàn)證,達(dá)到了預(yù)期目標(biāo)。
關(guān)鍵詞:WebSocket;HTML5技術(shù);串口通信
中圖分類(lèi)號(hào):TP393文獻(xiàn)標(biāo)志碼:A文章編號(hào):1008-1739(2020)14-62-4
0引言
隨著互聯(lián)網(wǎng)的不斷發(fā)展,軟件趨向于網(wǎng)絡(luò)化,很多計(jì)算機(jī)上的應(yīng)用都做成了B/S架構(gòu),客戶端打開(kāi)瀏覽器就可以進(jìn)行訪問(wèn)。但是出于安全考慮,瀏覽器與操作系統(tǒng)進(jìn)行了隔離,瀏覽器不允許Web應(yīng)用直接訪問(wèn)客戶端的硬件,訪問(wèn)硬件就只能開(kāi)發(fā)插件。每種瀏覽器各自的API不兼容,Chrome瀏覽器用NPAPI來(lái)執(zhí)行一個(gè)本地程序獲取硬件,F(xiàn)irefox瀏覽器使用JS-Ctypes技術(shù)實(shí)現(xiàn)插件,然后調(diào)用C++代碼等來(lái)獲取本地硬件。瀏覽器迭代速度快、接口變化大,開(kāi)發(fā)插件時(shí)常遇到瀏覽器更新導(dǎo)致不能用,客戶體驗(yàn)非常差,而且每次都開(kāi)發(fā)對(duì)應(yīng)版本的插件費(fèi)時(shí)費(fèi)力。WebSocket是HTML5規(guī)范中的一個(gè)部分,借鑒了Socket思想,為了Web應(yīng)用程序和服務(wù)端全雙工通信而專(zhuān)門(mén)制定的一種新的應(yīng)用層協(xié)議。
1 WebSocket協(xié)議及幀結(jié)構(gòu)
WebSocket Protocol是HTML5中一種新的協(xié)議,實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工通信(full-duplex)。在這之前都是客戶端主動(dòng)請(qǐng)求服務(wù)端,請(qǐng)求一次應(yīng)答一次,很多時(shí)候?qū)崿F(xiàn)消息更新都是采用Ajax輪詢(xún),有延遲。有了WebSocket,雙方都可以主動(dòng)發(fā)給對(duì)端,實(shí)現(xiàn)真正的推送。WebSocket連接創(chuàng)建后,客戶端和服務(wù)端進(jìn)行數(shù)據(jù)交換時(shí),協(xié)議控制的數(shù)據(jù)包頭部較小。在不包含頭部的情況下,服務(wù)端到客戶端的包頭只有2~10 Byte(取決于數(shù)據(jù)包長(zhǎng)度),客戶端到服務(wù)端需要加上額外的4 Byte掩碼。而HTTP協(xié)議每次通信都需要攜帶完整的頭部[1]。RFC文檔給出的WebSocket協(xié)議格式,如圖1所示。
WebSocket協(xié)議報(bào)文是分幀傳輸,F(xiàn)IN:1 bit,代表是否是尾幀,如果為1,即為最后片段;RSV1,RSV2,RSV3:每個(gè)占1 bit,為擴(kuò)展保留的,若建立連接時(shí)使用了擴(kuò)展,那么這些位的含義應(yīng)自定義好;opcode:4 bit,定義負(fù)載數(shù)據(jù)(payload data)的類(lèi)型,如表1所示。
WebSocket有控制幀和數(shù)據(jù)幀2種,opcode最高位為1的都是控制幀,opcode最高位為0的都是數(shù)據(jù)幀。應(yīng)用級(jí)的數(shù)據(jù)傳輸幀,有文本幀和二進(jìn)制幀2種。協(xié)議級(jí)別的控制報(bào)文幀,有關(guān)閉幀、ping幀和pong幀3種。關(guān)閉幀:opcode 0x8,連接任一端想關(guān)閉WebSocket,就發(fā)一個(gè)關(guān)閉幀給對(duì)端,對(duì)端收到該幀,若之前沒(méi)有發(fā)過(guò)關(guān)閉幀,則必須回復(fù)一個(gè)關(guān)閉幀。ping幀和pong幀:用來(lái)心跳檢測(cè)和判斷對(duì)端是否還連接,連接建立后任一端都可以發(fā)送ping幀,收到ping的一端必須回復(fù)pong幀。
masked:1 bit,表示是否進(jìn)行掩碼處理,客戶端發(fā)送給服務(wù)端時(shí)為1,服務(wù)端發(fā)送給客戶端時(shí)為0。根據(jù)WebSocket的定義,客戶端發(fā)送數(shù)據(jù)需要進(jìn)行掩碼處理,接收數(shù)據(jù)無(wú)需反掩碼操作,服務(wù)端發(fā)送數(shù)據(jù)無(wú)需進(jìn)行掩碼處理,接收數(shù)據(jù)需要反掩碼操作。
payload length:7 bit,如果第2個(gè)字節(jié)的后面7 bit的十進(jìn)制值≤125,則直接用7 bit表示數(shù)據(jù)長(zhǎng)度;如果該值為126,表示數(shù)據(jù)長(zhǎng)度是126~65 535,這時(shí)要用3~4 Byte,每個(gè)字節(jié)8 bit,即16 bit來(lái)表示數(shù)據(jù)長(zhǎng)度;如果該值為127,則說(shuō)明數(shù)據(jù)長(zhǎng)度已經(jīng)>65 535,16 bit也已經(jīng)不足以表示數(shù)據(jù)長(zhǎng)度了,這時(shí)就用3~10 Byte,即64 bit來(lái)表示數(shù)據(jù)長(zhǎng)度。
masking key:當(dāng)masked為1的時(shí)候才存在,用于對(duì)需要的數(shù)據(jù)進(jìn)行解密。
payload data:負(fù)載數(shù)據(jù),就是要傳輸?shù)臄?shù)據(jù)。如果masked為1,該數(shù)據(jù)會(huì)被加密,要通過(guò)與masking key的值進(jìn)行異或運(yùn)算解密才能獲取真正的負(fù)載數(shù)據(jù)。負(fù)載數(shù)據(jù)=擴(kuò)展數(shù)據(jù)+應(yīng)用數(shù)據(jù)。擴(kuò)展數(shù)據(jù)包含在總負(fù)載數(shù)據(jù)長(zhǎng)度中,其實(shí)就是自定義一個(gè)協(xié)議,如果有擴(kuò)展數(shù)據(jù),擴(kuò)展數(shù)據(jù)就加在應(yīng)用數(shù)據(jù)前面,并且要協(xié)商好擴(kuò)展數(shù)據(jù)長(zhǎng)度如何計(jì)算。應(yīng)用數(shù)據(jù)是指擴(kuò)展數(shù)據(jù)之后幀的剩余部分。
2方案設(shè)計(jì)
2.1本地服務(wù)的結(jié)構(gòu)
本地服務(wù)主要實(shí)現(xiàn)WebSocket的服務(wù)端的串口控制和數(shù)據(jù)轉(zhuǎn)發(fā)。WebSocket服務(wù)端用來(lái)處理客戶端的瀏覽器Web應(yīng)用連接,串口控制用來(lái)操作計(jì)算機(jī)的串口設(shè)備,本地服務(wù)內(nèi)部轉(zhuǎn)接雙方的數(shù)據(jù)實(shí)現(xiàn)數(shù)據(jù)轉(zhuǎn)發(fā)傳輸[2],本地服務(wù)結(jié)構(gòu)如圖2所示。