日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

connect()函數(shù)阻塞問題解決

 leon0821 2014-02-18

建立socket后默認(rèn)connect()函數(shù)為阻塞連接狀態(tài),在大多數(shù)實(shí)現(xiàn)中,connect的超時(shí)時(shí)間在75s至幾分鐘之間,想要縮短超時(shí)時(shí)間,可解決問題的兩種方法:方法一、將socket句柄設(shè)置為非阻塞狀態(tài),方法二、采用信號(hào)處理函數(shù)設(shè)置阻塞超時(shí)控制。

在一個(gè)TCP套接口被設(shè)置為非阻塞之后調(diào)用connect,connect會(huì)立即返回EINPROGRESS錯(cuò)誤,表示連接操作正在進(jìn)行中,但是仍未完成;同時(shí)TCP的三路握手操作繼續(xù)進(jìn)行;在這之后,我們可以調(diào)用select來檢查這個(gè)鏈接是否建立成功;非阻塞connect有三種用途:
1.我們可以在三路握手的同時(shí)做一些其它的處理.connect操作要花一個(gè)往返時(shí)間完成,而且可以是在任何地方,從幾個(gè)毫秒的局域網(wǎng)到幾百毫秒或幾秒的廣域網(wǎng).在這段時(shí)間內(nèi)我們可能有一些其他的處理想要執(zhí)行;
2.可以用這種技術(shù)同時(shí)建立多個(gè)連接.在Web瀏覽器中很普遍;
3.由于我們使用select來等待連接的完成,因此我們可以給select設(shè)置一個(gè)時(shí)間限制,從而縮短connect的超時(shí)時(shí)間.在大多數(shù)實(shí)現(xiàn)中,connect的超時(shí)時(shí)間在75秒到幾分鐘之間.有時(shí)候應(yīng)用程序想要一個(gè)更短的超時(shí)時(shí)間,使用非阻塞connect就是一種方法;
非阻塞connect聽起來雖然簡(jiǎn)單,但是仍然有一些細(xì)節(jié)問題要處理:
1.即使套接口是非阻塞的,如果連接的服務(wù)器在同一臺(tái)主機(jī)上,那么在調(diào)用connect建立連接時(shí),連接通常會(huì)立即建立成功.我們必須處理這種情況;
2.源自Berkeley的實(shí)現(xiàn)(和Posix.1g)有兩條與select和非阻塞IO相關(guān)的規(guī)則:
A:當(dāng)連接建立成功時(shí),套接口描述符變成可寫;
B:當(dāng)連接出錯(cuò)時(shí),套接口描述符變成既可讀又可寫;
注意:當(dāng)一個(gè)套接口出錯(cuò)時(shí),它會(huì)被select調(diào)用標(biāo)記為既可讀又可寫;

非阻塞connect有這么多好處,但是處理非阻塞connect時(shí)會(huì)遇到很多可移植性問題;

處理非阻塞connect的步驟:
第一步:創(chuàng)建socket,返回套接口描述符;
第二步:調(diào)用fcntl把套接口描述符設(shè)置成非阻塞;
第三步:調(diào)用connect開始建立連接;
第四步:判斷連接是否成功建立;
A:如果connect返回0,表示連接簡(jiǎn)稱成功(服務(wù)器可客戶端在同一臺(tái)機(jī)器上時(shí)就有可能發(fā)生這種情況);
B:調(diào)用select來等待連接建立成功完成;
如果select返回0,則表示建立連接超時(shí);我們返回超時(shí)錯(cuò)誤給用戶,同時(shí)關(guān)閉連接,以防止三路握手操作繼續(xù)進(jìn)行下去;
如果select返回大于0的值,則需要檢查套接口描述符是否可讀或可寫;如果套接口描述符可讀或可寫,則我們可以通過調(diào)用getsockopt來得到套接口上待處理的錯(cuò)誤(SO_ERROR),如果連接建立成功,這個(gè)錯(cuò)誤值將是0,如果建立連接時(shí)遇到錯(cuò)誤,則這個(gè)值是連接錯(cuò)誤所對(duì)應(yīng)的errno值(比如:ECONNREFUSED,ETIMEDOUT等).
"讀取套接口上的錯(cuò)誤"是遇到的第一個(gè)可移植性問題;如果出現(xiàn)問題,getsockopt源自Berkeley的實(shí)現(xiàn)是返回0,等待處理的錯(cuò)誤在變量errno中返回;但是Solaris會(huì)讓getsockopt返回-1,errno置為待處理的錯(cuò)誤;我們對(duì)這兩種情況都要處理;

這樣,在處理非阻塞connect時(shí),在不同的套接口實(shí)現(xiàn)的平臺(tái)中存在的移植性問題,首先,有可能在調(diào)用select之前,連接就已經(jīng)建立成功,而且對(duì)方的數(shù)據(jù)已經(jīng)到來.在這種情況下,連接成功時(shí)套接口將既可讀又可寫.這和連接失敗時(shí)是一樣的.這個(gè)時(shí)候我們還得通過getsockopt來讀取錯(cuò)誤值;這是第二個(gè)可移植性問題;
移植性問題總結(jié):
1.對(duì)于出錯(cuò)的套接口描述符,getsockopt的返回值源自Berkeley的實(shí)現(xiàn)是返回0,待處理的錯(cuò)誤值存儲(chǔ)在errno中;而源自Solaris的實(shí)現(xiàn)是返回0,待處理的錯(cuò)誤存儲(chǔ)在errno中;(套接口描述符出錯(cuò)時(shí)調(diào)用getsockopt的返回值不可移植)
2.有可能在調(diào)用select之前,連接就已經(jīng)建立成功,而且對(duì)方的數(shù)據(jù)已經(jīng)到來,在這種情況下,套接口描述符是既可讀又可寫;這與套接口描述符出錯(cuò)時(shí)是一樣的;(怎樣判斷連接是否建立成功的條件不可移植)

這樣的話,在我們判斷連接是否建立成功的條件不唯一時(shí),我們可以有以下的方法來解決這個(gè)問題:
1.調(diào)用getpeername代替getsockopt.如果調(diào)用getpeername失敗,getpeername返回ENOTCONN,表示連接建立失敗,我們必須以SO_ERROR調(diào)用getsockopt得到套接口描述符上的待處理錯(cuò)誤;
2.調(diào)用read,讀取長(zhǎng)度為0字節(jié)的數(shù)據(jù).如果read調(diào)用失敗,則表示連接建立失敗,而且read返回的errno指明了連接失敗的原因.如果連接建立成功,read應(yīng)該返回0;
3.再調(diào)用一次connect.它應(yīng)該失敗,如果錯(cuò)誤errno是EISCONN,就表示套接口已經(jīng)建立,而且第一次連接是成功的;否則,連接就是失敗的;

被中斷的connect:
如果在一個(gè)阻塞式套接口上調(diào)用connect,在TCP的三路握手操作完成之前被中斷了,比如說,被捕獲的信號(hào)中斷,將會(huì)發(fā)生什么呢?假定connect不會(huì)自動(dòng)重啟,它將返回EINTR.那么,這個(gè)時(shí)候,我們就不能再調(diào)用connect等待連接建立完成了,如果再次調(diào)用connect來等待連接建立完成的話,connect將會(huì)返回錯(cuò)誤值EADDRINUSE.在這種情況下,應(yīng)該做的是調(diào)用select,就像在非阻塞式connect中所做的一樣.然后,select在連接建立成功(使套接口描述符可寫)或連接建立失敗(使套接口描述符既可讀又可寫)時(shí)返回;

方法二、定義信號(hào)處理函數(shù):

  1. sigset(SIGALRM, u_alarm_handler);
  2. alarm(2);
  3. code = connect(socket_fd, (struct sockaddr*)&socket_st, sizeof(struct sockaddr_in));
  4. alarm(0);
  5. sigrelse(SIGALRM);

首先定義一個(gè)中斷信號(hào)處理函數(shù)u_alarm_handler,用于超時(shí)后的報(bào)警處理,然后定義一個(gè)2秒的定時(shí)器,執(zhí)行connect,當(dāng)系統(tǒng)connect成功,則系統(tǒng)正常執(zhí)行下去;如果connect不成功阻塞在這里,則超過定義的2秒后,系統(tǒng)會(huì)產(chǎn)生一個(gè)信號(hào),觸發(fā)執(zhí)行u_alarm_handler函數(shù), 當(dāng)執(zhí)行完u_alarm_handler后,程序?qū)⒗^續(xù)從connect的下面一行執(zhí)行下去。
其中,處理函數(shù)可以如下定義,也可以加入更多的錯(cuò)誤處理。

  1. void u_alarm_handler()
  2. {
  3. }

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多