connect()函式阻塞問題解決
在學習嵌入式Linux網路程式設計中,很多同學都發現了一個問題,那就是呼叫connect函式時,如果服務端關閉,客戶端呼叫connect()函式時,發現阻塞在那裡,而且利用ctrl+c訊號去停止客戶端程式時,需要等待一個較為長的時間才能響應了,這個時間如果大家細心會發現,每次都是75秒的時間。那麼有沒有什麼比較好的辦法,可以以使用者能接受的一個時間響應來停止掉一個正在connect連線的客戶端那?比如我們在做一個網路控制檯的程式,使用者需要隨時可以停止掉任何一個網路服務連線,那麼對於這樣一個需要等待75秒時間才能反饋出服務狀態的程式,使用者是無法接受的。
對於如何解決這個問題,我們可以分析下,要想完成使用者在一個能接受的時間裡迅速反饋出服務端已經關閉的狀態,那麼我們的程式應該做到在一個規定的時間片內,可以捕獲到使用者發出的控制狀態,然後處理使用者的需求。那麼要做到可以在規定的時間片內捕獲使用者的控制狀態,就必須禁止讓我們的connect()函式阻塞75秒的情況發生,也就是說,要讓connect()函式變為非阻塞狀態才行。
好了,現在解決問題的關鍵就是如何把connect變為非阻塞狀態了,我們知道,socket程式設計的操作物件是socket,而socket他又屬於系統描述符型別,那麼對於系統描述符,我們是怎麼操作他變為非阻塞的那?是利用fcntl()函式或者ioctl()函式。
想到這裡,好像問題應該已經解決了,但是我們除錯發現,在服務端出現錯誤的時候,connect確實馬上返回,但是,如果服務端正確那,connect還是馬上返回,這樣,我們無法判斷connect函式是否成功了,那這個問題又該如何解決呢?
我們是否想到了一個select函式那,他具備監聽檔案描述符的功能,如果我們把之前的socket讓select監聽他是否可寫,是不是問題也就解決了。
好了,那麼我們總結下整個思路:
1.建立socket
2.將該socket設定為非阻塞模式
3.呼叫connect()
4.使用select()檢查該socket描述符是否可寫
5.根據select()返回的結果判斷connect()結果
6.將socket設定為阻塞模式
對於第六步,為什麼還要設定為阻塞模式那,留給我們同學自己思考下。
那麼根據上面的6個步驟,我們寫一個簡單的模組程式來除錯看下:
{intsockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd< 0) exit(1);
structsockaddr_in serv_addr;
………//以伺服器地址填充結構serv_addr
interror=-1, len;
len= sizeof(int);
timevaltm;
fd_setset;
unsignedlong ul = 1;
ioctl(sockfd,FIONBIO, &ul); //設定為非阻塞模式
boolret = false;
if(connect(sockfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) == -1)
{
tm.tv_set= TIME_OUT_TIME;