Jack Jiang

          我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
          posts - 506, comments - 13, trackbacks - 0, articles - 1

          1、點(diǎn)評(píng)

          IM聊天消息的可靠投遞,是每個(gè)線上產(chǎn)品都要考慮的IM熱點(diǎn)技術(shù)問(wèn)題。

          IM聊天消息能保證可靠送達(dá),對(duì)于用戶來(lái)說(shuō),就好比把錢(qián)存在銀行不怕被偷一樣,是信任的問(wèn)題。試想,如果用戶能明顯感知到聊天消息無(wú)法保證送達(dá),誰(shuí)還愿意來(lái)用你的APP?誰(shuí)也不希望自已的話就像浮云一樣隨風(fēng)飄逝。

          必竟用IM聊天,雖然很多時(shí)候是費(fèi)話,但總有關(guān)鍵時(shí)刻存在——比如向女神表白(哪怕明知被拒),作為合格的舔狗一定不希望女神錯(cuò)過(guò)這條消息。

          所以,消息的可靠投遞是每款I(lǐng)M產(chǎn)品和立足之本,也是IM開(kāi)發(fā)者們孜孜不倦追求的技術(shù)目標(biāo)。

          本文作者將以自已IM開(kāi)發(fā)過(guò)程中的真實(shí)總結(jié),分享針對(duì)大量離線聊天消息,在確保用戶端體驗(yàn)不降級(jí)的前提下,保證離線消息的可靠投遞。

          學(xué)習(xí)交流:

          - 即時(shí)通訊/推送技術(shù)開(kāi)發(fā)交流5群:215477170[推薦]

          - 移動(dòng)端IM開(kāi)發(fā)入門(mén)文章:《新手入門(mén)一篇就夠:從零開(kāi)發(fā)移動(dòng)端IM

          本文已同步發(fā)布于“即時(shí)通訊技術(shù)圈”公眾號(hào),歡迎關(guān)注:

          ▲ 本文在公眾號(hào)上的鏈接是:https://mp.weixin.qq.com/s/T2w9h_AN_T2UnqNdVikX0Q,原文鏈接是:http://www.52im.net/thread-3069-1-1.html

           

          2、本文作者 

          fzully(柳林勇):2005年數(shù)學(xué)系畢業(yè),先后就職于福建新大陸、福建富士通、北京世紀(jì)奧通。長(zhǎng)期從事服務(wù)端軟件開(kāi)發(fā),涉及SIP服務(wù)器、內(nèi)核RTP轉(zhuǎn)送、電信級(jí)AAA認(rèn)證系統(tǒng)、IM即時(shí)通訊系統(tǒng)等。在分布式高性能系統(tǒng)設(shè)計(jì)有多年經(jīng)驗(yàn)積累。

          本作者的另一篇:《IM群聊消息的已讀未讀功能在存儲(chǔ)空間方面的實(shí)現(xiàn)思路探討》也已被即時(shí)通訊網(wǎng)收錄并整理發(fā)布,有興趣可以前往閱讀。

          3、相關(guān)文章

          從客戶端的角度來(lái)談?wù)勔苿?dòng)端IM的消息可靠性和送達(dá)機(jī)制

          移動(dòng)端IM中大規(guī)模群消息的推送如何保證效率、實(shí)時(shí)性?

          IM消息送達(dá)保證機(jī)制實(shí)現(xiàn)(一):保證在線實(shí)時(shí)消息的可靠投遞

          IM消息送達(dá)保證機(jī)制實(shí)現(xiàn)(二):保證離線消息的可靠投遞》(* 強(qiáng)烈推薦

          如何保證IM實(shí)時(shí)消息的“時(shí)序性”與“一致性”?

          一個(gè)低成本確保IM消息時(shí)序的方法探討

          IM群聊消息如此復(fù)雜,如何保證不丟不重?》(* 強(qiáng)烈推薦

          移動(dòng)端IM登錄時(shí)拉取數(shù)據(jù)如何作到省流量?》(* 強(qiáng)烈推薦

          完全自已開(kāi)發(fā)的IM該如何設(shè)計(jì)“失敗重試”機(jī)制?

          IM開(kāi)發(fā)干貨分享:我是如何解決大量離線消息導(dǎo)致客戶端卡頓的》(* 強(qiáng)烈推薦

          4、正文引言

          暗戀女神良久,終于鼓起勇氣決定向女神寫(xiě)一封情書(shū)。但如何表達(dá)才能感動(dòng)女神?自感才疏學(xué)淺,于是通讀四書(shū)五經(jīng)、熟背唐詩(shī)宋詞、遍覽四大名著,已然腹有詩(shī)書(shū)氣自華。一周末冥思苦想整日才寫(xiě)就一首七言律詩(shī),雖無(wú)驚天地泣鬼神之勢(shì),但誠(chéng)摯的愛(ài)念在字里行間里流淌,亦歌亦詩(shī),相信會(huì)感動(dòng)到女神,手機(jī)欣然發(fā)出。

          發(fā)出一秒后,手心冒汗,感覺(jué)臉頰發(fā)燙,心臟像受驚嚇的野兔一樣快速跳動(dòng),就像第一次看見(jiàn)女神那時(shí)的感覺(jué)。閉著眼睛,想象女神看到消息時(shí)的情形,她是否也期盼我的表白?看到消息時(shí)是否心跳加速、小臉緋紅?

          一分鐘后,緊盯手機(jī)屏幕,等待、期盼女神回復(fù)。

          時(shí)間一分一秒地逝去,等一分鐘像等一年一樣漫長(zhǎng)。

          一小時(shí)后,仍然杳無(wú)音訊,難道她沒(méi)看到消息么?或許在忙什么而沒(méi)留意手機(jī)吧!

          一天過(guò)去了,坐立不安,等待是一種痛苦的煎熬,期待和煎熬在心中交織翻滾,有幾個(gè)瞬間甚至希望女神趕快拒絕自己,好讓自己解脫!茶飯無(wú)味,失眠多天,整日魂不守舍。

          一個(gè)月過(guò)去了,死心。

          半年后,女神出嫁,婚禮那天前去祝福。席間亦隨眾觥籌交錯(cuò),略有醉意,向女神敬酒:祝福你,但愿以后能遇見(jiàn)像你這樣的女人。女神先是愣住、收起笑容,低下頭,目光無(wú)神地看著大紅地毯,長(zhǎng)嘆一聲,言:我等你表白,等了一年!空氣凝滯了幾秒,女神強(qiáng)作歡顏:從今往后,各自安好吧,干杯!

          我轉(zhuǎn)身踱回到座位,拿起手機(jī),打開(kāi)那個(gè)App,看著曾經(jīng)發(fā)出的情書(shū),一切仿佛還在昨日,但故事腳本已被別人書(shū)寫(xiě),欲哭無(wú)淚,嘆老天為何如此捉弄我?為何我發(fā)的消息女神沒(méi)收到啊!

          失魂落魄地回到家里,從冰箱里拿出幾瓶羅斯福10號(hào)來(lái)麻醉自己,在酒精強(qiáng)烈的作用下,迷迷入睡。

          第二天醒來(lái),我明白了一個(gè)道理:對(duì)IM系統(tǒng)而言,消息必達(dá)永遠(yuǎn)擺在第一位!

          以上是胡說(shuō)八道,以下開(kāi)始正文。。。

          5、用全量離線消息實(shí)現(xiàn)消息必達(dá)

          我們?cè)谥貥?gòu)IM系統(tǒng)時(shí),需解決上一代設(shè)計(jì)的痛點(diǎn)之一就是確保消息必達(dá)。

          5.1 離線消息實(shí)現(xiàn)消息必達(dá)的流程

          自然而然地會(huì)想到這么做——即由服務(wù)端為每個(gè)人保存一個(gè)“離線消息列表”。

          具體的思路是這樣:

          • 1)當(dāng)用戶在線時(shí),由IMS主動(dòng)確保消息下發(fā)且收到客戶端的應(yīng)答確認(rèn)時(shí),才認(rèn)為消息送達(dá)客戶端,相應(yīng)地把消息從“離線消息列表”移除;
          • 2)如果客戶端沒(méi)有發(fā)回應(yīng)答確認(rèn),IM服務(wù)端會(huì)再發(fā)送。

          以此來(lái)確保消息一定送到客戶端,看起來(lái)是很符合邏輯。當(dāng)時(shí)調(diào)查過(guò)市面上多款I(lǐng)M,行為基本如此。

          5.2 海嘯般的離線消息

          5.2.1)和平時(shí)期:

          重構(gòu)后的IM上線,內(nèi)部測(cè)試及在公網(wǎng)運(yùn)行,離線消息的工作一直很正常。

          5.2.2)被簽到簽死了:

          后來(lái),為某客戶部署的私有環(huán)境,其用戶量達(dá)幾十萬(wàn),其中的一個(gè)組織接近三萬(wàn)人,全員群也接近三萬(wàn)人;還有,底下的部門(mén)也有相應(yīng)的群組,幾百到幾千人群不等。

          “報(bào)到”、“簽到”。。。大量的類似消息被發(fā)到幾千、幾萬(wàn)人的群內(nèi),然后如果有人一兩天沒(méi)上線,或者被加入到多個(gè)組織內(nèi),等到其上線時(shí),幾萬(wàn)條離線消息像海嘯一般涌來(lái),您想象一下:手機(jī)用戶剛登陸的幾分鐘內(nèi),是什么場(chǎng)景?

          用戶真的很無(wú)辜:我不就是登陸了一下App,叮叮咚咚響了幾分鐘,還卡,還發(fā)熱。。。

          客戶端承受不起大規(guī)模離線消息的轟炸,怎么辦?

          5.3 臨時(shí)運(yùn)用方案

          • 1)對(duì)若干大組織的全員群,對(duì)非管理員禁言;
          • 2)通知所有用戶不要在大群簽到。

          我承認(rèn),這確實(shí)不算是個(gè)正經(jīng)方案。。。

          6、遠(yuǎn)離全量離線消息

          我承認(rèn),一開(kāi)始設(shè)計(jì)離線消息時(shí),真沒(méi)想到是這樣的使用場(chǎng)景。對(duì)于大多數(shù)IM的開(kāi)發(fā)者,或許不會(huì)碰到這種場(chǎng)景(但凡事住最壞的可能性想,總是沒(méi)錯(cuò)的)。

          6.1 放棄以離線消息的形式實(shí)現(xiàn)消息必達(dá)

          我開(kāi)始思考什么是消息必達(dá),以前的想法是:把用戶該收的消息都送到其客戶端,是消息必達(dá)。

          后來(lái),給消息必達(dá)下了新的定義:

          • 1)用戶有新消息時(shí),確保讓用戶知道;
          • 2)當(dāng)用戶要查看這些消息時(shí),確保其可一條不漏地看到。

          打個(gè)比方:

          • 1)客戶要把錢(qián)給您,不必送到您家里才算送到;
          • 2)而是轉(zhuǎn)賬到您的銀行賬戶上,并告知您;
          • 3)當(dāng)您要用錢(qián)時(shí),直接從銀行賬戶上消費(fèi)即可。

          從此,不會(huì)在用戶上線時(shí)向其發(fā)送大量離線消息(即全量推送)。

          6.2 以會(huì)話列表為基礎(chǔ)來(lái)實(shí)現(xiàn)消息必達(dá)

          客戶端在上線時(shí),先從服務(wù)端更新會(huì)話列表,也就是你通常在每個(gè)IM客戶端的首頁(yè)看到的這個(gè)(如下圖所示)。

          上圖引用自《IM開(kāi)發(fā)快速入門(mén)(一):什么是IM系統(tǒng)?

          每一個(gè)會(huì)話列表項(xiàng)包含如下信息(此處簡(jiǎn)化了與本文無(wú)關(guān)的成員變量):

          {

                  // 會(huì)話對(duì)象的角色類型,比如私聊、群聊、系統(tǒng)通知、業(yè)務(wù)通知。。。

                  uint32  session_role;

                  // 會(huì)話對(duì)象的ID

                  uint32        session_id;

                  // 會(huì)話時(shí)間戳,用于消息同步;

                  // 指會(huì)話的最后操作時(shí)間,比如清除角標(biāo)的時(shí)間,與會(huì)話最后一條的消息時(shí)間未必一致

                  uint64 session_timestamp;

                  // true表示新增或更新,false表示被刪除

                  boolis_add;

           

                  // 當(dāng)is_add=false時(shí),忽略以下信息

           

                  // 僅用于顯示角標(biāo)的未讀數(shù)量,當(dāng)用戶查看該會(huì)話后清零,且客戶端多端同步

                  uint32 new_msg_count;

                  // 會(huì)話的最后一條消息

                  MessageItem         latest_msg;

                  // 跳轉(zhuǎn)消息的時(shí)間戳,即new_msg_count的最舊1條消息的時(shí)間

                  uint64 goto_timestamp;

          }

          為方便討論,假設(shè)以下前提:

          • 1)周五傍晚18:00下班,我關(guān)閉App,我是9527;
          • 2)有1小姐姐向我發(fā)了5條消息留言,約我周末去海邊玩,她是楊冪3306;
          • 3)然后,另1小姐姐也向我發(fā)了33條消息留言,內(nèi)容我不便透露,她是景甜5672;
          • 4)嚴(yán)正聲明:我跟她們很清白,其實(shí)我喜歡的是6379。

          對(duì),既然是假設(shè),假一點(diǎn)也無(wú)妨。

          我下班回到家,看到手機(jī)有通知欄消息,打開(kāi)App將會(huì)發(fā)生哪些事呢?

          App和IM后端的交互:

          1)登錄后,App以18:00填充參數(shù)latest_session_time,向IMS獲取會(huì)話列表(其實(shí)不是以下線時(shí)間18:00,但這樣更易理解);

          2)IM后端檢查發(fā)現(xiàn)我從18:00開(kāi)始,有2個(gè)會(huì)話更新了,于是向App發(fā)送應(yīng)答,以增量形式攜帶2個(gè)會(huì)話項(xiàng):楊冪3306,景甜5672。其中景甜5672的會(huì)話項(xiàng)信息如下:

          {

                  uint32  session_role = Role_User; //表示私聊

                  uint32        session_id = 5672; //景甜的ID

                  uint64  session_timestamp = 1594464295335672; //最后一條消息的時(shí)間戳,微秒

                  boolis_add = true; // true表示是更新項(xiàng)

                  uint32  new_msg_count = 33; // 景甜向我發(fā)了33條消息

                  MessageItem         latest_msg = "房號(hào)是0520"; //最后1條消息,結(jié)構(gòu)體MessageItem簡(jiǎn)略不表

                  uint64  goto_timestamp = 1594463697556677; // 向我發(fā)的33條消息的最早1條的時(shí)間

          }

          3)App收到步驟2的應(yīng)答,我在App的會(huì)話列表窗口里,能看到2項(xiàng)更新,景甜發(fā)來(lái)的未讀消息數(shù)33條,楊冪的是5條,如下圖所示:

           

          4)點(diǎn)開(kāi)景甜5672的會(huì)話,App將向IMS發(fā)起同步消息的請(qǐng)求,獲取最新的10條聊天消息(為了顯示一屏):

          {

                  uint32  session_role = Role_User; //表示私聊

                  uint32        session_id = 5672; //景甜的ID

                  uint64        begin_time  = 1594464295335672; //步驟2返回的session_timestamp

                  uint64        end_time  = 1594434153444222; //景甜上午向我發(fā)的最后一條消息的時(shí)間

                  uint32        max_pieces = 10; //本次最多取10條,PC屏幕大則不妨取20條

          }

          5)IM后端收到步驟4請(qǐng)求,將返回33條新消息的最后10條給App,呈現(xiàn)聊天窗口內(nèi),且聊天窗口上方有一個(gè)tip:“↑ 33條新消息”,如下圖所示:

           
           

          6)我可以向上翻動(dòng)聊天記錄,那么App將持續(xù)向IMS獲取第2批同步消息;或者也可以點(diǎn)擊tip:“↑ 33條新消息”,直接跳轉(zhuǎn)到33條消息的最舊一條,這樣支持從最舊的消息向新的翻看。

          相比于客戶端簡(jiǎn)單地被動(dòng)接收服務(wù)端的離線通知方式,這種設(shè)計(jì)使得客戶端的處理邏輯更復(fù)雜。

          主要體現(xiàn)在:

          • 1)客戶端向服務(wù)端取的同步消息是未必完整,這些存在客戶端的消息,在時(shí)間區(qū)間上可能不連續(xù)的;
          • 2)客戶端需要知道不同消息之間是否有斷代,如果有則需要向服務(wù)端查詢同步消息來(lái)merge本地信息,使其連續(xù),即客戶端要實(shí)現(xiàn)消息融合。

          我的建議:用C++實(shí)現(xiàn)一個(gè)統(tǒng)一的底層imsdk庫(kù),來(lái)負(fù)責(zé)這些共通的消息處理和存儲(chǔ)。避免各客戶端(Windows,iOS,Android等)各自實(shí)現(xiàn)這些邏輯,減少工作量,也降低各端不一致的風(fēng)險(xiǎn)。

          6.3 以會(huì)話列表為基礎(chǔ)與用全量離線消息的方案對(duì)比

          6.3.1)用全量離線消息實(shí)現(xiàn)的方案優(yōu)缺點(diǎn):

          實(shí)現(xiàn)原理:由IM服務(wù)端確保消息送達(dá)客戶端,客戶端存儲(chǔ)后發(fā)回確認(rèn)。

          方案優(yōu)點(diǎn):邏輯簡(jiǎn)單。

          在聊天消息不同數(shù)量級(jí)時(shí)的表現(xiàn):

          • a. 離線消息量不多(如幾百條):沒(méi)有效率問(wèn)題,且消息全部達(dá)到客戶端本地,方便進(jìn)行查找等動(dòng)作;
          • b. 離線消息量巨大(如幾萬(wàn)條):用戶登錄瞬間CS間瞬時(shí)流量大,客戶端瞬時(shí)要存儲(chǔ)、更新的數(shù)據(jù)量巨大,可能出現(xiàn)卡頓、假死等情況。

          6.3.2)用會(huì)話列表為基礎(chǔ)的方案優(yōu)缺點(diǎn):

          實(shí)現(xiàn)原理:客戶端先同步會(huì)話列表,由用戶驅(qū)動(dòng)不定次獲取同步消息。

          方案缺點(diǎn):邏輯復(fù)雜,客戶端增加不少工作。

          在聊天消息不同數(shù)量級(jí)時(shí)的表現(xiàn):

          • a. 離線消息量不多(如幾百條):沒(méi)優(yōu)勢(shì);
          • b. 離線消息量巨大(如幾萬(wàn)條):登錄時(shí)交互數(shù)據(jù)小,對(duì)IM后端、客戶端、用戶體驗(yàn),都比較友好。

          7、多終端條件下,如何得到完整消息履歷?

          由于同一個(gè)用戶的每個(gè)終端,其會(huì)話最后更新時(shí)間、每個(gè)會(huì)話的最后一條時(shí)間可能都不一樣,參照上一節(jié)的實(shí)現(xiàn)思路,可以得到解決方案。

          具體如下:

          • 1)參照第6.2章節(jié)的“App和IM后端的交互”第1個(gè)步驟,可取到不同的增量變化的會(huì)話列表項(xiàng);
          • 2)參照第6.2章節(jié)的“App和IM后端的交互”第4個(gè)步驟,可取到任一區(qū)間的同步消息,得到完整消息。

          8、離線消息是否就徹底廢棄了?

          有若干情況,仍然需要保留離線消息,以確保消息送達(dá)。

          比如以下情形:

          • 1)別人向我發(fā)送離線文件:這種情況下不能依賴同步消息來(lái)獲取。因?yàn)椴灰噪x線消息通知的話,用戶在沒(méi)有拉取到對(duì)應(yīng)的同步消息前,是不知道有離線文件的;
          • 2)撤回消息:即使接收者不拉取同步,仍然要保證在上線后其數(shù)據(jù)在第一時(shí)間被撤回。注意:這里可能存在多端撤回問(wèn)題;
          • 3)用戶在線時(shí)的消息下發(fā):由于用戶在線時(shí),IM后端向客戶端發(fā)送消息可能碰到網(wǎng)絡(luò)抖動(dòng)等情況,導(dǎo)致消息下發(fā)失敗,這些消息先可以直接存在離線消息隊(duì)列,IM后端可在收到客戶端的心跳包時(shí)重發(fā)消息。相當(dāng)于維護(hù)了一個(gè)在線消息的離線隊(duì)列。

          9、本文結(jié)語(yǔ)

          曾經(jīng)有一段真摯的愛(ài)情擺在我面前,如果時(shí)間倒流到半年前,我會(huì)選擇一個(gè)靠譜的IM來(lái)發(fā)送消息,也許故事的腳本就由自己書(shū)寫(xiě)——是否要整一個(gè)時(shí)光倒流的版本,抱得美人歸的那種?

          不整了不整了,我得不到女神,你們才歡喜,我太了解你們了。。。各位爺歡喜就好。

          附錄:IM開(kāi)發(fā)干貨系列文章

          本文是系列文章中的第26篇,總目錄如下:

          IM消息送達(dá)保證機(jī)制實(shí)現(xiàn)(一):保證在線實(shí)時(shí)消息的可靠投遞

          IM消息送達(dá)保證機(jī)制實(shí)現(xiàn)(二):保證離線消息的可靠投遞

          如何保證IM實(shí)時(shí)消息的“時(shí)序性”與“一致性”?

          IM單聊和群聊中的在線狀態(tài)同步應(yīng)該用“推”還是“拉”?

          IM群聊消息如此復(fù)雜,如何保證不丟不重?

          一種Android端IM智能心跳算法的設(shè)計(jì)與實(shí)現(xiàn)探討(含樣例代碼)

          移動(dòng)端IM登錄時(shí)拉取數(shù)據(jù)如何作到省流量?

          通俗易懂:基于集群的移動(dòng)端IM接入層負(fù)載均衡方案分享

          淺談移動(dòng)端IM的多點(diǎn)登陸和消息漫游原理

          IM開(kāi)發(fā)基礎(chǔ)知識(shí)補(bǔ)課(一):正確理解前置HTTP SSO單點(diǎn)登陸接口的原理

          IM開(kāi)發(fā)基礎(chǔ)知識(shí)補(bǔ)課(二):如何設(shè)計(jì)大量圖片文件的服務(wù)端存儲(chǔ)架構(gòu)?

          IM開(kāi)發(fā)基礎(chǔ)知識(shí)補(bǔ)課(三):快速理解服務(wù)端數(shù)據(jù)庫(kù)讀寫(xiě)分離原理及實(shí)踐建議

          IM開(kāi)發(fā)基礎(chǔ)知識(shí)補(bǔ)課(四):正確理解HTTP短連接中的Cookie、Session和Token

          IM群聊消息的已讀回執(zhí)功能該怎么實(shí)現(xiàn)?

          IM群聊消息究竟是存1份(即擴(kuò)散讀)還是存多份(即擴(kuò)散寫(xiě))?

          IM開(kāi)發(fā)基礎(chǔ)知識(shí)補(bǔ)課(五):通俗易懂,正確理解并用好MQ消息隊(duì)列

          一個(gè)低成本確保IM消息時(shí)序的方法探討

          IM開(kāi)發(fā)基礎(chǔ)知識(shí)補(bǔ)課(六):數(shù)據(jù)庫(kù)用NoSQL還是SQL?讀這篇就夠了!

          IM里“附近的人”功能實(shí)現(xiàn)原理是什么?如何高效率地實(shí)現(xiàn)它?

          IM開(kāi)發(fā)基礎(chǔ)知識(shí)補(bǔ)課(七):主流移動(dòng)端賬號(hào)登錄方式的原理及設(shè)計(jì)思路

          IM開(kāi)發(fā)基礎(chǔ)知識(shí)補(bǔ)課(八):史上最通俗,徹底搞懂字符亂碼問(wèn)題的本質(zhì)

          IM的掃碼登功能如何實(shí)現(xiàn)?一文搞懂主流應(yīng)用的掃碼登陸技術(shù)原理

          IM要做手機(jī)掃碼登陸?先看看微信的掃碼登錄功能技術(shù)原理

          IM開(kāi)發(fā)基礎(chǔ)知識(shí)補(bǔ)課(九):想開(kāi)發(fā)IM集群?先搞懂什么是RPC!

          IM開(kāi)發(fā)實(shí)戰(zhàn)干貨:我是如何解決大量離線聊天消息導(dǎo)致客戶端卡頓的

          IM開(kāi)發(fā)干貨分享:如何優(yōu)雅的實(shí)現(xiàn)大量離線消息的可靠投遞》(* 本文)

          另外,如果您是IM開(kāi)發(fā)初學(xué)者,強(qiáng)烈建議首先閱讀《新手入門(mén)一篇就夠:從零開(kāi)發(fā)移動(dòng)端IM》。

          (本文同步發(fā)布于:http://www.52im.net/thread-3069-1-1.html



          作者:Jack Jiang (點(diǎn)擊作者姓名進(jìn)入Github)
          出處:http://www.52im.net/space-uid-1.html
          交流:歡迎加入即時(shí)通訊開(kāi)發(fā)交流群 215891622
          討論:http://www.52im.net/
          Jack Jiang同時(shí)是【原創(chuàng)Java Swing外觀工程BeautyEye】【輕量級(jí)移動(dòng)端即時(shí)通訊框架MobileIMSDK】的作者,可前往下載交流。
          本博文 歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處(也可前往 我的52im.net 找到我)。


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          Jack Jiang的 Mail: jb2011@163.com, 聯(lián)系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 修水县| 哈尔滨市| 长垣县| 河源市| 余姚市| 永春县| 略阳县| 如皋市| 灵寿县| 富裕县| 镇雄县| 哈巴河县| 桑植县| 甘洛县| 鄂托克前旗| 乳山市| 安吉县| 平陆县| 苗栗市| 岗巴县| 高要市| 全椒县| 鄂伦春自治旗| 鹤岗市| 班戈县| 庐江县| 巴楚县| 河源市| 六枝特区| 广饶县| 丹棱县| 赤壁市| 镇原县| 山东省| 合作市| 尉氏县| 丰宁| 广宗县| 灵宝市| 信阳市| 宁都县|