socket non-blocking mode connect
對於面向連線的socket型別(sock_stream,sock_seqpacket),在讀寫資料之前必須建立連線,connect()函式用於完成面向連線的socket的建鏈過程,對於tcp,也就是三次握手過程。
connect()函式
標頭檔案:
#include
#include
宣告:int connect (int sockfd,struct sockaddr * serv_addr,int addrlen);
功能:使用套接字sockfd建立到指定網路位址serv_addr的socket連線,引數addrlen為serv_addr指向的記憶體空間大小,即sizeof(struct sockaddr_in)。
返回值:
1)成功返回0,表示連線建立成功(如伺服器和客戶端是同一臺機器上的兩個程序時,會發生這種情況)
2)失敗返回socket_error,相應的設定errno,通過errno獲取錯誤資訊。常見的錯誤有對方主機不可達或者超時錯誤,也可能是對方主機沒有程序監聽對應的埠。
非阻塞connect(non-block mode connect)
套接字執行i/o操作有阻塞和非阻塞兩種模式。在阻塞模式下,在i/o操作完成前,執行操作的函式一直等候而不會立即返回,該函式所在的執行緒會阻塞在這裡。相反,在非阻塞模式下,套接字函式會立即返回,而不管i/o是否完成,該函式所在的執行緒會繼續執行。
客戶端呼叫connect()發起對服務端的socket連線,如果客戶端的socket描述符為阻塞模式,則connect()會阻塞到連線建立成功或連線建立超時(linux核心中對connect的超時時間限制是75s, soliris 9是幾分鐘,因此通常認為是75s到幾分鐘不等)。如果為非阻塞模式,則呼叫connect()後函式立即返回,如果連線不能馬上建立成功(返回-1),則errno設定為einprogress,此時tcp三次握手仍在繼續。此時可以呼叫select()檢測非阻塞connect是否完成。select指定的超時時間可以比connect的超時時間短,因此可以防止連線線程長時間阻塞在connect處。
select判斷規則:
1)如果select()返回0,表示在select()超時,超時時間內未能成功建立連線,也可以再次執行select()進行檢測,如若多次超時,需返回超時錯誤給使用者。
a) 當連線建立成功時,套介面描述符變成 可寫(連線建立時,寫緩衝區空閒,所以可寫)
b) 當連線建立出錯時,套介面描述符變成 既可讀又可寫(由於有未決的錯誤,從而可讀又可寫)
因此,當發現套介面描述符可讀或可寫時,可進一步判斷是連線成功還是出錯。這裡必須將b)和另外一種連線正常的情況區分開,就是連線建立好了之後,伺服器端傳送了資料給客戶端,此時select同樣會返回非阻塞socket描述符既可讀又可寫。
□對於unix環境,可通過呼叫getsockopt來檢測描述符集合是連線成功還是出錯(此為《unix network programming》一書中提供的方法,該方法在linux環境上測試,發現是無效的):
a)如果連線建立是成功的,則通過getsockopt(sockfd,sol_socket,so_error,(char *)&error,&len) 獲取的error 值將是0
b)如果建立連線時遇到錯誤,則errno 的值是連線錯誤所對應的errno值,比如econnrefused,etimedout 等
□一種更有效的判斷方法,經測試驗證,在linux環境下是有效的:
再次呼叫connect,相應返回失敗,如果錯誤errno是eisconn,表示socket連線已經建立,否則認為連線失敗。
綜上所述,這裡總結一下非阻塞connect的實現過程。
非阻塞connect的實現過程
1. 建立套接字sockfd
/* 1. obtain a socket */
int sock_fd;
sock_fd = socket(af_inet, sock_stream, 0);
2. 設定套接字為非阻塞模式
/* 2. set non-blocking mode no socket */
#if 1
int flags = fcntl(sock_fd, f_getfl, 0);
fcntl(sock_fd, f_setfl, flags|o_nonblock);
#else
int imode = 1;
ioctl(sock_fd, fionbio, &imode);
3. 呼叫connect進行連線
struct sockaddr_in addr;
addr.sin_family = af_inet;
addr.sin_port = htons(peer_port);
addr.sin_addr.s_addr = inet_addr(peer_ip);
int ret = connect(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr));
if (0 == res)
else
}
connect會立即返回,可能返回成功,也可能返回失敗。如果連線的伺服器在同一臺主機上,那麼在呼叫connect 建立連線時,連線通常會立即建立成功(我們必須處理這種情況)。
4.呼叫select(),通過fd_isset()檢查套介面是否可寫,確定連線請求是否完成
fd_set rfds, wfds;
struct timeval tv;
fd_zero(&rfds);fd_zero(&wfds);
fd_set(sock_fd, &rfds);
fd_set(sock_fd, &wfds);
/* set select() time out */
tv.tv_sec = 10;
tv.tv_usec = 0;
int selres = select(sock_fd + 1, &rfds, &wfds, null, &tv);
switch (selres)
}
對於無連線的socket型別(sock_dgram),客戶端也可以呼叫connect進行連線,此連線實際上並不建立類似sock_stream的連線,而僅僅是在本地儲存了對端的位址,這樣後續的讀寫操作可以預設以連線的對端為操作物件。
linux下常見的socket錯誤碼:
eagain:沒有足夠空閒的本地埠。
ealready 114:operation already in progress(套接字為非阻塞套接字,並且原來的連線請求還未完成)
ebadf 77:file descriptor in bad state(非法的檔案描述符)
einprogress 115:operation now in progress(套接字為非阻塞套接字,且連線請求沒有立即完成)
eintr:系統呼叫的執行由於捕獲中斷而中止。
eisconn 106:transport endpoint is already connected(已經連線到該套接字)
enetunreach 101:network is unreachable(網路不可到達)
etimedout 110:connection timed out(連線超時)
測試**:
#include #include #include #include #include #include #include #include #include//inet_addr()
#include #include #include #define peer_ip "192.254.1.1"
#define peer_port 7008
int main(int argc, char **argv)
else
else if (0 != errinfo)
ret = 0;
printf("connect ok?\n");
#else
#if 1
connect(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
int err = errno;
if (err == eisconn)
else
#else
char buff[2];
if (read(sock_fd, buff, 0) < 0)
else
#endif
#endif
}else
}if (-1 != selres && (ret != 0))
else
}} else
}if (0 == ret)
else
close(sock_fd);
return ret;
linux socket非阻塞模式下筆記
阻塞即同步,一件事情沒有完成必然不會往下執行 非阻塞即非同步,不管當前事情有沒有完成,都會往下執行 linux socket下面,最常用的函式便是recvfrom sendto,recv send,前面那一對是基於udp的,後面是基於tcp。這兩組函式都有阻塞和非阻塞方式,可以通過fcntl函式設定...
阻塞 非阻塞
阻塞和非阻塞指 的是在接收和傳送時是否等待動作完成才返回 舉例 阻塞 block 是指,你撥通某人 的 但是此人不在,於是你拿著 等他回來,其間不能再用 非阻塞 nonblock 是指,你撥通某人 的 但是此人不在,於是你結束通話 待會兒再打。至於到時候他回來沒有,只有打了 才知道。即所謂的 輪詢 ...
阻塞非阻塞
阻塞和非阻塞 阻塞 可用在assign語句和always語句中,表示只要源訊號發生變化,目標訊號就立刻完成賦值操作,在always塊中,結果與語句順序有關,在always塊中是順序關係 非阻塞 只能用在always語句中,表示該語句結束時完成賦值操作,結果與語句順序無關,並行關係 可以這樣理解 阻塞...