国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

如何實現(xiàn)異步 Connect

開發(fā) 前端
寫過網(wǎng)絡(luò)程序的同學(xué),應(yīng)該都知道 connect 函數(shù),在 socket 開始讀寫操作之前,先要進(jìn)行連接,也即 TCP 的三次握手 , 這個過程就是在 connect 函數(shù)中完成的, connect 函數(shù)本身是阻塞的,通過設(shè)置 socket 的選項及調(diào)用 select/poll 函數(shù)可以實現(xiàn)異步 connect 的功能。

[[402493]]

本文轉(zhuǎn)載自微信公眾號「 Linux開發(fā)那些事兒」,作者LinuxThings。轉(zhuǎn)載本文請聯(lián)系 Linux開發(fā)那些事兒公眾號。

寫過網(wǎng)絡(luò)程序的同學(xué),應(yīng)該都知道 connect 函數(shù),在 socket 開始讀寫操作之前,先要進(jìn)行連接,也即 TCP 的三次握手 , 這個過程就是在 connect 函數(shù)中完成的, connect 函數(shù)本身是阻塞的,通過設(shè)置 socket 的選項及調(diào)用 select/poll 函數(shù)可以實現(xiàn)異步 connect 的功能

socket 默認(rèn)是阻塞模式,處于阻塞模式時,調(diào)用 connect 函數(shù)之后, 會一直等待連接結(jié)果返回為止,要么成功,要么失敗,connect 函數(shù)返回 0 時成功,返回 -1 失敗

在局域網(wǎng)中,調(diào)用 connect 函數(shù),基本上會立即返回結(jié)果,當(dāng)服務(wù)器在國外時,connect 函數(shù)時會阻塞一段時間,大概幾秒鐘吧,具體的還要看當(dāng)時的網(wǎng)絡(luò)狀況

為什么要用異步 connect

Linux 下 connect 默認(rèn)的超時時間大概在一分鐘左右(不同的Linux版本略有差別),在實際的開發(fā)中,這個時間顯得有點兒長了

對于服務(wù)器來說,需要為很多的客戶端服務(wù),要盡量減少阻塞,所以,一般都是采用 異步 connect 的技術(shù)

對于每一個編寫網(wǎng)絡(luò)程序的同學(xué)來說,異步connect 應(yīng)該是必須掌握的基本功

異步connect 步驟

(1) 創(chuàng)建socket,調(diào)用 fcntl 函數(shù)將其設(shè)置為非阻塞

(2) 調(diào)用 connect 函數(shù),返回 0 表示連接成功,返回 -1,需要檢查錯誤碼

如果錯誤碼為 EINPROGRESS,表示正在建立連接中

如果錯誤碼是 EINTR 表示,表示發(fā)生了系統(tǒng)中斷,這時繼續(xù)執(zhí)行連接即可

如果是其他錯誤碼,調(diào)用 close(fd) 函數(shù)關(guān)閉 socket, 連接失敗

(3) 將 socket 加入 select/poll 的可寫文件描述符集合中,并設(shè)置超時時間

(4) 判斷 select/poll 函數(shù)的返回值

小于等于 0 表示失敗

其他,表示 socket 可寫,調(diào)用 getsockopt 函數(shù) 捕獲 socket 的錯誤信息

具體的代碼如下:

  1. /* 
  2.     異步 connect 測試代碼, test_connect.cpp 
  3. */ 
  4. #include <stdint.h> 
  5. #include <sys/types.h> 
  6. #include <sys/socket.h> 
  7. #include <sys/select.h> 
  8. #include <poll.h> 
  9. #include <sys/un.h> 
  10. #include <netinet/in.h> 
  11. #include <netinet/tcp.h> 
  12. #include <arpa/inet.h> 
  13. #include <unistd.h> 
  14. #include <fcntl.h> 
  15. #include <string.h> 
  16. #include <netdb.h> 
  17. #include <errno.h> 
  18. #include <stdarg.h> 
  19. #include <poll.h> 
  20. #include <limits.h> 
  21. #include <iostream> 
  22. using namespace std; 
  23.  
  24. int32_t main(int32_t argc, char *argv[]) 
  25.     if(argc < 3) 
  26.     { 
  27.         std::cout << "argc < 3..." << std::endl; 
  28.         return -1; 
  29.     } 
  30.     std::string strip = argv[1]; 
  31.     uint32_t port = atoi(argv[2]); 
  32.     //創(chuàng)建 socket 
  33.     int32_t fd = socket(AF_INET, SOCK_STREAM, 0); 
  34.     if(-1 == fd) 
  35.     { 
  36.         std::cout << "create socket error:" << errno << std::endl; 
  37.         return -1; 
  38.     } 
  39.     //將 socket 設(shè)置成非阻塞 
  40.     int32_t flag = fcntl(fd, F_GETFL, 0); 
  41.     flag |= O_NONBLOCK; 
  42.     if(-1 == fcntl(fd, F_SETFL, flag)) 
  43.     { 
  44.         std::cout << " set socket nonblock error:" << errno << std::endl; 
  45.         close(fd); 
  46.         return -1; 
  47.     } 
  48.     //服務(wù)器地址 
  49.     struct sockaddr_in addr; 
  50.     addr.sin_family = AF_INET; 
  51.     addr.sin_port = htons(port); 
  52.     addr.sin_addr.s_addr = inet_addr(strip.c_str()); 
  53.     // 
  54.     for(; ;) 
  55.     { 
  56.         //連接服務(wù)器 
  57.         int32_t ret = connect(fd, (struct sockaddr*)&addr, sizeof(addr) ); 
  58.         if(-1 == ret) 
  59.         { 
  60.             int32_t err = errno; 
  61.             if(EINTR == err) 
  62.             { 
  63.                 //connect被中斷,繼續(xù)重試 
  64.                 //如果不處理 EINTR 錯誤的話,connect邏輯可以不用放到 for 循環(huán)中 
  65.                 continue
  66.             } 
  67.             if(EINPROGRESS != err) 
  68.             { 
  69.                 std::cout << "connect err:" << errno << ", str:" << strerror(errno) <<  std::endl; 
  70.                 goto exit; 
  71.             } 
  72.             //正在連接中 
  73.             std::cout << "connecting..." << std::endl; 
  74.             //處理結(jié)果 
  75.             int32_t result = -1; 
  76.     #if 1 
  77.             //將 socket 加入到 poll 的可寫集合中 
  78.             struct pollfd wfd[1]; 
  79.             wfd[0].fd = fd; 
  80.             wfd[0].events = POLLOUT; 
  81.             //檢測 socket 是否可寫 
  82.             result = poll(wfd, 1, 3000); 
  83.     #elif 0 
  84.             //設(shè)置超時時間 
  85.             struct timeval tval; 
  86.             tval.tv_sec = 3; 
  87.             tval.tv_usec = 0; 
  88.             //將 socket 加入到 select 的可寫集合中 
  89.             fd_set wfds; 
  90.             FD_ZERO(&wfds); 
  91.             FD_SET(fd,&wfds); 
  92.             //檢測 socket 是否可寫 
  93.             result = select(fd + 1, nullptr, &wfds, nullptr,&tval); 
  94.     #endif 
  95.             std::cout << "async connect result:" << result << std::endl; 
  96.             // 失敗 
  97.             if(result <= 0 ) 
  98.             {  
  99.                 std::cout << "async connect err:" << errno << ", str:" << strerror(errno) << std::endl; 
  100.                 goto exit; 
  101.             } 
  102.             //檢查socket 錯誤信息 
  103.             int32_t temperr = 0; 
  104.             socklen_t temperrlen = sizeof(temperr); 
  105.             if(-1 == getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&temperr, &temperrlen) ) 
  106.             { 
  107.                 std::cout << "async connect...getsockopt err:" << errno << ", str:" << strerror(errno) <<  std::endl; 
  108.                 goto exit; 
  109.             } 
  110.             if(0 != temperr) 
  111.             { 
  112.                 std::cout << "async connect...getsockopt temperr:" << temperr << ", str:" << strerror(temperr) << std::endl; 
  113.                 goto exit; 
  114.             } 
  115.             //成功 
  116.             std::cout << "async connect success..." << std::endl; 
  117.             goto exit; 
  118.         } 
  119.         else 
  120.         { 
  121.              //連接成功 
  122.             std::cout << "connect success..." << std::endl; 
  123.             goto exit;           
  124.         } 
  125.     } // end of  for(; ;) 
  126. exit: 
  127.     std::cout << "quit...." << std::endl; 
  128.     close(fd); 
  129.     return 0; 
  • 代碼說明

如果不處理 EINTR 錯誤的話,connect 函數(shù)及后面的邏輯可以不用放到 for 循環(huán)中

檢查 socket 是否可寫,調(diào)用 select 或者 poll 函數(shù)都可以,上述代碼中使用的是 poll 函數(shù),將代碼中的 #if 1 改成 #if 0 以及 #elif 0 改成 #elif 1 , 就是使用 select 函數(shù)檢測 socket 是否可寫了

測試

在另一臺機(jī)器上執(zhí)行 nc -l -v -k 192.168.70.20 5000 命令,啟動一個服務(wù)器程序

在當(dāng)前機(jī)器上執(zhí)行 g++ -g -Wall -std=c++11 -o test_connect test_connect.cpp 進(jìn)行編譯

執(zhí)行 ./test_connect 192.168.70.20 5000, 結(jié)果如下圖

此時,服務(wù)器程序顯示如下:

通過 test_connect 程序端的截圖可以看出,調(diào)用 connect 函數(shù)之后,返回了 EINPROGRESS 錯誤碼,然后調(diào)用 select/poll 函數(shù)返回 1, 表示 socket 可寫,緊接著調(diào)用 getsockopt 函數(shù)檢查 socket 錯誤信息,通過打印的信息知道,socket 無錯誤信息,即 連接成功

我們在服務(wù)器機(jī)器上按 CTRL + C 停止服務(wù)器程序,然后關(guān)閉 test_connect 程序,再次執(zhí)行 ./test_connect 192.168.70.20 5000 ,結(jié)果如下圖:

從上圖可以看出,即使服務(wù)器程序已經(jīng)退出了,調(diào)用 select/poll 之后還是返回 socket 可寫,當(dāng)繼續(xù)調(diào)用 getsockopt 函數(shù)檢查 socket 錯誤碼,此時錯誤碼是 111, 表示連接被拒絕,也即連接失敗

這里要注意一個很重要的點, 在 Linux 上,即使 socket 沒有連接成功,調(diào)用 select/poll 時,仍然返回 socket 是可寫的,所以 除了調(diào)用 select/poll 檢查 socket 可寫之外,還需要調(diào)用 getsockopt 函數(shù)檢查 socket 的錯誤碼,錯誤碼為 0 表示連接成功,其他表示連接失敗

 

責(zé)任編輯:武曉燕 來源: Linux開發(fā)那些事兒
相關(guān)推薦

2018-05-14 13:51:39

RDS Binlog架構(gòu)Kafka集群

2022-06-22 08:16:29

異步非阻塞框架

2023-08-02 08:03:08

Python線程池

2024-05-23 11:26:02

2013-05-21 13:33:02

Android游戲開發(fā)異步音樂播放

2023-03-10 14:56:37

Linuxconnect系統(tǒng)

2012-04-20 10:05:16

WCF

2017-05-11 20:20:59

JavascriptPromiseWeb

2024-11-29 10:23:35

2024-12-10 00:00:30

ServletTomcat異步

2024-03-13 14:35:33

Spring事件異步

2011-02-24 12:53:51

.NET異步傳統(tǒng)

2024-12-26 12:59:39

2024-08-13 09:26:07

2013-06-27 11:16:27

Android異步加載

2025-08-04 02:21:00

2023-08-30 08:43:42

asyncioaiohttp

2024-11-14 09:40:06

RPC框架NettyJava

2021-08-16 15:49:31

開發(fā)框架單線程異步

2009-11-09 10:50:30

WCF異步調(diào)用
點贊
收藏

51CTO技術(shù)棧公眾號

欧美日韩国产综合视频| 2024最新电影在线免费观看| 国产一区二区免费看| 91青草视频久久| 麻豆视频久久| 日韩最新av在线| 极品美女一区| 亚洲精品不卡在线| 国产素人视频在线观看| 一本色道亚洲精品aⅴ| 成人a视频在线| 亚洲一卡二卡三卡四卡| 好吊的妞视频这里都有| 亚洲丝袜精品丝袜在线| 99热免费在线| 国产精品久久毛片| jizzjizzjizz亚洲| 亚洲欧美自拍偷拍| 福利av痴女| 亚洲精品日日夜夜| 一本大道香蕉久久| 偷偷要91色婷婷| 国外av在线| 欧美精品粉嫩高潮一区二区| av网站在线免费| 亚洲美女精品久久| 欧美xxxhd| www国产91| 久久丝袜视频| 国产精品一区二区久久国产| 香蕉国产精品| 久久综合毛片| 国产精品小仙女| 91人人澡人人爽人人精品| 亚洲同性同志一二三专区| 国产精品午夜久久久久久 | 国产主播在线一区| 亚洲经典一区| 日韩精品福利视频| 成人深夜在线观看| www 四虎| 精品视频在线免费观看| 大黄网站在线观看| 久久综合久久美利坚合众国| jizz性欧美23| 亚洲一区二区日本| 欧美a级一区二区| av7777777| 亚洲h在线观看| 黄色av免费在线| 日韩小视频网址| 不卡av一区二区| 久久久久se| 91一区一区三区| 在线影院av| 欧美精品在线视频| 国产精品久久久久久吹潮| 国产成人精品在线播放| 日韩电影一二三区| 99re6在线视频| 欧美视频一区二区三区在线观看| 美女精品导航| 日韩av电影在线播放| 免费久久99精品国产自在现线| 人妻少妇精品无码专区二区| 亚洲一区二区三区美女| 超碰中文在线| 欧美中文字幕在线观看| 久久国产主播| 成人黄18免费网站| 91精品国产福利在线观看| 欧美黄页免费| 国产一区免费| 94色蜜桃网一区二区三区| 国产小视频福利在线| 日韩电影中文字幕av| 久久精品国产亚洲5555| 18成人免费观看网站下载| 久国产精品韩国三级视频| 无限资源日本好片| 欧洲av一区二区嗯嗯嗯啊| 久久久加勒比| 7777精品伊久久久大香线蕉语言| 国产综合色精品一区二区三区| 91黑丝在线| 日韩精品小视频| 日韩精品一卡| 精品无码国模私拍视频| 欧美日韩综合视频网址| 91国拍精品国产粉嫩亚洲一区| 成人黄色在线免费| 99国产精品99久久久久久| 国产在线一二三| 欧美韩国理论所午夜片917电影| 伊人久久综合| 美女张开让男人捅| 亚洲男人天堂古典| 欧美日韩18| 免费高清成人| 中文字幕在线日韩| 另类亚洲自拍| 亚洲日本高清| 欧美极品少妇xxxxⅹ免费视频| 男人的天堂亚洲| 在线视频手机国产| 色综合91久久精品中文字幕| 亚洲免费网址| 尤物网站在线| 欧美亚洲国产视频小说| 国产成人精品亚洲777人妖| 成人午夜影视| 国产伦精品免费视频| 久久欧美一区二区| 麻豆蜜桃在线观看| 久久久福利视频| 亚洲成a人在线观看| 天堂精品久久久久| 免费日韩在线观看| 精品久久国产字幕高潮| 国产精品久久观看| 欧美伦理片在线观看| 亚洲欧美色图片| 爽好久久久欧美精品| 成人福利在线| 国产精品国产精品国产专区不卡| 亚洲免费av在线| 老司机精品在线| 欧美视频免费播放| 伊人久久久久久久久久| 日韩—二三区免费观看av| 一级毛片视频在线| 国产亚洲精品美女久久久m| 天天影视色香欲综合网老头| 国产一区二区三区四区大秀| 另类图片亚洲色图| 日韩美女主播视频| 综合久久国产九一剧情麻豆| 国产精品777777在线播放| www.99热这里只有精品| 一区二区三区天堂av| 国产精品一区二区久激情瑜伽| 日本不良网站在线观看| 中文字幕一区二区三区乱码| 亚洲成人网在线| 国产成人亚洲综合色影视| 欧美18av| 精品99在线视频| 色综合视频一区中文字幕| 91在线观看免费视频| va天堂va亚洲va影视| 92看片淫黄大片一级| 久久夜精品香蕉| 国产精品妹子av| 欧美一区二区三| 国产一区二区影视| 免费在线成人av| 亚洲美女自拍视频| 2020国产精品自拍| 啪啪国产精品| 一色桃子在线| 欧美理论一区二区| 亚洲视频在线观看免费| 国产亚洲短视频| 国产日产一区| 九色在线视频| 日韩成人av电影在线| 亚洲欧美日韩精品久久| 久久久久久毛片| 日本黄色精品| 亚洲综合影视| 国产99久久九九精品无码| 97视频国产在线| 欧美综合一区二区三区| 日本亚洲欧美天堂免费| 伊人久久综合网另类网站| 国产福利电影网| 久久久精品动漫| 伊人久久综合97精品| 国产精品丝袜一区| 国产精品毛片一区二区在线看| 95在线视频| 99色精品视频| 国产一区私人高清影院| 日韩你懂的在线播放| 久久亚洲综合av| 女人色偷偷aa久久天堂| 桃色av一区二区| 男女羞羞视频教学| 品久久久久久久久久96高清| 日日狠狠久久偷偷四色综合免费| 一区二区成人在线| 蜜桃视频在线观看一区| 波多野结衣一区二区三区免费视频| 校园春色欧美| 色哟哟免费网站| 国产在线视频不卡| 亚洲欧洲免费视频| 欧美性猛交xxxx乱大交| 99re6这里只有精品视频在线观看 99re8在线精品视频免费播放 | 国产老熟妇精品观看|