SOCKET【3】-select+getsockopt客户端检测connect是否成功
生活随笔
收集整理的這篇文章主要介紹了
SOCKET【3】-select+getsockopt客户端检测connect是否成功
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 前言
- 一、使用`select+getsockopt`如何知道是否真的成功的連接到遠程服務器?
- 1.1 connect 返回的幾種情況:
- 1.2 針對1.1中的第二種情況的處理
- 三、 `getsockopt`獲取`SO_ERROR`等于0一定是沒有問題嗎?
- 四、 select 服務器如何編程能快速知道對端是否已經斷開?
- 總結
前言
一、使用select+getsockopt如何知道是否真的成功的連接到遠程服務器?
最近在看前輩的網絡客戶端編程,遇到以下代碼:
fd = socket(AF_INET, SOCK_STREAM, 0);ret = connect(fd, ( struct sockaddr* )&addr, sizeof(addr));if (ret == -1 && errno != EINPROGRESS) // connect失敗{ret = CONNECT_ERROR;}else{while(1){FD_ZERO(&read_fds);FD_ZERO(&write_fds);FD_SET(fd, &read_fds);FD_SET(fd, &write_fds);switch (flag){case CHECKSOCKET_CONN:ret = select(fd + 1, &read_fds, &write_fds, NULL, &tv);if (ret <= 0){ // errorret = CONNECT_ERROR;}break;case CHECKSOCKET_READ:ret = select(fd + 1, &read_fds, NULL, NULL, &tv);if (ret < 0){ // errorret = RECV_ERROR;}break;case CHECKSOCKET_WRITE:ret = select(fd + 1, NULL, &write_fds, NULL, &tv);if (ret < 0){ // errorret = SEND_ERROR;}break;default: // never go hereret = RET_UNKNOWN;break;}if (ret == 0){ // timeoutret = TIMEOUT_ERROR;}if (ret < 0) // select error or timeout ,exit{break;}ret = RET_OK; // set ret OKswitch (flag){case CHECKSOCKET_CONN:if (!FD_ISSET(fd, &read_fds) && !FD_ISSET(fd, &write_fds)){ret = CONNECT_ERROR;}else if (FD_ISSET(fd, &read_fds) && FD_ISSET(fd, &write_fds)){ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &sock_error, &tmp);if (ret == 0 && sock_error == 0){ // connect succ}else if (ret == 0 && sock_error != 0){ret = RET_SOCKET_CONNECT_ERROR;}else{ret = RET_SOCKET_CONNECT_ERROR;}}else if (!FD_ISSET(fd, &read_fds) && FD_ISSET(fd, &write_fds)){ // connect succ}else if (FD_ISSET(fd, &read_fds) && !FD_ISSET(fd, &write_fds)){ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &sock_error, &tmp);if (ret == 0){}ret = RET_SOCKET_CONNECT_ERROR;}else // never go here{ret = RET_UNKNOWN;}break;case CHECKSOCKET_READ:if (!FD_ISSET(fd, &read_fds)){ret = RET_SOCKET_RECV_ERROR;}break;case CHECKSOCKET_WRITE:if (!FD_ISSET(fd, &write_fds)){ret = SEND_ERROR;}break;default: // never go hereret = RET_UNKNOWN;break;} } }在網絡編程中,經常使用的是異步的socket也就是非阻塞socket,但是在在異步的情況下如何判斷connect是否連接成功成為了重中之重。
1.1 connect 返回的幾種情況:
1.2 針對1.1中的第二種情況的處理
如果socket連接失敗,則socket同時變的可讀可寫。
如果socket連接成功,則第一socket變得可寫,第二就是socket同時變的可讀(連接成功,對端馬上有數據發過來)可寫。
那么如何判斷connect是否真正的成功了呢?
第15行,程序在connect之后,緊接著調用select,如果返回錯誤,或者因為超時返回0,這兩種情況需要后續通過查看socket的可寫可讀的情況進行分析。
所以在可讀可寫的情況下,調用getsockopt函數選定SO_ERROR,通過該選項我們可以判斷出socket是否連接成功,注意不是獲取該函數的返回值而是函數的參數返回值,函數調用中的第四個參數會返回socket連接錯誤的錯誤碼,如果成功錯誤碼為0,否則不為0。
三、 getsockopt獲取SO_ERROR等于0一定是沒有問題嗎?
TCP socket連接失敗后getsockopt獲取SO_ERROR等于0誤以為連接成功;
在Linux下使用非阻塞TCP連接的方式連接一個錯誤的地址,第一次可以connect返回失敗,getsockopt能夠得到正確的錯誤碼。但使用此socket進行第二次連接的時候,connect也返回失敗,getsockopt返回獲取錯誤(SO_ERROR)為0,從而認為連接成功。
解決方法:tcp 在調用connect失敗后需要重新創建socket。
這是因為TCP連接的三次握手產生的問題,具體參考
網絡編程Socket之TCP之connect詳解
四、 select 服務器如何編程能快速知道對端是否已經斷開?
使用select重寫客戶端程序,目的是服務器進程一終止,客戶就能馬上得到通知。新版程序不是阻塞在套接字事件或者IO調用上,而是阻塞于select調用上,或是等待套接字或是等待標準IO輸入。
客戶的套接字上的處理條件:
總結
總結
以上是生活随笔為你收集整理的SOCKET【3】-select+getsockopt客户端检测connect是否成功的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 老师计算机组合照说说,照毕业照分离说说
- 下一篇: 让我摘下星星送给你_想摘下星星给你,就摘