欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

非阻塞socket調(diào)用connect, epoll和select檢查連

系統(tǒng) 2363 0

非阻塞socket調(diào)用connect, epoll和select檢查連接情況示例 - 語行 - 博客園

非阻塞socket調(diào)用connect, epoll和select檢查連接情況示例

我們知道,linux下socket編程有常見的幾個系統(tǒng)調(diào)用:

對于服務(wù)器來說, 有socket(), bind(),listen(), accept(),read(),write()

對于客戶端來說,有socket(),connect()

這里主要要講的是客戶端這邊的connect函數(shù)。

對于客戶端來說,需要打開一個套接字,然后與對端服務(wù)器連接,例如:

            
               1
            
            
              int
            
             main(
            
              int
            
             argc, 
            
              char
            
             **
            
              argv) 

            
            
               2
            
            
              {

            
            
               3
            
            
              struct
            
            
               sockaddr_in s_addr;

            
            
               4
            
                     memset(&s_addr, 
            
              0
            
            , 
            
              sizeof
            
            
              (s_addr));

            
            
               5
            
                     s_addr.sin_family =
            
               AF_INET;

            
            
               6
            
                     s_addr.sin_addr.s_addr = inet_addr(
            
              "
            
            
              remote host
            
            
              "
            
            
              );

            
            
               7
            
                     s_addr.sin_port =
            
               htons(remote port);

            
            
               8
            
                     socklen_t addr_len = 
            
              sizeof
            
            (
            
              struct
            
            
               sockaddr);

            
            
               9
            
            
              int
            
             c_fd = socket(AF_INET, SOCK_STREAM, 
            
              0
            
            
              );

            
            
              10
            
            
              int
            
             ret = connect(c_fd, (
            
              struct
            
             sockaddr*)&
            
              s_addr, addr_len);                                 

            
            
              11
            
            
                      ......

            
            
              12
            
             }
          

?

當(dāng)connect上對端服務(wù)器之后,就可以使用該套接字發(fā)送數(shù)據(jù)了。

我們知道,如果socket為TCP套接字, 則connect函數(shù)會激發(fā)TCP的三次握手過程,而三次握手是需要一些時間的, 內(nèi)核中對 connect的 超時限制是 75 秒,就是說如果超過75秒則connect會由于超時而返回失敗。但是如果對端服務(wù)器由于某些問題無法連接,那么每一個客戶端發(fā)起的connect都會要等待75才會返回,因為socket默認(rèn)是阻塞的。對于一些線上服務(wù)來說,假設(shè)某些對端服務(wù)器出問題了,在這種情況下就有可能引發(fā)嚴(yán)重的后果。 或者在有些時候,我們不希望在調(diào)用connect的時候阻塞住,有一些額外的任務(wù)需要處理;

這種場景下,我們就可以將socket設(shè)置為非阻塞,如下代碼:

            
              int
            
             flags = fcntl(c_fd, F_GETFL, 
            
              0
            
            
              );

            
            
              if
            
            (flags < 
            
              0
            
            
              ) {
    
            
            
              return
            
            
              0
            
            
              ;      
}
fcntl(c_fd, F_SETFL, flags 
            
            | O_NONBLOCK);
          

當(dāng)我們將socket設(shè)置為NONBLOCK后,在調(diào)用connect的時候,如果操作不能馬上完成,那connect便會立即返回,此時connect有可能返回-1, 此時需要根據(jù)相應(yīng)的錯誤碼errno,來判斷連接是否在繼續(xù)進行。

當(dāng)errno=EINPROGRESS時,這種情況是正常的,此時連接在繼續(xù)進行, 但是仍未完成;同時TCP的三路握手操作繼續(xù)進行; 后續(xù)只要用select/epoll去注冊對應(yīng)的事件并設(shè)置超時時間來判斷連接否是連接成功就可以了。

            
              int
            
             ret = connect(c_fd, (
            
              struct
            
             sockaddr*)&
            
              s_addr, addr_len);

            
            
              while
            
            (ret < 
            
              0
            
            
              ) {
    
            
            
              if
            
            ( errno ==
            
               EINPROGRESS ) {
         
            
            
              break
            
            
              ;
    }  
            
            
              else
            
            
               {
         perror(
            
            
              "
            
            
              connect fail'\n
            
            
              "
            
            
              );
         
            
            
              return
            
            
              0
            
            
              ;
    }
}
            
          

這個地方,我們很可能會判斷如果ret小于0,就直接判斷連接失敗而返回了,沒有根據(jù)errno去判斷EINPROGRESS這個錯誤碼。這里也是昨天在寫份程序的時候遇到的一個坑。

使用非阻塞 connect 需要注意的問題是:
1. 很可能 調(diào)用 connect 時會立即建立連接(比如,客戶端和服務(wù)端在同一臺機子上),必須處理這種情況。
2. Posix 定義了兩條與 select 和 非阻塞 connect 相關(guān)的規(guī)定:
1)連接成功建立時,socket 描述字變?yōu)榭蓪憽#ㄟB接建立時,寫緩沖區(qū)空閑,所以可寫)
2)連接建立失敗時,socket 描述字既可讀又可寫。 (由于有未決的錯誤,從而可讀又可寫)

不過我同時用epoll也做了實驗(connect一個無效端口,errno=110, errmsg=connect refused),當(dāng)連接失敗的時候,會觸發(fā)epoll的EPOLLERR與EPOLLIN,不會觸發(fā)EPOLLOUT。

當(dāng)用select檢測連接時,socket既可讀又可寫,只能在可讀的集合通過getsockopt獲取錯誤碼。

當(dāng)用epoll檢測連接時,socket既可讀又可寫,只能在EPOLLERR中通過getsockopt獲取錯誤碼。

完整代碼如下:

            
              /*
            
            
               
 * File:   main.cpp
 * Created on March 7, 2013, 5:54 PM
 
            
            
              */
            
            
              

#include 
            
            <cstdlib>
            
              
#include 
            
            <
            
              string
            
            >
            
              
#include 
            
            <iostream>
            
              

#include 
            
            <sys/epoll.h>
            
              
#include 
            
            <sys/socket.h>
            
              
#include 
            
            <sys/types.h>
            
              
#include 
            
            <sys/
            
              select
            
            .h>
            
              
#include 
            
            <error.h>
            
              
#include 
            
            <errno.h>
            
              
#include 
            
            <fcntl.h>
            
              
#include 
            
            <netinet/
            
              in
            
            .h>
            
              
#include 
            
            <arpa/inet.h>



            
              using
            
            
              namespace
            
            
               std;


            
            
              struct
            
            
               so {
    
            
            
              int
            
            
               fd;
    
            
            
              string
            
            
               val;
};


            
            
              int
            
             select_version(
            
              int
            
             *
            
              fd) {
    
            
            
              int
            
             c_fd = *
            
              fd;
    fd_set rset, wset;
    
            
            
              struct
            
            
               timeval tval;
    FD_ZERO(
            
            &
            
              rset);
    FD_SET(c_fd, 
            
            &
            
              rset);
    wset 
            
            =
            
               rset;
    tval.tv_sec 
            
            = 
            
              0
            
            
              ;
    tval.tv_usec 
            
            = 
            
              300
            
             * 
            
              1000
            
            ; 
            
              //
            
            
              300毫秒
            
            
              int
            
            
               ready_n;
    
            
            
              if
            
             ((ready_n = 
            
              select
            
            (c_fd + 
            
              1
            
            , &rset, &wset, NULL, &tval)) == 
            
              0
            
            
              ) {
        close(c_fd); 
            
            
              /*
            
            
               timeout 
            
            
              */
            
            
              
        errno 
            
            =
            
               ETIMEDOUT;
        perror(
            
            
              "
            
            
              select timeout.\n
            
            
              "
            
            
              );
        
            
            
              return
            
             (-
            
              1
            
            
              );
    }
    
            
            
              if
            
             (FD_ISSET(c_fd, &
            
              rset)) {
        
            
            
              int
            
            
               error;
        socklen_t len 
            
            = 
            
              sizeof
            
            
               (error);
        
            
            
              if
            
             (getsockopt(c_fd, SOL_SOCKET, SO_ERROR, &error, &len) < 
            
              0
            
            
              ) {
            cout 
            
            << 
            
              "
            
            
              getsockopt error.
            
            
              "
            
             <<
            
               endl;
            
            
            
              return
            
             -
            
              1
            
            
              ;
        }
        cout 
            
            << 
            
              "
            
            
              in fire.
            
            
              "
            
             << error <<
            
               endl;
    }
    
            
            
              if
            
             (FD_ISSET(c_fd, &
            
              wset)) {
        
            
            
              int
            
            
               error;
        socklen_t len 
            
            = 
            
              sizeof
            
            
               (error);
        
            
            
              if
            
             (getsockopt(c_fd, SOL_SOCKET, SO_ERROR, &error, &len) < 
            
              0
            
            
              ) {
            cout 
            
            << 
            
              "
            
            
              getsockopt error.
            
            
              "
            
             <<
            
               endl;
            
            
            
              return
            
             -
            
              1
            
            
              ;
        }
        cout 
            
            << 
            
              "
            
            
              out fire.
            
            
              "
            
             << error <<
            
               endl;
    }
    
            
            
              return
            
            
              0
            
            
              ;
}


            
            
              int
            
             epoll_version(
            
              int
            
             *
            
              fd) {
    
            
            
              int
            
             c_fd = *
            
              fd;
    
            
            
              int
            
             ep = epoll_create(
            
              1024
            
            
              );
    
            
            
              struct
            
             epoll_event 
            
              event
            
            
              ;
    
            
            
              event
            
            .events = (uint32_t) (EPOLLIN | EPOLLOUT |
            
               EPOLLET);
    
            
            
              struct
            
            
               so _data;
    _data.fd 
            
            =
            
               c_fd;
    _data.val 
            
            = 
            
              "
            
            
              test
            
            
              "
            
            
              ;
    
            
            
              event
            
            .data.ptr = (
            
              void
            
            *) &
            
              _data;
    epoll_ctl(ep, EPOLL_CTL_ADD, c_fd, 
            
            &
            
              event
            
            
              );
    
            
            
              struct
            
             epoll_event eventArr[
            
              1000
            
            
              ];
    
            
            
              int
            
            
               status, err;
    socklen_t len;
    err 
            
            = 
            
              0
            
            
              ;
    len 
            
            = 
            
              sizeof
            
            
               (err);
    
            
            
              int
            
             n = epoll_wait(ep, eventArr, 
            
              20
            
            , 
            
              300
            
            
              );
    
            
            
              for
            
             (
            
              int
            
             i = 
            
              0
            
            ; i < n; i++
            
              ) {
        epoll_event ev 
            
            =
            
               eventArr[i];
        
            
            
              int
            
             events =
            
               ev.events;
        
            
            
              if
            
             (events &
            
               EPOLLERR) {
            
            
            
              struct
            
             so* so_data = (
            
              struct
            
             so*
            
              ) ev.data.ptr;
            cout 
            
            << so_data->val << 
            
              "
            
            
              ,err event fire.
            
            
              "
            
             <<
            
               endl;
            status 
            
            = getsockopt(c_fd, SOL_SOCKET, SO_ERROR, &err, &
            
              len);
            cout 
            
            << status << 
            
              "
            
            
              ,
            
            
              "
            
             << err <<
            
               endl;
        }
        
            
            
              if
            
             (events &
            
               EPOLLIN) {
            
            
            
              struct
            
             so* so_data = (
            
              struct
            
             so*
            
              ) ev.data.ptr;
            cout 
            
            << so_data->val << 
            
              "
            
            
              ,in event fire.
            
            
              "
            
             <<
            
               endl;
            status 
            
            = getsockopt(c_fd, SOL_SOCKET, SO_ERROR, &err, &
            
              len);
            cout 
            
            << status << 
            
              "
            
            
              ,
            
            
              "
            
             << err <<
            
               endl;
        }
        
            
            
              if
            
             (events &
            
               EPOLLOUT) {
            
            
            
              struct
            
             so* so_data1 = (
            
              struct
            
             so*
            
              ) ev.data.ptr;
            cout 
            
            << so_data1->val << 
            
              "
            
            
              ,out event fire.
            
            
              "
            
             <<
            
               endl;
        }
    }

}


            
            
              int
            
             main(
            
              int
            
             argc, 
            
              char
            
            **
            
               argv) {
    
            
            
              string
            
             ip = 
            
              "
            
            
              127.0.0.1
            
            
              "
            
            
              ;
    
            
            
              int
            
             port = 
            
              25698
            
            
              ;
    
            
            
              int
            
            
               c_fd, flags, ret;
    
            
            
              struct
            
            
               sockaddr_in s_addr;
    memset(
            
            &s_addr, 
            
              0
            
            , 
            
              sizeof
            
            
               (s_addr));
    s_addr.sin_family 
            
            =
            
               AF_INET;
    s_addr.sin_port 
            
            =
            
               htons(port);
    s_addr.sin_addr.s_addr 
            
            =
            
               inet_addr(ip.c_str());

    
            
            
              if
            
             ((c_fd = socket(AF_INET, SOCK_STREAM, 
            
              0
            
            )) < 
            
              0
            
            
              ) {
        perror(
            
            
              "
            
            
              create socket fail.\n
            
            
              "
            
            
              );
        exit(
            
            
              0
            
            
              );
    }
    flags 
            
            = fcntl(c_fd, F_GETFL, 
            
              0
            
            
              );
    
            
            
              if
            
             (flags < 
            
              0
            
            
              ) {
        perror(
            
            
              "
            
            
              get socket flags fail.\n
            
            
              "
            
            
              );
        
            
            
              return
            
             -
            
              1
            
            
              ;
    }

    
            
            
              if
            
             (fcntl(c_fd, F_SETFL, flags | O_NONBLOCK) < 
            
              0
            
            
              ) {
        perror(
            
            
              "
            
            
              set socket O_NONBLOCK fail.\n
            
            
              "
            
            
              );
        
            
            
              return
            
             -
            
              1
            
            
              ;
    }
    ret 
            
            = connect(c_fd, (
            
              struct
            
             sockaddr*) &s_addr, 
            
              sizeof
            
             (
            
              struct
            
            
               sockaddr));
    
            
            
              while
            
             (ret < 
            
              0
            
            
              ) {
        
            
            
              if
            
             (errno ==
            
               EINPROGRESS) {
            
            
            
              break
            
            
              ;
        } 
            
            
              else
            
            
               {
            perror(
            
            
              "
            
            
              connect remote server fail.\n
            
            
              "
            
            
              );
            printf(
            
            
              "
            
            
              %d\n
            
            
              "
            
            
              , errno);
            exit(
            
            
              0
            
            
              );
        }
    }
    
            
            
              //
            
            
              select_version(&c_fd);
            
            
    epoll_version(&
            
              c_fd);
    
            
            
              return
            
            
              0
            
            
              ;
}
            
          

?

ps:文中如有不妥的地方,望各位博友指正。

?

非阻塞socket調(diào)用connect, epoll和select檢查連接情況示例


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 欧美一区二区精品 | 97爱爱爱 | 国产精品国产三级国产播12软件 | 欧美aaaaaaaaa| 91资源在线观看 | 成人福利视频网 | 亚洲精品一区二区三区四区 | av老司机久久| 色老头永久免费视频 | 日本免费在线视频 | 毛片入口| 国内一级一级毛片a免费 | 国产精品乱码在线观看 | 成人片网址 | 久在线播放 | 四虎1515hh海外永久免费在线 | 亚洲精品一| 哥斯拉大战金刚2在线观看免费完整版 | 亚洲国产一区二区三区四区五区 | 草久久免费视频 | a黄视频 | 一区二区三区回区在观看免费视频 | 欧美视频网址 | 午夜精品小视频 | 91精品视频免费 | 精品一区二区三区免费看 | 国产视频成人 | 国产精品理论片在线观看 | 日韩不卡在线 | 欧美一区二区三区免费不卡 | 国产精品久久久久久久7电影 | 亚洲综合一区二区三区 | 黑人精品欧美一区二区蜜桃 | 精品国产精品三级精品av网址 | 九九久久精品 | 夜夜骑狠狠干 | jizz在线观看18| 免费一级片在线观看 | 亚洲日韩视频免费观看 | 久久涩综合| 欧美久操|