微信端口及協(xié)議分析(java、C版)
有朋友公司需求如下,手機(jī)通過WIFI連接上網(wǎng),而老板要求,員工使用手機(jī)只能上微信,而不能上其他網(wǎng)頁和看在線視頻。上網(wǎng)搜索了微信使用協(xié)議和端口。
微信通過TCP方式來進(jìn)行通訊。
TCP通訊方式分析
通訊端口分析
遠(yuǎn)程通訊端口范圍: 80,443,80,443,8080。
HTTP方式分析
在特征分析中,發(fā)現(xiàn)微信會采用HTTP協(xié)議進(jìn)行通訊。
連接的主機(jī)(Host)(正則表達(dá)式)為:^short\.weixin\.qq\.com,^(mmsns|mmbiz)\.qpic\.cn。
TLS方式分析
在特征分析中,發(fā)現(xiàn)微信會采用TLS協(xié)議進(jìn)行通訊。
連接的TLS主機(jī)(正則表達(dá)式)為:^(wx|weixin|res\.wx)\.qq\.com。
這個(gè)協(xié)議只是用來檢測和屏蔽微信的,不能監(jiān)控聊天記錄內(nèi)容。
來源:笨驢技術(shù)
安桌手機(jī),可以用tcpdump進(jìn)行抓包。。分析!!
初步分析結(jié)果:
使用80、8080,登陸和交互。
使用:tcp 14000 端口 SCOTTY High-Speed Filetransferscotty-ft 發(fā)送語音文件
TCP: 5222 5223 5228 80 8080 443
來源:http://bbs.51cto.com/thread-1031608-1.html
微信、手機(jī)QQ網(wǎng)絡(luò)行為簡析
測試環(huán)境:
智能手機(jī)一部(打開wifi關(guān)閉gprs) —-> Linux wifi 熱點(diǎn) —-> 公網(wǎng)
分析手段:
在linux 上用tcpdump抓包,用wireshark分析抓到的數(shù)據(jù)
在linux上用iptables阻斷特定流量,模擬網(wǎng)絡(luò)故障,分別模擬了攔截udp 53/tcp 80/tcp 8080/tcp 14000/tcp全攔截等各種情況以及他們的組合
通過 adb shell在手機(jī)內(nèi)執(zhí)行netstat了解手機(jī)網(wǎng)絡(luò)鏈接情況
微信網(wǎng)絡(luò)行為:
程序啟動后,優(yōu)先嘗試DNS解析特定域名(support.weixin.qq.com,short.weixin.qq.com,long.weixin.qq.com,wx.qlogo.cn);
如果DNS查詢不可用,程序轉(zhuǎn)為使用hardcode的ip鏈接服務(wù);
如果dns可用,返回的ip為根據(jù)ISP智能解析的結(jié)果,程序使用返回的ip鏈接服務(wù);
程序僅在注冊階段使用https鏈接,內(nèi)容不詳;
程序使用tcp 80/8080鏈接服務(wù)器,其中80為http協(xié)議,8080為未知協(xié)議;
80/8080兩個(gè)端口同時(shí)或任何單獨(dú)一個(gè),均可提供服務(wù);
80端口為短鏈接,8080為長鏈接, 程序會優(yōu)先使用8080端口;
沒有使用udp傳輸數(shù)據(jù);
當(dāng)1-2次發(fā)送失敗時(shí),客戶端會彈出提示“當(dāng)前網(wǎng)絡(luò)狀況不好,是否提交反饋數(shù)據(jù)”,確認(rèn)后客戶端試圖通過web提交反饋數(shù)據(jù);
手機(jī)qq網(wǎng)絡(luò)行為:
僅列出跟微信不同之處
嘗試的域名不同: monitor.uu.qq.com,3gimg.qq.com, msfwifi.3g.qq.com, kiss.3g.qq.com;
除了80/8080外,還有tcp 14000,功能與8080相同;
程序會優(yōu)先嘗試80/8080,只有這兩個(gè)不可用時(shí),才嘗試14000;
其余同微信;
方案設(shè)想:只開放以上端口,其他上也是全部開放了,在上網(wǎng)出口處加上網(wǎng)行為管理設(shè)備或者軟件進(jìn)行控制,只允許以下正則的網(wǎng)址通行:
^short\.weixin\.qq\.com,^(mmsns|mmbiz)\.qpic\.cn
^(wx|weixin|res\.wx)\.qq\.com
以下是軟件實(shí)現(xiàn)方式
微信協(xié)議小結(jié)
http://www.dbjr.com.cn/article/96811.htm
發(fā)布的消息對應(yīng)一個(gè)ID(只要單個(gè)方向唯一即可,服務(wù)器端可能會根ID判斷重復(fù)接收),消息重傳機(jī)制確保有限次的重試,重試失敗給予用戶提示,發(fā)送成功會反饋確認(rèn),客戶端只有收到確認(rèn)信息才知道發(fā)送成功。發(fā)送消息可能不會產(chǎn)生新SyncKey。
基于版本號(SynKey)的狀態(tài)消息同步機(jī)制,增量、有序傳輸需求水到渠成。長連接通知/短連接獲取、確認(rèn)等,交互方式簡單,確保了消息可靠譜、準(zhǔn)確無誤到達(dá)。
客戶端/服務(wù)器端都會存儲消息ID處理記錄,避免被重復(fù)消費(fèi)客戶端獲取最新消息,但未確認(rèn),服務(wù)器端不會認(rèn)為該消息被消費(fèi)掉。下次客戶端會重新獲取,會查詢當(dāng)前消息是否被處理過。根據(jù)一些現(xiàn)象猜測。
總體上看,微信協(xié)議跨平臺(TCP或HTPP都可呈現(xiàn),處理方式可統(tǒng)一),通過“握手”同步,很可靠,無論哪一個(gè)平臺都可以支持的很好微信協(xié)議最小成本為16字節(jié),大部分時(shí)間若干個(gè)消息包和在一起,批量傳輸。微信協(xié)議說不上最簡潔,也不是最節(jié)省流量,但是非常成功的。
若服務(wù)器檢測到一些不確定因素,可能會導(dǎo)致微啟用安全套接層SSL協(xié)議進(jìn)行常規(guī)的TCP長連接傳輸。短連接都沒有發(fā)生變化
發(fā)送消息方式
發(fā)送消息走已經(jīng)建立的TCP長連接通道,發(fā)送消息到服務(wù)器,然后接受確認(rèn)信息等,產(chǎn)生一次交互。
小伙伴接收到信息閱讀也都會收到服務(wù)器端通知,產(chǎn)生一次交互等。
可以確定,微信發(fā)送消息走TCP長連接方式,因?yàn)椴粚ψ陨頎顟B(tài)數(shù)據(jù)產(chǎn)生影響,應(yīng)該不交換SyncKey。
在低速網(wǎng)絡(luò)下,大概會看到消息發(fā)送中的提示,屬于消息重發(fā)機(jī)制
網(wǎng)絡(luò)不好有時(shí)客戶端會出現(xiàn)發(fā)送失敗的紅色感嘆號
已發(fā)送到服務(wù)器但未收到確認(rèn)的消息,客戶端顯示紅色感嘆號,再次重發(fā),服務(wù)器作為重復(fù)消息處理,反饋確認(rèn)
上傳圖片,會根據(jù)圖片大小,分割成若干部分(大概1.5K被劃分為一部分),同一時(shí)間點(diǎn),客戶端會發(fā)起若干次POST請求,各自上傳成功之后,服務(wù)器大概會合并成一個(gè)完整圖片,返回一個(gè)縮略圖,顯示在APP聊天窗口內(nèi)。APP作為常規(guī)的文字消息發(fā)送到服務(wù)器端上傳音頻,則單獨(dú)走TCP通道,一個(gè)兩秒的錄制音頻,客戶端錄制完畢,分為兩塊傳輸,一塊最大1.5K左右,服務(wù)端響應(yīng)一條數(shù)據(jù)通知確認(rèn)收到。共三次數(shù)據(jù)傳輸。
音頻和純文字信息一致,都是走TCP長連接,客戶端發(fā)送,服務(wù)器端確認(rèn)。
微信協(xié)議簡單調(diào)研筆記如下介紹:
前言
微信可調(diào)研點(diǎn)很多,這里僅僅從協(xié)議角度進(jìn)行調(diào)研,會涉及到微信協(xié)議交換、消息收發(fā)等。所謂“弱水三千,只取一瓢”吧。
雜七雜八的,有些長,可直接拉到最后看結(jié)論好了。
一。微信協(xié)議概覽
微信傳輸協(xié)議,官方
公布甚少,在微信技術(shù)總監(jiān)所透漏PPT《微信之道—至簡》文檔中,有所體現(xiàn)。
純個(gè)人理解:
因張小龍做郵箱Foxmail起家,繼而又做了QQ Mail等,QQ Mail是國內(nèi)第一個(gè)支持Exchange ActiveSync協(xié)議的免費(fèi)郵箱,基于其從業(yè)背景,微信從一開始就采取基于ActiveSync的修改版狀態(tài)同步協(xié)議Sync,也就再自然不過了。
一句話:增量式、按序、可靠的狀態(tài)同步傳輸?shù)奈⑿艆f(xié)議。
大致交換簡圖如下:
如何獲取新數(shù)據(jù)呢:
服務(wù)器端通知,客戶端獲取
客戶端攜帶最新的SyncKey,發(fā)起數(shù)據(jù)請求
服務(wù)器端生成最新的SyncKey連同最新數(shù)據(jù)發(fā)送給客戶端
基于版本號機(jī)制同步協(xié)議,可確保數(shù)據(jù)增量、有序傳輸
SyncKey,由服務(wù)器端序列號生成器生成,一旦有新消息產(chǎn)生,將會產(chǎn)生最新的SyncKey。類似于版本號
服務(wù)器端通知有狀態(tài)更新,客戶端主動獲取自從上次更新之后有變動的狀態(tài)數(shù)據(jù),增量式,順序式。
二。微信Web端簡單調(diào)試
在線版本微信:
https://webpush.weixin.qq.com/
通過Firefox + Firebug組合調(diào)試,也能證實(shí)了微信大致通過交換SyncKey方式獲取新數(shù)據(jù)的論述。
1. 發(fā)起GET長連接檢測是否存在新的需要同步的數(shù)據(jù)
會攜帶上最新SyncKey
返回內(nèi)容:
window.synccheck={retcode:"0",selector:"2"}
selector值大于0,表示有新的消息需要同步。
據(jù)目測,心跳周期為27秒左右。
2. 一旦有新數(shù)據(jù),客戶端POST請求主動獲取同步的數(shù)據(jù)
https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=s7c%2FsxpGRSihgZAA&r=1393208447375
攜帶消息體:
{"BaseRequest":{"Uin":937355,"Sid":"s7c/sxpGRSihgZAA"},"SyncKey":{"Count":6,"List":[{"Key":1,"Val":620943725},{"Key":2,"Val":620943767},{"Key":3,"Val":620943760},{"Key":11,"Val":620942796},{"Key":201,"Val":1393208365},{"Key":1000,"Val":1393203219}]},"rr":1393208447374}
會攜帶上最新的SyncKey,會返回復(fù)雜結(jié)構(gòu)體JSON內(nèi)容。
但瀏覽端收取到消息之后,如何通知服務(wù)器端已確認(rèn)收到了?Web版本微信,沒有去做。
在以往使用過程中,曾發(fā)現(xiàn)WEB端有丟失消息的現(xiàn)象,但屬于偶爾現(xiàn)象。但Android微信客戶端(只要登陸連接上來之后)貌似就沒有丟失過。
3. 發(fā)送消息流程
發(fā)起一個(gè)POST提交,用于提交用戶需要發(fā)送的消息
https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?sid=lQ95vHR52DiaLVqo&r=1393988414386
發(fā)送內(nèi)容:
{"BaseRequest":{"Uin":937355,"Sid":"lQ95vHR52DiaLVqo","Skey":"A6A1ECC6A7DE59DEFF6A05F226AA334DECBA457887B25BC6","DeviceID":"e937227863752975"},"Msg":{"FromUserName":"yongboy","ToUserName":"hehe057854","Type":1,"Content":"hello","ClientMsgId":1393988414380,"LocalID":1393988414380}}
相應(yīng)內(nèi)容:
{ "BaseResponse": { "Ret": 0, "ErrMsg": "" } , "MsgID": 1020944348, "LocalID": "1393988414380" }
再次發(fā)起一個(gè)POST請求,用于申請最新SyncKey
https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=lQ95vHR52DiaLVqo&r=1393988414756
發(fā)送內(nèi)容:
{"BaseRequest":{"Uin":937355,"Sid":"lQ95vHR52DiaLVqo"},"SyncKey":{"Count":6,"List":[{"Key":1,"Val":620944310},{"Key":2,"Val":620944346},{"Key":3,"Val":620944344},{"Key":11,"Val":620942796},{"Key":201,"Val":1393988357},{"Key":1000,"Val":1393930108}]},"rr":1393988414756}
響應(yīng)的(部分)內(nèi)容:
"SKey": "8F8C6A03489E85E9FDF727ACB95C93C2CDCE9FB9532FC15B"
終止GET長連接,使用最新SyncKey再次發(fā)起一個(gè)新的GET長連接
三。微信Android簡單分析
Windows桌面端Android虛擬機(jī)中運(yùn)行最新版微信(5.2),通過tcpdump/Wireshark組合封包分析,以下為分析結(jié)果。
0. 初始連接記錄
簡單記錄微信啟動之后請求:
11:20:35 dns查詢
dns.weixin.qq.com
返回一組IP地址
11:20:35 DNS查詢
long.weixin.qq.com
返回一組IP地址,本次通信中,微信使用了最后一個(gè)IP作為TCP長連接的連接地址。
11:20:35
http://dns.weixin.qq.com/cgi-bin/micromsg-bin/newgetdns?uin=0&clientversion=620888113&scene=0&net=1
用于請求服務(wù)器獲得最優(yōu)IP路徑。服務(wù)器通過結(jié)算返回一個(gè)xml定義了域名:IP對應(yīng)列表。仔細(xì)閱讀,可看到微信已經(jīng)開始了國際化的步伐:香港、加拿大、韓國等。
具體文本,請參考:https://gist.github.com/yongboy/9341884
11:20:35
獲取到long.weixin.qq.com最優(yōu)IP,然后建立到101.227.131.105的TCP長連接
11:21:25
POST http://short.weixin.qq.com/cgi-bin/micromsg-bin/getprofile HTTP/1.1 (application/octet-stream)
返回一個(gè)名為“micromsgresp.dat”的附件,估計(jì)是未閱讀的離線消息
11:21:31
POST http://short.weixin.qq.com/cgi-bin/micromsg-bin/whatsnews HTTP/1.1 (application/octet-stream)
大概是資訊、訂閱更新等
中間進(jìn)行一些資源請求等,類似于
GET http://wx.qlogo.cn/mmhead/Q3auHgzwzM7NR4TYFcoNjbxZpfO9aiaE7RU5lXGUw13SMicL6iacWIf2A/96
圖片等一些靜態(tài)資源都會被分配到wx.qlogo.cn域名下面
不明白做什么用途
POST http://short.weixin.qq.com/cgi-bin/micromsg-bin/downloadpackage HTTP/1.1 (application/octet-stream)
輸出為micromsgresp.dat文件
11:21:47
GET http://support.weixin.qq.com/cgi-bin/mmsupport-bin/reportdevice?channel=34&deviceid=A952001f7a840c2a&clientversion=620888113&platform=0&lang=zh_CN&installtype=0 HTTP/1.1
返回chunked分塊數(shù)據(jù)
11:21:49
POST http://short.weixin.qq.com/cgi-bin/micromsg-bin/reportstrategy HTTP/1.1 (application/octet-stream)
1. 心跳頻率約為5分鐘
上次使用Wireshark分析有誤(得出18分鐘結(jié)論),再次重新分析,心跳頻率在5分鐘左右。
2. 登陸之后,會建立一個(gè)長連接,端口號為8080
簡單目測為HTTP,初始以為是雙通道HTTP,難道是自定義的用于雙通道通信的HTTP協(xié)議嗎,網(wǎng)絡(luò)上可見資料都是模棱兩可、語焉不詳。
具體查看長連接初始數(shù)據(jù)通信,沒有發(fā)現(xiàn)任何包含"HTTP"字樣的數(shù)據(jù),以為是微信自定義的TCP/HTTP通信格式。據(jù)分析,用于可能用于獲取數(shù)據(jù)、心跳交換消息等用途吧。這個(gè)后面會詳談微信是如何做到的。
2.0 初始消息傳輸
個(gè)人資料、離線未閱讀消息部分等通過 POST HTTP短連接單獨(dú)獲取。
2.1 二進(jìn)制簡單分析
抽取微信某次HTTP協(xié)議方式通信數(shù)據(jù),16進(jìn)制表示,每兩個(gè)靠近的數(shù)字為一個(gè)byte字節(jié):
2014-03-03_15h07_30
微信協(xié)議可能如下:
一個(gè)消息包 = 消息頭 + 消息體
消息頭固定16字節(jié)長度,消息包長度定義在消息頭前4個(gè)字節(jié)中。
單純摘取第0000行為例,共16個(gè)字節(jié)的頭部:
00 00 00 10 00 10 00 01 00 00 00 06 00 00 00 0f
16進(jìn)制表示,每兩個(gè)緊挨著數(shù)字代表一個(gè)byte字節(jié)。
微信消息包格式: 1. 前4字節(jié)表示數(shù)據(jù)包長度,可變 值為16時(shí),意味著一個(gè)僅僅包含頭部的完整的數(shù)據(jù)包(可能表示著預(yù)先定義好的業(yè)務(wù)意義),后面可能還有會別的消息包 2. 2個(gè)字節(jié)表示頭部長度,固定值,0x10 = 16 3. 2個(gè)字節(jié)表示謝意版本,固定值,0x01 = 1 4. 4個(gè)字節(jié)操作說明數(shù)字,可變 5. 序列號,可變 6. 頭部后面緊跟著消息體,非明文,加密形式 7. 一個(gè)消息包,最小16 byte字節(jié)
通過上圖(以及其它數(shù)據(jù)多次采樣)分析:
0000 - 0040為單獨(dú)的數(shù)據(jù)包
0050行為下一個(gè)數(shù)據(jù)包的頭部,前四個(gè)字節(jié)值為0xca = 202,表示包含了從0050-0110共202個(gè)字節(jié)數(shù)據(jù)
一次數(shù)據(jù)發(fā)送,可能包含若干子數(shù)據(jù)包
換行符\n,16進(jìn)制表示為0x0a,在00f0行,包含了兩個(gè)換行符號
一個(gè)數(shù)據(jù)體換行符號用于更細(xì)粒度的業(yè)務(wù)數(shù)據(jù)分割 是否蒙對,需要問問做微信協(xié)議的同學(xué)
所有被標(biāo)記為HTTP協(xié)議通信所發(fā)送數(shù)據(jù)都包含換行符號
2.2 動手試試猜想,模擬微信TCP長連接
開始很不解為什么會出現(xiàn)如此怪異的HTTP雙通道長連接請求,難道基于TCP通信,然后做了一些手腳?很常規(guī)的TCP長連接,傳輸數(shù)據(jù)時(shí)(不是所有數(shù)據(jù)傳輸),被wireshark誤認(rèn)為HTTP長連接。這個(gè)需要做一個(gè)實(shí)驗(yàn)證實(shí)一下自己想法,設(shè)想如下:
寫一個(gè)Ping-Pong客戶端、服務(wù)器端程序,然后使用Wireshark看一下結(jié)果,是否符合判斷。
Java版本的請求端,默認(rèn)請求8080端口:
<span style="font-size:12px;"><pre class="line-pre" name="code" style="white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-size: 13px; font-style: inherit; font-variant: inherit; line-height: inherit; font-family: Consolas, 'Liberation Mono', Courier, monospace; margin-top: 0px !important; margin-bottom: 0px !important; border: none !important; padding: 0px !important; background-color: transparent !important;"><div class="line" id="file-pingclient-java-LC1"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;">/**</span></div><div class="line" id="file-pingclient-java-LC2"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;"> * Ping Client</span></div><div class="line" id="file-pingclient-java-LC3"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;"> * @author nieyong</span></div><div class="line" id="file-pingclient-java-LC4"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;"> */</span></div><div class="line" id="file-pingclient-java-LC5"><span class="kn">package</span> <span class="n">com</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">learn</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC6"> </div><div class="line" id="file-pingclient-java-LC7"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.bootstrap.Bootstrap</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC8"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.buffer.ByteBuf</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC9"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.buffer.PooledByteBufAllocator</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC10"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.ChannelFuture</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC11"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.ChannelHandlerContext</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC12"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.ChannelInboundHandlerAdapter</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC13"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.ChannelInitializer</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC14"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.ChannelOption</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC15"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.EventLoopGroup</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC16"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.nio.NioEventLoopGroup</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC17"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.socket.SocketChannel</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC18"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.socket.nio.NioSocketChannel</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC19"> </div><div class="line" id="file-pingclient-java-LC20"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">java.util.concurrent.TimeUnit</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC21"> </div><div class="line" id="file-pingclient-java-LC22"><span class="kd" style="font-weight: bold;">class</span> <span class="nc" style="color: rgb(68, 85, 136); font-weight: bold;">PingClientHandler</span> <span class="kd" style="font-weight: bold;">extends</span> <span class="n">ChannelInboundHandlerAdapter</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC23"> <span class="kd" style="font-weight: bold;">private</span> <span class="kd" style="font-weight: bold;">final</span> <span class="n">ByteBuf</span> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC24"> </div><div class="line" id="file-pingclient-java-LC25"> <span class="kd" style="font-weight: bold;">public</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">PingClientHandler</span><span class="o" style="font-weight: bold;">()</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC26"> <span class="n">firstMessage</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">PooledByteBufAllocator</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">DEFAULT</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">buffer</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">22</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC27"> </div><div class="line" id="file-pingclient-java-LC28"> <span class="c1" style="color: rgb(153, 153, 136); font-style: italic;">// weixin 16 byte's header</span></div><div class="line" id="file-pingclient-java-LC29"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC30"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC31"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC32"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">16</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC33"> </div><div class="line" id="file-pingclient-java-LC34"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC35"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">16</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC36"> </div><div class="line" id="file-pingclient-java-LC37"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC38"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC39"> </div><div class="line" id="file-pingclient-java-LC40"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC41"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC42"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC43"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">6</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC44"> </div><div class="line" id="file-pingclient-java-LC45"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC46"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC47"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC48"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC49"> </div><div class="line" id="file-pingclient-java-LC50"> <span class="c1" style="color: rgb(153, 153, 136); font-style: italic;">// just for /n</span></div><div class="line" id="file-pingclient-java-LC51"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="sc" style="color: rgb(221, 17, 68);">'\n'</span><span class="o" style="font-weight: bold;">);</span> <span class="c1" style="color: rgb(153, 153, 136); font-style: italic;">// 1 byte</span></div><div class="line" id="file-pingclient-java-LC52"> </div><div class="line" id="file-pingclient-java-LC53"> <span class="c1" style="color: rgb(153, 153, 136); font-style: italic;">// footer 16 byte</span></div><div class="line" id="file-pingclient-java-LC54"> <span class="n">String</span> <span class="n">welcome</span> <span class="o" style="font-weight: bold;">=</span> <span class="s" style="color: rgb(221, 17, 68);">"hello"</span><span class="o" style="font-weight: bold;">;</span> <span class="c1" style="color: rgb(153, 153, 136); font-style: italic;">// 5 byte</span></div><div class="line" id="file-pingclient-java-LC55"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeBytes</span><span class="o" style="font-weight: bold;">(</span><span class="n">welcome</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">getBytes</span><span class="o" style="font-weight: bold;">());</span></div><div class="line" id="file-pingclient-java-LC56"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC57"> </div><div class="line" id="file-pingclient-java-LC58"> <span class="nd">@Override</span></div><div class="line" id="file-pingclient-java-LC59"> <span class="kd" style="font-weight: bold;">public</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">channelActive</span><span class="o" style="font-weight: bold;">(</span><span class="n">ChannelHandlerContext</span> <span class="n">ctx</span><span class="o" style="font-weight: bold;">)</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC60"> <span class="n">ctx</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeAndFlush</span><span class="o" style="font-weight: bold;">(</span><span class="n">firstMessage</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC61"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC62"> </div><div class="line" id="file-pingclient-java-LC63"> <span class="nd">@Override</span></div><div class="line" id="file-pingclient-java-LC64"> <span class="kd" style="font-weight: bold;">public</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">channelRead</span><span class="o" style="font-weight: bold;">(</span><span class="kd" style="font-weight: bold;">final</span> <span class="n">ChannelHandlerContext</span> <span class="n">ctx</span><span class="o" style="font-weight: bold;">,</span> <span class="kd" style="font-weight: bold;">final</span> <span class="n">Object</span> <span class="n">msg</span><span class="o" style="font-weight: bold;">)</span></div><div class="line" id="file-pingclient-java-LC65"> <span class="kd" style="font-weight: bold;">throws</span> <span class="n">Exception</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC66"> <span class="n">ctx</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">executor</span><span class="o" style="font-weight: bold;">().</span><span class="na" style="color: teal;">schedule</span><span class="o" style="font-weight: bold;">(</span><span class="k" style="font-weight: bold;">new</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">Runnable</span><span class="o" style="font-weight: bold;">()</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC67"> <span class="nd">@Override</span></div><div class="line" id="file-pingclient-java-LC68"> <span class="kd" style="font-weight: bold;">public</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">run</span><span class="o" style="font-weight: bold;">()</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC69"> <span class="n">ctx</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">channel</span><span class="o" style="font-weight: bold;">().</span><span class="na" style="color: teal;">writeAndFlush</span><span class="o" style="font-weight: bold;">(</span><span class="n">msg</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC70"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC71"> <span class="o" style="font-weight: bold;">},</span> <span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="o" style="font-weight: bold;">,</span> <span class="n">TimeUnit</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">SECONDS</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC72"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC73"> </div><div class="line" id="file-pingclient-java-LC74"> <span class="nd">@Override</span></div><div class="line" id="file-pingclient-java-LC75"> <span class="kd" style="font-weight: bold;">public</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">channelReadComplete</span><span class="o" style="font-weight: bold;">(</span><span class="n">ChannelHandlerContext</span> <span class="n">ctx</span><span class="o" style="font-weight: bold;">)</span> <span class="kd" style="font-weight: bold;">throws</span> <span class="n">Exception</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC76"> <span class="n">ctx</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">flush</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC77"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC78"> </div><div class="line" id="file-pingclient-java-LC79"> <span class="nd">@Override</span></div><div class="line" id="file-pingclient-java-LC80"> <span class="kd" style="font-weight: bold;">public</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">exceptionCaught</span><span class="o" style="font-weight: bold;">(</span><span class="n">ChannelHandlerContext</span> <span class="n">ctx</span><span class="o" style="font-weight: bold;">,</span> <span class="n">Throwable</span> <span class="n">cause</span><span class="o" style="font-weight: bold;">)</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC81"> <span class="n">System</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">err</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">println</span><span class="o" style="font-weight: bold;">(</span><span class="s" style="color: rgb(221, 17, 68);">"Unexpected exception from downstream :"</span></div><div class="line" id="file-pingclient-java-LC82"> <span class="o" style="font-weight: bold;">+</span> <span class="n">cause</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">getMessage</span><span class="o" style="font-weight: bold;">());</span></div><div class="line" id="file-pingclient-java-LC83"> <span class="n">ctx</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">close</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC84"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC85"><span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC86"> </div><div class="line" id="file-pingclient-java-LC87"><span class="kd" style="font-weight: bold;">public</span> <span class="kd" style="font-weight: bold;">class</span> <span class="nc" style="color: rgb(68, 85, 136); font-weight: bold;">PingClient</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC88"> </div><div class="line" id="file-pingclient-java-LC89"> <span class="kd" style="font-weight: bold;">private</span> <span class="kd" style="font-weight: bold;">final</span> <span class="n">String</span> <span class="n">host</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC90"> <span class="kd" style="font-weight: bold;">private</span> <span class="kd" style="font-weight: bold;">final</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">port</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC91"> </div><div class="line" id="file-pingclient-java-LC92"> <span class="kd" style="font-weight: bold;">public</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">PingClient</span><span class="o" style="font-weight: bold;">(</span><span class="n">String</span> <span class="n">host</span><span class="o" style="font-weight: bold;">,</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">port</span><span class="o" style="font-weight: bold;">)</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC93"> <span class="k" style="font-weight: bold;">this</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">host</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">host</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC94"> <span class="k" style="font-weight: bold;">this</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">port</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">port</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC95"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC96"> </div><div class="line" id="file-pingclient-java-LC97"> <span class="kd" style="font-weight: bold;">public</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">run</span><span class="o" style="font-weight: bold;">()</span> <span class="kd" style="font-weight: bold;">throws</span> <span class="n">Exception</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC98"> <span class="n">EventLoopGroup</span> <span class="n">group</span> <span class="o" style="font-weight: bold;">=</span> <span class="k" style="font-weight: bold;">new</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">NioEventLoopGroup</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC99"> <span class="k" style="font-weight: bold;">try</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC100"> <span class="n">Bootstrap</span> <span class="n">b</span> <span class="o" style="font-weight: bold;">=</span> <span class="k" style="font-weight: bold;">new</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">Bootstrap</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC101"> <span class="n">b</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">group</span><span class="o" style="font-weight: bold;">(</span><span class="n">group</span><span class="o" style="font-weight: bold;">).</span><span class="na" style="color: teal;">channel</span><span class="o" style="font-weight: bold;">(</span><span class="n">NioSocketChannel</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">class</span><span class="o" style="font-weight: bold;">)</span></div><div class="line" id="file-pingclient-java-LC102"> <span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">option</span><span class="o" style="font-weight: bold;">(</span><span class="n">ChannelOption</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">TCP_NODELAY</span><span class="o" style="font-weight: bold;">,</span> <span class="kc" style="font-weight: bold;">true</span><span class="o" style="font-weight: bold;">)</span></div><div class="line" id="file-pingclient-java-LC103"> <span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">handler</span><span class="o" style="font-weight: bold;">(</span><span class="k" style="font-weight: bold;">new</span> <span class="n">ChannelInitializer</span><span class="o" style="font-weight: bold;"><</span><span class="n">SocketChannel</span><span class="o" style="font-weight: bold;">>()</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC104"> <span class="nd">@Override</span></div><div class="line" id="file-pingclient-java-LC105"> <span class="kd" style="font-weight: bold;">public</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">initChannel</span><span class="o" style="font-weight: bold;">(</span><span class="n">SocketChannel</span> <span class="n">ch</span><span class="o" style="font-weight: bold;">)</span></div><div class="line" id="file-pingclient-java-LC106"> <span class="kd" style="font-weight: bold;">throws</span> <span class="n">Exception</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC107"> <span class="n">ch</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">pipeline</span><span class="o" style="font-weight: bold;">().</span><span class="na" style="color: teal;">addLast</span><span class="o" style="font-weight: bold;">(</span><span class="k" style="font-weight: bold;">new</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">PingClientHandler</span><span class="o" style="font-weight: bold;">());</span></div><div class="line" id="file-pingclient-java-LC108"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC109"> <span class="o" style="font-weight: bold;">});</span></div><div class="line" id="file-pingclient-java-LC110"> </div><div class="line" id="file-pingclient-java-LC111"> <span class="n">ChannelFuture</span> <span class="n">f</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">b</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">connect</span><span class="o" style="font-weight: bold;">(</span><span class="n">host</span><span class="o" style="font-weight: bold;">,</span> <span class="n">port</span><span class="o" style="font-weight: bold;">).</span><span class="na" style="color: teal;">sync</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC112"> </div><div class="line" id="file-pingclient-java-LC113"> <span class="n">f</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">channel</span><span class="o" style="font-weight: bold;">().</span><span class="na" style="color: teal;">closeFuture</span><span class="o" style="font-weight: bold;">().</span><span class="na" style="color: teal;">sync</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC114"> <span class="o" style="font-weight: bold;">}</span> <span class="k" style="font-weight: bold;">finally</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC115"> <span class="c1" style="color: rgb(153, 153, 136); font-style: italic;">// Shut down the event loop to terminate all threads.</span></div><div class="line" id="file-pingclient-java-LC116"> <span class="n">group</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">shutdownGracefully</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC117"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC118"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC119"> </div><div class="line" id="file-pingclient-java-LC120"> <span class="kd" style="font-weight: bold;">public</span> <span class="kd" style="font-weight: bold;">static</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">main</span><span class="o" style="font-weight: bold;">(</span><span class="n">String</span><span class="o" style="font-weight: bold;">[]</span> <span class="n">args</span><span class="o" style="font-weight: bold;">)</span> <span class="kd" style="font-weight: bold;">throws</span> <span class="n">Exception</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC121"> <span class="n">String</span> <span class="n">host</span> <span class="o" style="font-weight: bold;">=</span> <span class="s" style="color: rgb(221, 17, 68);">"127.0.0.1"</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC122"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">port</span> <span class="o" style="font-weight: bold;">=</span> <span class="mi" style="color: rgb(0, 153, 153);">8080</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC123"> </div><div class="line" id="file-pingclient-java-LC124"> <span class="k" style="font-weight: bold;">if</span> <span class="o" style="font-weight: bold;">(</span><span class="n">args</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">length</span> <span class="o" style="font-weight: bold;">==</span> <span class="mi" style="color: rgb(0, 153, 153);">3</span><span class="o" style="font-weight: bold;">)</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC125"> <span class="n">host</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">args</span><span class="o" style="font-weight: bold;">[</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">];</span></div><div class="line" id="file-pingclient-java-LC126"> <span class="n">port</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">Integer</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">parseInt</span><span class="o" style="font-weight: bold;">(</span><span class="n">args</span><span class="o" style="font-weight: bold;">[</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="o" style="font-weight: bold;">]);</span></div><div class="line" id="file-pingclient-java-LC127"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC128"> </div><div class="line" id="file-pingclient-java-LC129"> <span class="k" style="font-weight: bold;">new</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">PingClient</span><span class="o" style="font-weight: bold;">(</span><span class="n">host</span><span class="o" style="font-weight: bold;">,</span> <span class="n">port</span><span class="o" style="font-weight: bold;">).</span><span class="na" style="color: teal;">run</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC130"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC131"><span class="o" style="font-weight: bold;">}</span></div></span>
C語言版本的服務(wù)器程序,收到什么發(fā)送什么,沒有任何邏輯,默認(rèn)綁定8080端口:
<span style="font-size:12px;"><pre class="line-pre" name="code" style="white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-size: 13px; font-style: inherit; font-variant: inherit; line-height: inherit; font-family: Consolas, 'Liberation Mono', Courier, monospace; margin-top: 0px !important; margin-bottom: 0px !important; border: none !important; padding: 0px !important; background-color: transparent !important;"><div class="line" id="file-pong_server-c-LC1"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;">/**</span></div><div class="line" id="file-pong_server-c-LC2"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;"> * nieyong@youku.com</span></div><div class="line" id="file-pong_server-c-LC3"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;"> * how to compile it:</span></div><div class="line" id="file-pong_server-c-LC4"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;"> * gcc pong_server.c -o pong_server /usr/local/lib/libev.a -lm </span></div><div class="line" id="file-pong_server-c-LC5"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;"> */</span></div><div class="line" id="file-pong_server-c-LC6"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <arpa/inet.h></span></div><div class="line" id="file-pong_server-c-LC7"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <stdlib.h></span></div><div class="line" id="file-pong_server-c-LC8"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <stdio.h></span></div><div class="line" id="file-pong_server-c-LC9"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <string.h></span></div><div class="line" id="file-pong_server-c-LC10"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <fcntl.h></span></div><div class="line" id="file-pong_server-c-LC11"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <errno.h></span></div><div class="line" id="file-pong_server-c-LC12"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <err.h></span></div><div class="line" id="file-pong_server-c-LC13"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <unistd.h></span></div><div class="line" id="file-pong_server-c-LC14"> </div><div class="line" id="file-pong_server-c-LC15"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include "../include/ev.h"</span></div><div class="line" id="file-pong_server-c-LC16"> </div><div class="line" id="file-pong_server-c-LC17"><span class="k" style="font-weight: bold;">static</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">server_port</span> <span class="o" style="font-weight: bold;">=</span> <span class="mi" style="color: rgb(0, 153, 153);">8080</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC18"> </div><div class="line" id="file-pong_server-c-LC19"><span class="k" style="font-weight: bold;">struct</span> <span class="n">ev_loop</span> <span class="o" style="font-weight: bold;">*</span><span class="n">loop</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC20"><span class="k" style="font-weight: bold;">typedef</span> <span class="k" style="font-weight: bold;">struct</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC21"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">fd</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC22"> <span class="n">ev_io</span> <span class="n">ev_read</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC23"><span class="p">}</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">client_t</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC24"> </div><div class="line" id="file-pong_server-c-LC25"><span class="n">ev_io</span> <span class="n">ev_accept</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC26"> </div><div class="line" id="file-pong_server-c-LC27"><span class="k" style="font-weight: bold;">static</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">free_res</span><span class="p">(</span><span class="k" style="font-weight: bold;">struct</span> <span class="n">ev_loop</span> <span class="o" style="font-weight: bold;">*</span><span class="n">loop</span><span class="p">,</span> <span class="n">ev_io</span> <span class="o" style="font-weight: bold;">*</span><span class="n">ws</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC28"> </div><div class="line" id="file-pong_server-c-LC29"><span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">setnonblock</span><span class="p">(</span><span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">fd</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC30"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">flags</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">fcntl</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">F_GETFL</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC31"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">flags</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC32"> <span class="k" style="font-weight: bold;">return</span> <span class="n">flags</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC33"> </div><div class="line" id="file-pong_server-c-LC34"> <span class="n">flags</span> <span class="o" style="font-weight: bold;">|=</span> <span class="n">O_NONBLOCK</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC35"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">fcntl</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">F_SETFL</span><span class="p">,</span> <span class="n">flags</span><span class="p">)</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC36"> <span class="k" style="font-weight: bold;">return</span> <span class="o" style="font-weight: bold;">-</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC37"> </div><div class="line" id="file-pong_server-c-LC38"> <span class="k" style="font-weight: bold;">return</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC39"><span class="p">}</span></div><div class="line" id="file-pong_server-c-LC40"> </div><div class="line" id="file-pong_server-c-LC41"><span class="k" style="font-weight: bold;">static</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">read_cb</span><span class="p">(</span><span class="k" style="font-weight: bold;">struct</span> <span class="n">ev_loop</span> <span class="o" style="font-weight: bold;">*</span><span class="n">loop</span><span class="p">,</span> <span class="n">ev_io</span> <span class="o" style="font-weight: bold;">*</span><span class="n">w</span><span class="p">,</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">revents</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC42"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">client_t</span> <span class="o" style="font-weight: bold;">*</span><span class="n">client</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">w</span><span class="o" style="font-weight: bold;">-></span><span class="n">data</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC43"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">r</span> <span class="o" style="font-weight: bold;">=</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC44"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">char</span> <span class="n">rbuff</span><span class="p">[</span><span class="mi" style="color: rgb(0, 153, 153);">1024</span><span class="p">];</span></div><div class="line" id="file-pong_server-c-LC45"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">revents</span> <span class="o" style="font-weight: bold;">&</span> <span class="n">EV_READ</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC46"> <span class="n">r</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">read</span><span class="p">(</span><span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">fd</span><span class="p">,</span> <span class="o" style="font-weight: bold;">&</span><span class="n">rbuff</span><span class="p">,</span> <span class="mi" style="color: rgb(0, 153, 153);">1024</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC47"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC48"> </div><div class="line" id="file-pong_server-c-LC49"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">EV_ERROR</span> <span class="o" style="font-weight: bold;">&</span> <span class="n">revents</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC50"> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"error event in read</span><span class="se" style="color: rgb(221, 17, 68);">\n</span><span class="s" style="color: rgb(221, 17, 68);">"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC51"> <span class="n">free_res</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="n">w</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC52"> <span class="k" style="font-weight: bold;">return</span> <span class="p">;</span></div><div class="line" id="file-pong_server-c-LC53"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC54"> </div><div class="line" id="file-pong_server-c-LC55"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">r</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC56"> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"read error</span><span class="se" style="color: rgb(221, 17, 68);">\n</span><span class="s" style="color: rgb(221, 17, 68);">"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC57"> <span class="n">ev_io_stop</span><span class="p">(</span><span class="n">EV_A_</span> <span class="n">w</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC58"> <span class="n">free_res</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="n">w</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC59"> <span class="k" style="font-weight: bold;">return</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC60"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC61"> </div><div class="line" id="file-pong_server-c-LC62"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">r</span> <span class="o" style="font-weight: bold;">==</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC63"> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"client disconnected.</span><span class="se" style="color: rgb(221, 17, 68);">\n</span><span class="s" style="color: rgb(221, 17, 68);">"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC64"> <span class="n">ev_io_stop</span><span class="p">(</span><span class="n">EV_A_</span> <span class="n">w</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC65"> <span class="n">free_res</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="n">w</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC66"> <span class="k" style="font-weight: bold;">return</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC67"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC68"> </div><div class="line" id="file-pong_server-c-LC69"> <span class="n">send</span><span class="p">(</span><span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">fd</span><span class="p">,</span> <span class="n">rbuff</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC70"><span class="p">}</span></div><div class="line" id="file-pong_server-c-LC71"> </div><div class="line" id="file-pong_server-c-LC72"><span class="k" style="font-weight: bold;">static</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">accept_cb</span><span class="p">(</span><span class="k" style="font-weight: bold;">struct</span> <span class="n">ev_loop</span> <span class="o" style="font-weight: bold;">*</span><span class="n">loop</span><span class="p">,</span> <span class="n">ev_io</span> <span class="o" style="font-weight: bold;">*</span><span class="n">w</span><span class="p">,</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">revents</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC73"> <span class="k" style="font-weight: bold;">struct</span> <span class="n">sockaddr_in</span> <span class="n">client_addr</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC74"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">socklen_t</span> <span class="n">client_len</span> <span class="o" style="font-weight: bold;">=</span> <span class="k" style="font-weight: bold;">sizeof</span><span class="p">(</span><span class="n">client_addr</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC75"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">client_fd</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">accept</span><span class="p">(</span><span class="n">w</span><span class="o" style="font-weight: bold;">-></span><span class="n">fd</span><span class="p">,</span> <span class="p">(</span><span class="k" style="font-weight: bold;">struct</span> <span class="n">sockaddr</span> <span class="o" style="font-weight: bold;">*</span><span class="p">)</span> <span class="o" style="font-weight: bold;">&</span><span class="n">client_addr</span><span class="p">,</span> <span class="o" style="font-weight: bold;">&</span><span class="n">client_len</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC76"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">client_fd</span> <span class="o" style="font-weight: bold;">==</span> <span class="o" style="font-weight: bold;">-</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC77"> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"the client_fd is NULL !</span><span class="se" style="color: rgb(221, 17, 68);">\n</span><span class="s" style="color: rgb(221, 17, 68);">"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC78"> <span class="k" style="font-weight: bold;">return</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC79"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC80"> </div><div class="line" id="file-pong_server-c-LC81"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">client_t</span> <span class="o" style="font-weight: bold;">*</span><span class="n">client</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">malloc</span><span class="p">(</span><span class="k" style="font-weight: bold;">sizeof</span><span class="p">(</span><span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">client_t</span><span class="p">));</span></div><div class="line" id="file-pong_server-c-LC82"> <span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">fd</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">client_fd</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC83"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">setnonblock</span><span class="p">(</span><span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">fd</span><span class="p">)</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC84"> <span class="n">err</span><span class="p">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"failed to set client socket to non-blocking"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC85"> </div><div class="line" id="file-pong_server-c-LC86"> <span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">ev_read</span><span class="p">.</span><span class="n">data</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">client</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC87"> </div><div class="line" id="file-pong_server-c-LC88"> <span class="n">ev_io_init</span><span class="p">(</span><span class="o" style="font-weight: bold;">&</span><span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">ev_read</span><span class="p">,</span> <span class="n">read_cb</span><span class="p">,</span> <span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">fd</span><span class="p">,</span> <span class="n">EV_READ</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC89"> <span class="n">ev_io_start</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="o" style="font-weight: bold;">&</span><span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">ev_read</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC90"><span class="p">}</span></div><div class="line" id="file-pong_server-c-LC91"> </div><div class="line" id="file-pong_server-c-LC92"><span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">main</span><span class="p">(</span><span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">char</span> <span class="k" style="font-weight: bold;">const</span> <span class="o" style="font-weight: bold;">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC93"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">ch</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC94"> <span class="k" style="font-weight: bold;">while</span> <span class="p">((</span><span class="n">ch</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">getopt</span><span class="p">(</span><span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"p:"</span><span class="p">))</span> <span class="o" style="font-weight: bold;">!=</span> <span class="o" style="font-weight: bold;">-</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC95"> <span class="k" style="font-weight: bold;">switch</span> <span class="p">(</span><span class="n">ch</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC96"> <span class="k" style="font-weight: bold;">case</span> <span class="sc" style="color: rgb(221, 17, 68);">'p'</span><span class="o" style="font-weight: bold;">:</span></div><div class="line" id="file-pong_server-c-LC97"> <span class="n">server_port</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">atoi</span><span class="p">(</span><span class="n">optarg</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC98"> <span class="k" style="font-weight: bold;">break</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC99"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC100"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC101"> </div><div class="line" id="file-pong_server-c-LC102"> <span class="n">loop</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">ev_default_loop</span><span class="p">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC103"> <span class="k" style="font-weight: bold;">struct</span> <span class="n">sockaddr_in</span> <span class="n">listen_addr</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC104"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">reuseaddr_on</span> <span class="o" style="font-weight: bold;">=</span> <span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC105"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">listen_fd</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_STREAM</span><span class="p">,</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC106"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">listen_fd</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC107"> <span class="n">err</span><span class="p">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"listen failed"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC108"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">setsockopt</span><span class="p">(</span><span class="n">listen_fd</span><span class="p">,</span> <span class="n">SOL_SOCKET</span><span class="p">,</span> <span class="n">SO_REUSEADDR</span><span class="p">,</span> <span class="o" style="font-weight: bold;">&</span><span class="n">reuseaddr_on</span><span class="p">,</span> <span class="k" style="font-weight: bold;">sizeof</span><span class="p">(</span><span class="n">reuseaddr_on</span><span class="p">))</span> <span class="o" style="font-weight: bold;">==</span> <span class="o" style="font-weight: bold;">-</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC109"> <span class="n">err</span><span class="p">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"setsockopt failed"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC110"> </div><div class="line" id="file-pong_server-c-LC111"> <span class="n">memset</span><span class="p">(</span><span class="o" style="font-weight: bold;">&</span><span class="n">listen_addr</span><span class="p">,</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">,</span> <span class="k" style="font-weight: bold;">sizeof</span><span class="p">(</span><span class="n">listen_addr</span><span class="p">));</span></div><div class="line" id="file-pong_server-c-LC112"> <span class="n">listen_addr</span><span class="p">.</span><span class="n">sin_family</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">AF_INET</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC113"> <span class="n">listen_addr</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">.</span><span class="n">s_addr</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">INADDR_ANY</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC114"> <span class="n">listen_addr</span><span class="p">.</span><span class="n">sin_port</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">htons</span><span class="p">(</span><span class="n">server_port</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC115"> </div><div class="line" id="file-pong_server-c-LC116"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">bind</span><span class="p">(</span><span class="n">listen_fd</span><span class="p">,</span> <span class="p">(</span><span class="k" style="font-weight: bold;">struct</span> <span class="n">sockaddr</span> <span class="o" style="font-weight: bold;">*</span><span class="p">)</span> <span class="o" style="font-weight: bold;">&</span><span class="n">listen_addr</span><span class="p">,</span> <span class="k" style="font-weight: bold;">sizeof</span><span class="p">(</span><span class="n">listen_addr</span><span class="p">))</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC117"> <span class="n">err</span><span class="p">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"bind failed"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC118"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">listen</span><span class="p">(</span><span class="n">listen_fd</span><span class="p">,</span> <span class="mi" style="color: rgb(0, 153, 153);">5</span><span class="p">)</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC119"> <span class="n">err</span><span class="p">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"listen failed"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC120"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">setnonblock</span><span class="p">(</span><span class="n">listen_fd</span><span class="p">)</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC121"> <span class="n">err</span><span class="p">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"failed to set server socket to non-blocking"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC122"> </div><div class="line" id="file-pong_server-c-LC123"> <span class="n">ev_io_init</span><span class="p">(</span><span class="o" style="font-weight: bold;">&</span><span class="n">ev_accept</span><span class="p">,</span> <span class="n">accept_cb</span><span class="p">,</span> <span class="n">listen_fd</span><span class="p">,</span> <span class="n">EV_READ</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC124"> <span class="n">ev_io_start</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="o" style="font-weight: bold;">&</span><span class="n">ev_accept</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC125"> <span class="n">ev_loop</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC126"> </div><div class="line" id="file-pong_server-c-LC127"> <span class="k" style="font-weight: bold;">return</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC128"><span class="p">}</span></div><div class="line" id="file-pong_server-c-LC129"> </div><div class="line" id="file-pong_server-c-LC130"><span class="k" style="font-weight: bold;">static</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">free_res</span><span class="p">(</span><span class="k" style="font-weight: bold;">struct</span> <span class="n">ev_loop</span> <span class="o" style="font-weight: bold;">*</span><span class="n">loop</span><span class="p">,</span> <span class="n">ev_io</span> <span class="o" style="font-weight: bold;">*</span><span class="n">w</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC131"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">client_t</span> <span class="o" style="font-weight: bold;">*</span><span class="n">client</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">w</span><span class="o" style="font-weight: bold;">-></span><span class="n">data</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC132"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">client</span> <span class="o" style="font-weight: bold;">==</span> <span class="nb" style="color: rgb(0, 134, 179);">NULL</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC133"> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"the client is NULL !!!!!!"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC134"> <span class="k" style="font-weight: bold;">return</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC135"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC136"> </div><div class="line" id="file-pong_server-c-LC137"> <span class="n">ev_io_stop</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="o" style="font-weight: bold;">&</span><span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">ev_read</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC138"> <span class="n">close</span><span class="p">(</span><span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">fd</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC139"> <span class="n">free</span><span class="p">(</span><span class="n">client</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC140"><span class="p">}</span></div></span>
這里有一個(gè)現(xiàn)場圖:
可以嘗試稍微改變輸出內(nèi)容,去除換行符“\n”,把端口換成9000,試試看,就會發(fā)現(xiàn)Wireshark輸出不同的結(jié)果來。
2.3 結(jié)論是什么呢?
若使用原始TCP進(jìn)行雙向通信,則需要滿足以下條件,可以被類似于Wireshark協(xié)議攔截器誤認(rèn)為是HTTP長連接:
使用80/8080端口(81/3128/8000經(jīng)測試無效) 也許8080一般被作為WEB代理服務(wù)端口,微信才會享用這個(gè)紅利吧。
輸出的內(nèi)容中,一定要包含換行字符"\n"
因此,可以定性為微信使用了基于8080端口TCP長連接,一旦數(shù)據(jù)包中含有換行"\n"符號,就會被Wireshark誤認(rèn)為HTTP協(xié)議。可能微信是無心為之吧。
3. 新消息獲取方式
TCP長連接接收到服務(wù)器通知有新消息需要獲取
APP發(fā)起一個(gè)HTTP POST請求獲取新狀態(tài)消息,會帶上當(dāng)前SyncKey 地址為:http://short.weixin.qq.com/cgi-bin/micromsg-bin/reportstrategy HTTP/1.1,看不到明文
APP獲取到新的消息,會再次發(fā)起一次HTTP POST請求,告訴服務(wù)器已確認(rèn)收到,同時(shí)獲取最新SyncKey 地址為:http://short.weixin.qq.com/cgi-bin/micromsg-bin/kvreport,看不到明文
接受一個(gè)消息,TCP長連接至少交互兩次,客戶端發(fā)起兩次HTTP POST請求 具體每次交互內(nèi)容是什么,有些模糊
服務(wù)器需要支持:狀態(tài)消息獲取標(biāo)記,狀態(tài)消息確認(rèn)收取標(biāo)記。只有被確認(rèn)收到,此狀態(tài)消息才算是被正確消費(fèi)掉
多個(gè)不同設(shè)備同一賬號同時(shí)使用微信,同一個(gè)狀態(tài)消息會會被同時(shí)分發(fā)到多個(gè)設(shè)備上
此時(shí)消息請求截圖如下:
4. 發(fā)送消息方式
發(fā)送消息走已經(jīng)建立的TCP長連接通道,發(fā)送消息到服務(wù)器,然后接受確認(rèn)信息等,產(chǎn)生一次交互。
小伙伴接收到信息閱讀也都會收到服務(wù)器端通知,產(chǎn)生一次交互等。
可以確定,微信發(fā)送消息走TCP長連接方式,因?yàn)椴粚ψ陨頎顟B(tài)數(shù)據(jù)產(chǎn)生影響,應(yīng)該不交換SyncKey。
在低速網(wǎng)絡(luò)下,大概會看到消息發(fā)送中的提示,屬于消息重發(fā)機(jī)制
網(wǎng)絡(luò)不好有時(shí)客戶端會出現(xiàn)發(fā)送失敗的紅色感嘆號
已發(fā)送到服務(wù)器但未收到確認(rèn)的消息,客戶端顯示紅色感嘆號,再次重發(fā),服務(wù)器作為重復(fù)消息處理,反饋確認(rèn)
上傳圖片,會根據(jù)圖片大小,分割成若干部分(大概1.5K被劃分為一部分),同一時(shí)間點(diǎn),客戶端會發(fā)起若干次POST請求,各自上傳成功之后,服務(wù)器大概會合并成一個(gè)完整圖片,返回一個(gè)縮略圖,顯示在APP聊天窗口內(nèi)。APP作為常規(guī)的文字消息發(fā)送到服務(wù)器端上傳音頻,則單獨(dú)走TCP通道,一個(gè)兩秒的錄制音頻,客戶端錄制完畢,分為兩塊傳輸,一塊最大1.5K左右,服務(wù)端響應(yīng)一條數(shù)據(jù)通知確認(rèn)收到。共三次數(shù)據(jù)傳輸。音頻和純文字信息一致,都是走TCP長連接,客戶端發(fā)送,服務(wù)器端確認(rèn)。
四。微信協(xié)議小結(jié)
發(fā)布的消息對應(yīng)一個(gè)ID(只要單個(gè)方向唯一即可,服務(wù)器端可能會根ID判斷重復(fù)接收),消息重傳機(jī)制確保有限次的重試,重試失敗給予用戶提示,發(fā)送成功會反饋確認(rèn),客戶端只有收到確認(rèn)信息才知道發(fā)送成功。發(fā)送消息可能不會產(chǎn)生新SyncKey。
基于版本號(SynKey)的狀態(tài)消息同步機(jī)制,增量、有序傳輸需求水到渠成。長連接通知/短連接獲取、確認(rèn)等,交互方式簡單,確保了消息可靠譜、準(zhǔn)確無誤到達(dá)。
客戶端/服務(wù)器端都會存儲消息ID處理記錄,避免被重復(fù)消費(fèi)客戶端獲取最新消息,但未確認(rèn),服務(wù)器端不會認(rèn)為該消息被消費(fèi)掉。下次客戶端會重新獲取,會查詢當(dāng)前消息是否被處理過。根據(jù)一些現(xiàn)象猜測。
總體上看,微信協(xié)議跨平臺(TCP或HTPP都可呈現(xiàn),處理方式可統(tǒng)一),通過“握手”同步,很可靠,無論哪一個(gè)平臺都可以支持的很好微信協(xié)議最小成本為16字節(jié),大部分時(shí)間若干個(gè)消息包和在一起,批量傳輸。微信協(xié)議說不上最簡潔,也不是最節(jié)省流量,但是非常成功的。
若服務(wù)器檢測到一些不確定因素,可能會導(dǎo)致微啟用安全套接層SSL協(xié)議進(jìn)行常規(guī)的TCP長連接傳輸。短連接都沒有發(fā)生變化
以上,根據(jù)有限資料和數(shù)據(jù)攔截觀察總結(jié)得出,啰啰嗦嗦,勉強(qiáng)湊成一篇,會存在一些不正確之處,歡迎給予糾正。在多次
五。附錄
Microsoft Exchange Active Sync協(xié)議,簡稱EAS,分為folderrsync(同步文件夾目錄,即郵箱內(nèi)有哪幾個(gè)文件夾)和sync(每個(gè)文件夾內(nèi)有哪些文檔)兩部分。
某網(wǎng)友總結(jié)的協(xié)議一次回話大致示范:
Client: synckey=0 //第一次key為0
Server: newsynckey=1235434 //第一次返回新key
Client: synckey=1235434 //使用新key查詢
Server: newsynckey=1647645,data=*****//第一次查詢,得到新key和數(shù)據(jù)
Client: synckey=1647645
Server: newsynckey=5637535,data=null //第二次查詢,無新消息
Client: synckey=5637535
Server: newsynckey=8654542, data=****//第三次查詢,增量同步
上頁中的相鄰請求都是隔固定時(shí)間的,如兩分鐘
客戶端每次使用舊key標(biāo)記自己的狀態(tài),服務(wù)端每次將新key和增量數(shù)據(jù)一起返回。
key是遞增的,但不要求連續(xù)
請求的某個(gè)參數(shù)決定服務(wù)器是否立即返回
相關(guān)文章
JS實(shí)現(xiàn)即點(diǎn)即編輯功能代碼
以前在網(wǎng)上都看到過類似的功能,不過沒自己想要實(shí)現(xiàn)過,這次剛好做靜態(tài)頁面中有這樣的一個(gè)需求,就試著自己做做看,做完發(fā)現(xiàn)也不是什么很難的事情。2008-10-10基于JS實(shí)現(xiàn)EOS隱藏錯(cuò)誤提示層代碼
本文給大家分享一段代碼基于js實(shí)現(xiàn)EOS隱藏錯(cuò)誤提示層,對eos隱藏提示層的相關(guān)知識感興趣的朋友一起學(xué)習(xí)吧2016-04-04ts依賴引入報(bào)錯(cuò):無法找到模塊“xxxxxx”的聲明文件問題解決
這篇文章主要給大家介紹了關(guān)于ts依賴引入報(bào)錯(cuò):無法找到模塊“xxxxxx”的聲明文件問題的解決辦法,文中通過示例帶將解決辦法介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07基于JavaScript實(shí)現(xiàn)淘寶商品廣告效果
這篇文章主要為大家詳細(xì)介紹了基于JavaScript實(shí)現(xiàn)淘寶商品廣告效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08