Linux socket非阻塞connect方法

2021-09-03 09:51:11 字數 4478 閱讀 6832

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語句中,表示該語句結束時完成賦值操作,結果與語句順序無關,並行關係 可以這樣理解 阻塞...