方案1:
int connect_socket_timeout(int sockfd,char *dest_host, int port, int timeout)
else
memcpy(&address.sin_addr, host->h_addr_list[0], sizeof(address.sin_addr));
}address.sin_family = af_inet;
address.sin_port = htons(port);
/* take the first ip address associated with this hostname */
ioctl(sockfd,fionbio,&noblock);
/** connect until timeout */
/*einprogress a nonblocking socket connection cannot be completed immediately.
ealready the socket is nonblocking and a previous connection attempt has not been completed.
eisconn the socket is already connected.
*/if (connect(sockfd, (struct sockaddr *) &address, sizeof(address)) < 0)
else
if (connect_ok==1)
if (connect_ok==-1)
if ( (timeout>0) && ((time(null) - begin_time)>timeout) )}}
}else /* connect successful immediately */
/** end of try connect */
return ((connect_ok==1)?sockfd:-1);
} 方案2:
補充關於select在非同步(非阻塞)connect中的應用,剛開始搞socket程式設計的時候
我一直都用阻塞式的connect,非阻塞connect的問題是由於當時搞proxy scan
而提出的呵呵
通過在網上與網友們的交流及查詢相關faq,總算知道了怎麼解決這一問題.同樣
用select可以很好地解決這一問題.大致過程是這樣的:
1.將開啟的socket設為非阻塞的,可以用fcntl(socket, f_setfl, o_ndelay)完
成(有的系統用fnedlay也可).
2.發connect呼叫,這時返回-1,但是errno被設為einprogress,意即connect仍舊
在進行還沒有完成.
3.將開啟的socket設進被監視的可寫(注意不是可讀)檔案集合用select進行監視,
如果可寫,用
getsockopt(socket, sol_socket, so_error, &error, sizeof(int));
來得到error的值,如果為零,則connect成功.
在許多unix版本的proxyscan程式你都可以看到類似的過程,另外在solaris精華
區->程式設計技巧中有乙個通用的帶超時引數的connect模組.
我們知道,預設狀態下的套接字都是阻塞方式的,這意味著乙個套介面的呼叫不能立即完成時,程序將進入睡眠狀態,並等待操作完成。對於某些應用,需要及時可控的客戶響應,而阻塞的方式可能會導致乙個較長的時間段內,連線沒有響應。造成套接字阻塞的操作主要有
recv, send, accept, connect.
下面主要以
connect
為例,講講非阻塞的
connect
的工作原理。當乙個
tcp套接字設定為非阻塞後,呼叫
connect
,會立刻返回乙個
einprocess
的錯誤。但
tcp的三路握手繼續進行,我們將用
select
函式檢查這個連線是否建立成功。建立非阻塞的
connect
有下面三個用途: 1.
可以在系統做三路握手的時候做些其它事情,這段時間你可以為所欲為。 2.
可以用這個技術同時建立多個連線,在
web應用中很普遍。 3.
可以縮短
connect
的超時時間,多數實現中,
connect
的超時在
75秒到幾分鐘之間,累傻小子呢?
雖然非阻塞的
conncet
實現起來並不複雜,但我們必須注意以下的細節:
l即使套接字是非阻塞的,如果連線的伺服器是在同一臺主機,
connect
通常會立刻建立。
(connect
返回0
而不是einprocess) l
當連線成功建立時,描述字變成可寫 l
當連線出錯時,描述字變成可讀可寫
例程:定義乙個非阻塞的
connect
函式connect_nonb
int connect_nonb(int sockfd, const sa *saptr, socklen_t salen, int nsec)
if(fd_isset(sockfd, &rset) || fd_isset(sockfd, &west))
else err_quit(「select error: sockfd not set」);
done:
fcntl(sockfd, f_setfl, flags); //
恢復socket 屬性
if (error)
return (0); }
注意事項: l
如果select
呼叫之前,連線已經建立成功,並且有資料傳送過來了,這時套接字將是即可讀又可寫,和連線失敗時是一樣的。所以我們必須用
getsockopt
來檢查套接字的狀態。 l
如果我們不能確定套接字可寫是成功的唯一情況時,我們可以採用以下的呼叫
(1)呼叫getpeername
,如果呼叫失敗,返回
enotconn
,表示連線失敗
(2)呼叫read
,長度引數為
0,如果
read
失敗,表示
connect
失敗。
(3)再呼叫
connect
一次,其應該失敗,如果錯誤是
eisconn
,表示套接字已建立而且連線成功。 l
如果在乙個阻塞的套接字上呼叫的
connect
,在tcp
三路握手前被中斷,如果
connect
不被自動重啟,會返回
eintr
。但是我們不能呼叫
connect
等待連線完成,這樣會返回
eaddrinuse
,此時我們必須呼叫
select
,和非阻塞的方式一樣。
Socket實現非阻塞連線
include include include include pragma comment lib,ws2 32.lib define time out time 20 connect超時時間20秒 void geturl char url socket sockfd struct sockadd...
阻塞 非阻塞socket的理解
b 阻塞socket是這樣的 b recv socket1,buf,length 去網絡卡緩衝區讀取socket1的資料,讀到的資料儲存到buf 如果網絡卡緩衝區有1個位元組,就返回1個,有兩個就返回兩個,當然不能超過length 如果網絡卡緩衝區沒有資料,那麼就一直等待,直到有資料可讀 是的,很傻...
socket阻塞與非阻塞
何為阻塞?在以上過程中若連線還沒到來,那麼接受阻塞,程式執行到這裡不得不掛起,cpu轉而執行其他執行緒。在以上過程中若資料還沒準備好,請閱讀會一樣也會阻塞。阻塞式網路io的特點 多執行緒處理多個連線。每個執行緒擁有自己的棧空間並且占用一些cpu時間。每個執行緒遇到外部為準備好的時候,都會阻塞掉。阻塞...