當(dāng)前位置:首頁 > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 講師博文 > 網(wǎng)絡(luò)編程之網(wǎng)絡(luò)超時檢測
1、什么是網(wǎng)絡(luò)超時檢測
我們都知道阻塞IO是進(jìn)程如果有數(shù)據(jù)到來時,就會繼續(xù)執(zhí)行,如果沒有數(shù)據(jù)到來時,就會無限制的阻塞下去,直到數(shù)據(jù)到來,比如:我在等一個人給我匯報一件事情,如果他一直沒有做完,我就要一直等下去,這樣就太浪費時間了,而如果我只給他10分鐘時間,如果他還是沒有完成,我就認(rèn)為他事情沒有完成,然后繼續(xù)做我自己的事情,這就是超時檢測,而不是一直死等,那么如果是用于在網(wǎng)絡(luò)通信過程中進(jìn)行超時檢測的話,就稱為網(wǎng)絡(luò)超時檢測
2、網(wǎng)絡(luò)超時檢測的必要性
1)避免進(jìn)程在沒有數(shù)據(jù)時無限制的阻塞
2)當(dāng)設(shè)定的時間到時,進(jìn)程從原操作返回繼續(xù)執(zhí)行
3、設(shè)置網(wǎng)絡(luò)超時檢測的方法
在網(wǎng)絡(luò)通信中,要做到超時檢測有三種方法:
1)設(shè)置socket的屬性SO_RCVTIMEO
2)用select檢測socket是否ready
3)設(shè)置定時器(timer),捕捉SIGALRM信號
接下來,我們分別去看怎么實現(xiàn):
1)設(shè)置socket的屬性SO_RCVTIMEO
使用setsockopt設(shè)置socket的屬性為SO_RCVTIMEO,即接收超時
注意:如果是tcp服務(wù)器的話,會有兩個套接字,一個是監(jiān)聽套接字一個是連接套接字,都可以進(jìn)行設(shè)置
設(shè)置好了以后,定義結(jié)構(gòu)體變量,設(shè)置超時時間,如下圖:
2)用select檢測socket是否ready
int select(int n, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, struct timeval *timeout);這是select函數(shù)的原型,后一個參數(shù),就是用來設(shè)置超時的,如果后一個參數(shù)為NULL的話,也就是沒有超時檢測,那么select監(jiān)控的文件描述符都沒有準(zhǔn)備好,select就會一直阻塞,直到有準(zhǔn)備好的文件描述符,如要需要超時檢測,后一個參數(shù)就是要設(shè)置的超時時間,一旦超時,此時select就會返回0,表示沒有準(zhǔn)備好的文件描述符,代碼可參考下圖:
但是要注意:我們在運行的時候發(fā)現(xiàn)select只有在第一次調(diào)用的時候,會阻塞等待,直 到超時,而后面”select timeout...”會不斷打印,根本就不會等待,這是因為在第一次調(diào)用select函數(shù)的時候,就將tv.tv_sec的值改為0了
3)設(shè)置定時器(timer),捕捉SIGALRM信號
這種方式是想通過信號的方式,中斷正在阻塞的系統(tǒng)調(diào)用的執(zhí)行,也就是,首先在系統(tǒng)調(diào)用之前(比如recv函數(shù))設(shè)置定時器,當(dāng)時間到了以后,中斷recv函數(shù),然后再繼續(xù)執(zhí)行recv下面的操作,而不是像之前的如果沒有數(shù)據(jù)可讀,recv會一直阻塞
但要注意:在安裝信號的時候,不能使用signal函數(shù),因為signal默認(rèn)會繼續(xù)執(zhí)行系統(tǒng)調(diào)用,也就是說當(dāng)時間到了以后,又繼續(xù)執(zhí)行recv函數(shù)了,還是會繼續(xù)阻塞,沒有達(dá)到我們想要的效果,所以這個時候我們就要使用比它功能更強(qiáng)大的sigaction了,如下圖:
下圖當(dāng)沒有數(shù)據(jù)可讀時的運行結(jié)果:
另外注意:上面的代碼中SA_RESTART指的是重新執(zhí)行被信號中斷的系統(tǒng)調(diào)用,如果沒有取反的話,就和signal的處理結(jié)果是一樣的了