網(wang)絡編(bian)程之網(wang)絡超時檢測
時間:2018-09-29 來源:未知
1、什(shen)么是(shi)網(wang)絡超時檢測
我們(men)都知(zhi)道阻塞(sai)(sai)IO是(shi)(shi)進(jin)(jin)程如(ru)(ru)果(guo)(guo)有數(shu)據(ju)到來時(shi)(shi)(shi),就會繼續(xu)執(zhi)行,如(ru)(ru)果(guo)(guo)沒有數(shu)據(ju)到來時(shi)(shi)(shi),就會無限制的阻塞(sai)(sai)下(xia)去,直(zhi)到數(shu)據(ju)到來,比如(ru)(ru):我在(zai)等(deng)(deng)(deng)一個人給我匯報(bao)一件事(shi)情,如(ru)(ru)果(guo)(guo)他(ta)(ta)一直(zhi)沒有做(zuo)完(wan),我就要一直(zhi)等(deng)(deng)(deng)下(xia)去,這(zhe)樣就太浪費時(shi)(shi)(shi)間(jian)(jian)了,而如(ru)(ru)果(guo)(guo)我只給他(ta)(ta)10分鐘時(shi)(shi)(shi)間(jian)(jian),如(ru)(ru)果(guo)(guo)他(ta)(ta)還是(shi)(shi)沒有完(wan)成,我就認為他(ta)(ta)事(shi)情沒有完(wan)成,然(ran)后(hou)繼續(xu)做(zuo)我自己的事(shi)情,這(zhe)就是(shi)(shi)超時(shi)(shi)(shi)檢(jian)測,而不是(shi)(shi)一直(zhi)死等(deng)(deng)(deng),那么(me)如(ru)(ru)果(guo)(guo)是(shi)(shi)用于(yu)在(zai)網絡通信過程中進(jin)(jin)行超時(shi)(shi)(shi)檢(jian)測的話,就稱為網絡超時(shi)(shi)(shi)檢(jian)測
2、網絡超時檢測的(de)必要性
1)避免進程在沒有數據時無限(xian)制的阻塞
2)當(dang)設定的時(shi)間到(dao)時(shi),進程從原操作(zuo)返回繼續執行
3、設(she)置網絡(luo)超時檢測的方法
在網絡通信中,要做到超時檢測有三種方法:
1)設(she)置socket的屬性SO_RCVTIMEO
2)用select檢測socket是否ready
3)設置定時器(timer),捕捉SIGALRM信號
接下(xia)來,我們分別去看怎(zen)么實(shi)現:
1)設置socket的(de)屬性SO_RCVTIMEO
使用setsockopt設置socket的屬性為(wei)SO_RCVTIMEO,即接收超時
注意:如果是tcp服務器的(de)話,會(hui)有兩個套接(jie)字(zi)(zi),一個是監(jian)聽(ting)套接(jie)字(zi)(zi)一個是連接(jie)套接(jie)字(zi)(zi),都可以進行設(she)置
設置好了以(yi)后,定義結構體變量,設置超時(shi)時(shi)間,如(ru)下圖:

2)用select檢(jian)測(ce)socket是否ready
int select(int n, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, struct timeval *timeout);這(zhe)是(shi)select函數(shu)(shu)的(de)原型,后(hou)一(yi)個參(can)數(shu)(shu),就(jiu)是(shi)用來(lai)設(she)置超(chao)(chao)時(shi)的(de),如果后(hou)一(yi)個參(can)數(shu)(shu)為NULL的(de)話,也就(jiu)是(shi)沒有超(chao)(chao)時(shi)檢(jian)(jian)測,那(nei)么select監控的(de)文件描(miao)述符(fu)(fu)都沒有準備好(hao),select就(jiu)會(hui)一(yi)直阻塞,直到有準備好(hao)的(de)文件描(miao)述符(fu)(fu),如要(yao)需(xu)要(yao)超(chao)(chao)時(shi)檢(jian)(jian)測,后(hou)一(yi)個參(can)數(shu)(shu)就(jiu)是(shi)要(yao)設(she)置的(de)超(chao)(chao)時(shi)時(shi)間,一(yi)旦超(chao)(chao)時(shi),此(ci)時(shi)select就(jiu)會(hui)返回0,表示沒有準備好(hao)的(de)文件描(miao)述符(fu)(fu),代碼可參(can)考下圖:

但是(shi)要注意:我們在(zai)運行的(de)(de)時(shi)候發現select只有在(zai)第一(yi)次調用的(de)(de)時(shi)候,會阻塞(sai)等待,直 到超(chao)時(shi),而后面(mian)”select timeout...”會不斷打印,根本就不會等待,這是(shi)因為(wei)在(zai)第一(yi)次調用select函數的(de)(de)時(shi)候,就將tv.tv_sec的(de)(de)值改(gai)為(wei)0了
3)設置定時器(qi)(timer),捕捉SIGALRM信(xin)號
這種方式是(shi)想通過信號的方式,中斷(duan)正(zheng)在(zai)阻塞(sai)的系統調(diao)用(yong)的執行(xing),也就是(shi),首先在(zai)系統調(diao)用(yong)之(zhi)(zhi)前(比如recv函數(shu))設置定時器,當時間到(dao)了以后(hou)(hou),中斷(duan)recv函數(shu),然后(hou)(hou)再繼續(xu)執行(xing)recv下面的操作,而不是(shi)像之(zhi)(zhi)前的如果沒有數(shu)據可讀,recv會一直(zhi)阻塞(sai)
但(dan)要(yao)注意:在(zai)安裝信號的(de)時候,不能使用(yong)signal函數,因為signal默認會繼續執行(xing)系統調用(yong),也(ye)就是說(shuo)當時間到了(le)以(yi)后,又繼續執行(xing)recv函數了(le),還是會繼續阻塞,沒有達到我(wo)們想要(yao)的(de)效果,所以(yi)這(zhe)個時候我(wo)們就要(yao)使用(yong)比它(ta)功能更強大的(de)sigaction了(le),如下圖:

下圖當沒(mei)有數據可(ke)讀時的運行結果:

另外注(zhu)意:上面的(de)代碼(ma)中SA_RESTART指的(de)是(shi)重新執行被信號中斷的(de)系統調用,如果(guo)沒有(you)取反的(de)話,就和signal的(de)處理結果(guo)是(shi)一(yi)樣(yang)的(de)了

