国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

TCP編程問題總結(jié)!

發(fā)布時間:2020-4-9 11:08    發(fā)布者:嵌入式人生17
TCP編程問題總結(jié)!
先來復(fù)習(xí)一下TCP/IP五層模型:從上到下依次是應(yīng)用層、傳輸層、網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層、物理層;我們會接觸到的是應(yīng)用層、傳輸層、網(wǎng)絡(luò)層。
這三層是干啥的?以下是來自《計算機(jī)網(wǎng)絡(luò)——自頂向下方法》這本書的筆記(是一本好書,深入淺出,把復(fù)雜的概念講的很容易懂,不同于大學(xué)時那些味同嚼蠟的課本)。
網(wǎng)絡(luò)層
網(wǎng)絡(luò)層提供主機(jī)到主機(jī)的通信服務(wù),即從一個IP地址到另一個IP地址的數(shù)據(jù)傳輸,網(wǎng)絡(luò)層分為數(shù)據(jù)平面和控制平面。
數(shù)據(jù)平面主要作用是從其輸入鏈路向其輸出鏈路轉(zhuǎn)發(fā)數(shù)據(jù);
控制平面作用是協(xié)調(diào)這些本地的每個路由器轉(zhuǎn)發(fā)動作,使得數(shù)據(jù)報沿著源和目的地主機(jī)之間的路由器路徑最終進(jìn)行端到端傳送,簡單說,控制平面的作用就是路由選擇。計算轉(zhuǎn)發(fā)路徑的算法稱為路由選擇算法。
作者舉了個例子來說明數(shù)據(jù)平面和控制平面,一個人駕車從賓夕法尼亞州到佛羅里達(dá)州,轉(zhuǎn)發(fā)就是經(jīng)過立交橋的過程,從立交橋的一個入口進(jìn)入立交橋然后從一個出口離開立交橋走上了另一條路;而控制平面路由選擇就是著手行程之前規(guī)劃路線的過程,查閱地圖,從許多可能路線中選擇一條。
傳輸層(又叫運輸層)
為運行在不同主機(jī)的應(yīng)用進(jìn)程提供邏輯通信,網(wǎng)絡(luò)層為主機(jī)之間提供了邏輯通信,報文到達(dá)主機(jī)后,是傳輸層協(xié)議將報文定向到不同進(jìn)程的。
作者舉了一個很有意思的例子:有兩個家庭AB,每家有12個孩子,他們每個人每星期都要給對方家庭12個小孩寫信,那每周有144封信件往來,每星期A家庭由Ann來為大家收集信件并投遞到郵車上,信件到時,Ann再把信件一封封分給兄弟姐妹,B家庭由Bill來做這個工作。AnnBill做的事情就是傳輸層做的事。這個例子中:
家庭=主機(jī)
兄弟姐妹 =進(jìn)程
運輸層協(xié)議 = Ann或者Bill
網(wǎng)絡(luò)層協(xié)議= 郵政服務(wù)(包括郵車)
信封上的字符 = 應(yīng)用層報文
舉個例子電腦上跑著好幾個網(wǎng)絡(luò)應(yīng)用,瀏覽器、網(wǎng)易云音樂、迅雷下載等,到達(dá)電腦的數(shù)據(jù)怎么知道是給哪個應(yīng)用進(jìn)程的?這就是傳輸層要做的事。
傳輸層通過什么來區(qū)分不同進(jìn)程?socket端口號。
上面的兩個例子都很妙對不對?
傳輸層的協(xié)議分為TCP和UDP,TCP是面向連接的保證數(shù)據(jù)可靠到達(dá)的通信協(xié)議(是一個負(fù)責(zé)任的信件分發(fā)員,除了把到達(dá)主機(jī)的數(shù)據(jù)分給不同進(jìn)程還有很多附加服務(wù)),UDP是面向無連接的不可靠的數(shù)據(jù)報文協(xié)議(只提供最基本分發(fā)服務(wù),只管把到達(dá)主機(jī)的數(shù)據(jù)分發(fā)一下,收沒收到不管)。
那TCP是怎么保證數(shù)據(jù)可靠到達(dá)的?簡單說他把要傳輸?shù)臄?shù)據(jù),分成一個一個包裹,每個包裹編號,按順序發(fā),不斷傳輸?shù)臄?shù)據(jù)包形成數(shù)據(jù)流,每個編號的數(shù)據(jù)包到達(dá)后對方發(fā)送ACK,發(fā)送方收到對方的ACK才認(rèn)為這包數(shù)據(jù)成功發(fā)出去了,數(shù)據(jù)發(fā)送的數(shù)據(jù)包序號窗體往后滑。實際并不是這么簡單還有很多內(nèi)容。
應(yīng)用層就不說了。
下面總結(jié)幾個TCP通信遇到過的問題。
1  數(shù)據(jù)到達(dá)的次序不是預(yù)期
遇到過一個這樣的問題,有一款洗衣機(jī),一定要先開機(jī),才能再設(shè)置洗衣的模式,調(diào)試時發(fā)現(xiàn)APP明明是先發(fā)開機(jī)指令,再發(fā)設(shè)置模式,但家電端wifi板總是先收到設(shè)置模式,再收到開機(jī)指令。
分析發(fā)現(xiàn),APP是把數(shù)據(jù)按順序發(fā)給了服務(wù)器,但是服務(wù)器會按順序一條一條發(fā)給wifi板嗎?并不是,服務(wù)器是一對多同時與成千上萬的設(shè)備通信的,有手機(jī)APP用戶,有家電wifi,所以他通常是并發(fā)的,也就是會把消息分給很多個線程同時處理,比如這里APP發(fā)來的控制消息應(yīng)該是分給了兩個線程同時處理,應(yīng)用層2個線程同時向傳輸層丟數(shù)據(jù),這兩包數(shù)據(jù)指向同一個IP同一個端口(即家電wifi板),傳輸層只有一個,那不同線程的數(shù)據(jù)誰先傳下來誰就排在前面了,所以造成了先發(fā)的不一定先到的現(xiàn)象。
那這個問題后來怎么解決的?APP把開關(guān)機(jī)和設(shè)模式一起發(fā)下來由wifi板端來處理,首先檢索有沒有開關(guān)機(jī)消息,有的話去執(zhí)行開關(guān)機(jī),再檢索有沒有設(shè)模式。
2  數(shù)據(jù)分多次連著到達(dá)
這是TCP編程要考慮的基本問題,理想的情況是APP發(fā)一條完整消息,wifi板收到一條完整消息。但在測試時發(fā)現(xiàn),對著APP點擊空調(diào)開關(guān)機(jī)鍵,不斷的開關(guān)開關(guān),點個20次左右,APP上最后顯示是開空調(diào)最后是關(guān),或者APP上最后是關(guān)空調(diào)最后是開(這個測試是不是很變態(tài)?)
分析log發(fā)現(xiàn)是最后一條控制消息分兩次到達(dá)了,tcp傳輸層是數(shù)據(jù)流傳輸,發(fā)送方的傳輸層不會管應(yīng)用層傳下來是什么數(shù)據(jù),他只會把數(shù)據(jù)分裝成一個一個小包裹往外發(fā),接收方的傳輸層也不會管對方發(fā)來的數(shù)據(jù)里面具體是什么,收到多少就傳多少給應(yīng)用層。
我們當(dāng)時的TCP數(shù)據(jù)處理程序不完善,無法處理一條消息分兩次到達(dá)的情況,如果消息分兩次到達(dá),第一次收到的片段不符合應(yīng)用層協(xié)議格式就被丟棄掉了,第二次到達(dá)的也被丟棄掉了。
一個完善的tcp數(shù)據(jù)處理程序應(yīng)該:
(1)最基本能處理一條完整到達(dá)的消息;
(2)好幾條消息一起收到,能一條一條處理完;
(3)好幾條完整消息+一段殘缺的消息片段,能把前面完整的一條一條處理完,再把殘缺的消息片段存入緩存,等著下次或下幾次收到剩下的消息片段組成一條完整消息再處理;
(4)只有一段殘缺的消息片段,存入緩存,與下次或者下幾次收到的消息組成完整消息再處理。
后來對程序做了完善,消息存在一個循環(huán)隊列里處理,bug解除了。
3快速點擊APP時發(fā)現(xiàn)后面執(zhí)行變慢
還是上面那個變態(tài)的測試,不斷的點APP上的開關(guān)按鈕,測試的人反應(yīng)說一開始空調(diào)反應(yīng)很快,為什么點了10次以上之后,反應(yīng)這么慢,也就是APP上已經(jīng)點完了,空調(diào)慢半拍還在那里開關(guān)開關(guān)好久,好像是在自動開關(guān)一樣。
檢查TCP線程,while主循環(huán)里面用了select,當(dāng)select檢測到有數(shù)據(jù)到達(dá)這個socket時,去收數(shù)據(jù)。而select設(shè)置的超時時間是1s,也就是沒數(shù)據(jù)時,最多等待1s才往下走,有數(shù)據(jù)時馬上去收,后來把1s改成了500ms,明顯就快多了!
但我還是有疑問,按理說select函數(shù)并不會耽誤數(shù)據(jù)的處理和收發(fā)啊,因為他是有數(shù)據(jù)馬上返回告訴你有數(shù)據(jù),此時馬上去收,無數(shù)據(jù)等待一個timeout的時間返回,那就應(yīng)該不管timeout時間設(shè)多長都沒關(guān)系才對啊?
4  數(shù)據(jù)分兩次中間隔了一段時間才到
這是最近在wifi+zigbee網(wǎng)關(guān)上出現(xiàn)的一個bug,網(wǎng)關(guān)一頭是wifi連接服務(wù)器,一頭是zigbee接著很多子設(shè)備,比如開關(guān)、水浸、氣感等等,bug的現(xiàn)象是概率性出現(xiàn)場景命令無法執(zhí)行,比如開所有燈或者關(guān)所有燈這樣的場景命令,用戶在APP上點一個場景按鈕,消息下發(fā)到網(wǎng)關(guān)上。
分析log發(fā)現(xiàn),這條消息是分兩次到達(dá)了,兩次到達(dá)中間還隔了2秒,奇怪的是第二段數(shù)據(jù)到達(dá)時前面那一段數(shù)據(jù)被清除掉了,沒有存下來,但是大多數(shù)時候分兩次到達(dá)的消息都能正確處理,為什么單單這一次沒有處理好?這一次跟其他次有什么區(qū)別?
這一次的區(qū)別是,看到收到第一段消息后,發(fā)ping消息的時間到了,給服務(wù)器發(fā)了ping消息(這條消息是應(yīng)用層的心跳消息,30s發(fā)一次,為了保持心跳以及偵測掉線,當(dāng)發(fā)給服務(wù)器的ping消息5s沒收到服務(wù)器回復(fù)認(rèn)為掉線了)然后過了2s才收到第二段消息。
搜索所有清除緩存的地方,發(fā)現(xiàn)就在發(fā)ping消息的地方把緩存清除了!所以造成了消息起那一段丟掉了沒有被正確處理,去掉這個清除動作多次測試沒有再出現(xiàn)這種情況。
這里發(fā)現(xiàn)另外一個問題是:這一次的ping消息沒有收到服務(wù)器回包,因此網(wǎng)關(guān)這邊判斷掉線了,收到的控制消息也沒有再去處理,應(yīng)該怎么設(shè)計掉線的邏輯?
僅僅沒有收到心跳消息回包就認(rèn)為掉線合理不? 此時我們關(guān)注的有用的控制消息是能正常收到的啊!
所以應(yīng)該對判斷掉線的邏輯做一些優(yōu)化:
(1)當(dāng)沒收到ping消息回包但控制消息仍然能收到時不應(yīng)該判斷成掉線,只要還能收到數(shù)據(jù)就不認(rèn)為掉線;
(2)消抖處理,當(dāng)連續(xù)幾次沒有收到ping消息(ping消息30s發(fā)一次)回包時才認(rèn)為掉線。
5  數(shù)據(jù)被意外清除
問題4改了后,提測后結(jié)果又出現(xiàn)了一次場景消息不執(zhí)行,前前后后測了兩百次出現(xiàn)一次,崩潰!憑直覺我覺得這是一個新bug!
分析log,發(fā)現(xiàn)這也是一個分兩次到達(dá)的消息沒有正確處理,第一次到達(dá)的數(shù)據(jù)總共有n條完整的消息+控制消息的前半段,看到最后有去把殘缺消息片段拷貝到緩存中的操作,但是當(dāng)后半段消息收到時,緩存里打印出來卻沒有前半段消息!
拷貝字符串用的是memcpy這個庫函數(shù),要拷貝的字符串長度用的是strlen這個函數(shù)。
把這條出問題的消息再次用測試代碼運行起來,增加log,看代碼怎么跑的,看到確實有去處理前面那些一條一條的完整消息,問題在于,處理的時候直接把主循環(huán)用于接收socket數(shù)據(jù)的緩存指針傳進(jìn)去了,有個地方要計算消息的MD5摘要值與消息中帶下來的MD5摘要值去比較,把字符串中某個位置的字符賦值成了0。
file:///C:\Users\Administrator.WIN-STED6B9V5UI\AppData\Local\Temp\ksohtml18176\wps7.png
這個操作是很危險的!直接導(dǎo)致了后面拷貝殘缺消息片段時strlen計算出來的長度是0,strlen、strstr、strcpy這類字符串處理函數(shù)都是遇到0就停止的。
直接把接收緩存指針傳進(jìn)去,這種操作也不規(guī)范。
修改方法是,對賦值0那個函數(shù)傳進(jìn)去的指針不再是用于接收socket數(shù)據(jù)的緩存指針,而是而是另外開辟緩存,把要處理的數(shù)據(jù)拷貝過去,再把新開辟的緩存指針傳進(jìn)去。
6 socket端口號問題
寫到這好累了,長話短說,與服務(wù)器連接過程如下:
(1)調(diào)用socket 函數(shù),創(chuàng)建一個tcp類型的socket
(2)初始化自己的地址my_addr,類型為sockaddr_in,內(nèi)容包括端口號、類型、IP地址(如下圖);
file:///C:\Users\Administrator.WIN-STED6B9V5UI\AppData\Local\Temp\ksohtml18176\wps8.jpg
(3)調(diào)用bind,把socket 和my_addr綁定起來;
(4)初始化要連接的服務(wù)器地址svr_addr
file:///C:\Users\Administrator.WIN-STED6B9V5UI\AppData\Local\Temp\ksohtml18176\wps9.jpg
(5)調(diào)用connect,連接服務(wù)器
第2步有一個特別要注意的是自己地址的端口號必須是一個不重數(shù),也就是說這次用的是2000,那么下次wifi板再次connect時(比如斷電上電再次connect)不能再用2000,可以是2001依次遞增或者其他。
那么為什么要這樣?因為服務(wù)器偵測wifi板掉線一般是沒有wifi板自身快的,wifi板去重連服務(wù)器時如果用的是原來的端口號,而服務(wù)器那邊還沒偵測出wifi板掉線,原來的那個端口號的tcp鏈接還在,資源沒有釋放,再用原來那個端口號建立新的鏈接肯定不會成功;另一種情況,wifi板斷電上電重新去連服務(wù)器,服務(wù)器肯定是不知道wifi板重啟了,還用原來的端口號去連也是連不上的,除非斷電很久等服務(wù)器偵測出wifi掉線再上電。
所以正確的做法是把端口號存入Flash里,每次用時從flash里取,用完更新這個值。
單片機(jī)方案都不會自己產(chǎn)生不重數(shù),因此需要自己操心存起來, 有些linux系統(tǒng)方案是底層自己會產(chǎn)生不重數(shù)不用自己操心。
7、  沒有 keep alive機(jī)制引發(fā)的問題
好累了,這個有點不記得了,改天完全記起來再補(bǔ)充。今天的分享就到這里 有疑問3250395686

本文地址:http://www.qingdxww.cn/thread-583404-1-1.html     【打印本頁】

本站部分文章為轉(zhuǎn)載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀點和對其真實性負(fù)責(zé);文章版權(quán)歸原作者及原出處所有,如涉及作品內(nèi)容、版權(quán)和其它問題,我們將根據(jù)著作權(quán)人的要求,第一時間更正或刪除。
您需要登錄后才可以發(fā)表評論 登錄 | 立即注冊

廠商推薦

  • Microchip視頻專區(qū)
  • PIC18-Q71系列MCU概述
  • 想要避免發(fā)生災(zāi)難,就用MPLAB® SiC電源仿真器!
  • 5分鐘詳解定時器/計數(shù)器E和波形擴(kuò)展!
  • 了解一下Microchip強(qiáng)大的PIC18-Q24 MCU系列
  • 貿(mào)澤電子(Mouser)專區(qū)
關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權(quán)所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 91瑟瑟 | 精精国产xxxx视频在线播放器 | 精品视频一区二区三三区四区 | 91麻豆精品国产剧情 | 99久久精品费精品国产 | 九九九热视频 | 在线观看免费播放网址成人 | 四虎最新网| 黄色片免费网站 | 窝窝人体色 | 欧美日韩国产一区二区三区播放 | 成年女人18毛片毛片免费 | 国产综合影院 | 五月婷婷中文 | 国产麻豆果冻传媒 | 四虎影视884a精品国产古代 | 欧美精彩视频在线观看 | 欧美精品影视 | 好男人社区神马www在线观看 | 午夜久久免费视频 | 成人精品网 | 日韩视频精品 | 麻豆午夜视频 | 色网站在线看 | 91青青青国产在观免费影视 | 欧美日韩一区二区三区自拍 | 日韩在线观看第一页 | 97视频在线观看播放 | 幸福宝8008app下载章节 | 国产全黄a一级毛片 | 日韩综合| 国内精品免费 | 精品视频在线观看一区二区 | 国产精品久久一区一区 | 国产区精品一区二区不卡中文 | 麻豆爱爱 | 日韩亚洲欧洲在线com91tv | 欧美一区二区在线播放 | 欧美日韩精品免费一区二区三区 | 国产三级手机在线 | 一区二区视频在线观看 |