日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

connect函数在阻塞和非阻塞模式下的行为

發布時間:2023/12/10 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 connect函数在阻塞和非阻塞模式下的行为 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

connect函數在阻塞和非阻塞模式下的行為

當socket使用阻塞模式時,connect函數會阻塞到有明確結果才會返回,如果網絡環境較差,可能要等一會,影響體驗,

為了解決這個問題,我們使用異步connect技術

  • 創建socket,將socket設置為非阻塞模式

  • 調用connect函數,此時無論connect函數是否連接成功,都會立即返回,如果返回-1,不一定表示連接出錯,如果此時錯誤碼為EINPROGRESS表示正在嘗試連接

  • 調用select函數,在指定時間內判斷該socket是否可寫,可寫說明連接成功,反之,連接失敗

    上述流程代碼

    #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <iostream> #include <string.h> #include <stdio.h> #include <fcntl.h> #include <errno.h>#define SERVER_ADDRESS "127.0.0.1" #define SERVER_PORT 3000 #define SEND_DATA "helloworld"int main(int argc, char* argv[]) {//1.創建一個socketint clientfd = socket(AF_INET, SOCK_STREAM, 0);if (clientfd == -1){std::cout << "create client socket error." << std::endl;return -1;}//將clientfd設置成非阻塞模式int oldSocketFlag = fcntl(clientfd, F_GETFL, 0);int newSocketFlag = oldSocketFlag | O_NONBLOCK;if (fcntl(clientfd, F_SETFL, newSocketFlag) == -1){close(clientfd);std::cout << "set socket to nonblock error." << std::endl;return -1;}//2.連接服務器struct sockaddr_in serveraddr;serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(SERVER_ADDRESS);serveraddr.sin_port = htons(SERVER_PORT);for (;;){int ret = connect(clientfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));if (ret == 0){std::cout << "connect to server successfully." << std::endl;close(clientfd);return 0;} else if (ret == -1) {if (errno == EINTR){//connect 動作被信號中斷,重試connectstd::cout << "connecting interruptted by signal, try again." << std::endl;continue;} else if (errno == EINPROGRESS){//連接正在嘗試中break;} else{//真的出錯了,close(clientfd);return -1;}}}fd_set writeset;FD_ZERO(&writeset);FD_SET(clientfd, &writeset);struct timeval tv;tv.tv_sec = 3; tv.tv_usec = 0;//3.調用select函數判斷socket是否可寫if (select(clientfd + 1, NULL, &writeset, NULL, &tv) == 1){std::cout << "[select] connect to server successfully." << std::endl;} else {std::cout << "[select] connect to server error." << std::endl;}close(clientfd);return 0; }

    首先先用nc命令啟動一個服務端程序并執行

    nc -v -l -n 0.0.0.0 3000

    然后運行程序,我用的clion

    把服務端關掉,在重新啟動客戶端,一看結果,還是

    為什么連接不上也會輸出同樣的結果?原因如下:

    • 在Windows上,一個socket沒有建立連接之前,我們用select檢測是否可寫,是可以得到正確結果的,即不可寫;連接成功后在檢測,就會變為可寫

    • 在Linux上一個socket沒有建立連接之前,用select函數檢測是否可寫,我們也會得到可寫的結果,**所以,在Linux上,我們不僅要用select檢測socket是否可寫還要用getsocketopt檢測socket此時是否出錯

      #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <iostream> #include <string.h> #include <stdio.h> #include <fcntl.h> #include <errno.h>#define SERVER_ADDRESS "127.0.0.1" #define SERVER_PORT 3000 #define SEND_DATA "helloworld"int main(int argc, char* argv[]) {//1.創建一個socketint clientfd = socket(AF_INET, SOCK_STREAM, 0);if (clientfd == -1){std::cout << "create client socket error." << std::endl;return -1;}//將clientfd設置成非阻塞模式int oldSocketFlag = fcntl(clientfd, F_GETFL, 0);int newSocketFlag = oldSocketFlag | O_NONBLOCK;if (fcntl(clientfd, F_SETFL, newSocketFlag) == -1){close(clientfd);std::cout << "set socket to nonblock error." << std::endl;return -1;}//2.連接服務器struct sockaddr_in serveraddr;serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(SERVER_ADDRESS);serveraddr.sin_port = htons(SERVER_PORT);for (;;){int ret = connect(clientfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));if (ret == 0){std::cout << "connect to server successfully." << std::endl;close(clientfd);return 0;}else if (ret == -1){if (errno == EINTR){//connect 動作被信號中斷,重試connectstd::cout << "connecting interruptted by signal, try again." << std::endl;continue;}else if (errno == EINPROGRESS){//連接正在嘗試中break;}else{//真的出錯了,close(clientfd);return -1;}}}fd_set writeset;FD_ZERO(&writeset);FD_SET(clientfd, &writeset);struct timeval tv;tv.tv_sec = 3;tv.tv_usec = 0;//3.調用select函數判斷socket是否可寫if (select(clientfd + 1, NULL, &writeset, NULL, &tv) != 1){std::cout << "[select] connect to server error." << std::endl;close(clientfd);return -1;}int err;socklen_t len = static_cast<socklen_t>(sizeof err);//4.調用getsockopt檢測此時socket是否出錯if (::getsockopt(clientfd, SOL_SOCKET, SO_ERROR, &err, &len) < 0){close(clientfd);return -1;}if (err == 0)std::cout << "connect to server successfully." << std::endl;elsestd::cout << "connect to server error." << std::endl;close(clientfd);return 0; }
  • TCP網絡編程的基本流程

    Linux與C++11多線程編程(學習筆記)

    Linux select函數用法和原理

    socket的阻塞模式和非阻塞模式(send和recv函數在阻塞和非阻塞模式下的表現)

    connect函數在阻塞和非阻塞模式下的行為

    獲取socket對應的接收緩沖區中的可讀數據量

    總結

    以上是生活随笔為你收集整理的connect函数在阻塞和非阻塞模式下的行为的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。