欧美三级电影完整|亚洲一二三四久久|性爱视频精品一区二区免费在线观看|国产精品啪啪视频|婷婷六月综合操人妻视频网站|99爱免费视频在线观看|美女一级片在线观看|北京熟女88av|免费看黄色A级电影|欧美黄色毛片儿

在阻塞和非阻塞模式下,connect函數(shù)的行為

2023-05-19


在阻塞和非阻塞模式下,connect函數(shù)的行為


socket在使用堵塞方式時,connect如果網(wǎng)絡環(huán)境不好,函數(shù)會被堵塞,直到有明確的結果才會回來,可能要等一會兒,影響感覺,


為解決這一問題,我們使用它。異步connect技術


  1. 建立socket,將socket將其設置為非阻塞模式
  2. 調用connect此時不管函數(shù)connect函數(shù)是否連接成功,將立即返回,如果返回-1,則不一定意味著連接錯誤,如果此時錯誤碼為EINPROGRESS表示正在嘗試連接
  3. 調用select在規(guī)定的時間內判斷函數(shù)。socket是否可以寫,可以寫表示連接成功,相反,連接失敗
    以上流程代碼
#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SERVER_ADDRESS  "127.0.0.1"
#define SERVER_PORT     3000
#define SEND_DATA       "helloworld"

int main(int argc, char* argv[])
{
    創(chuàng)建一個socket
    int 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 信號中斷了動作,再次嘗試connect
std::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;
使用select函數(shù)來判斷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啟動服務器程序并執(zhí)行指令


nc -v -l -n 0.0.0.0 3000

然后運行程序,我使用的clion


關閉服務器,重新啟動客戶端,看看結果,或者


為什么不能連接也會導出相同的結果?理由如下:


  • 一個Windows,socket在建立連接之前,我們使用它。select檢驗是否可以寫,是否可以得到正確的結果,即不能寫;連接成功后,在檢驗中,就會變成可寫的。
  • 最后一個是Linuxsocket使用前未建立連接,select函數(shù)檢驗是否可以寫,我們也可以得到可以寫的結果。因此,在Linux上,我們不僅要使用它。select檢驗socket是否可以寫還要用getsocketopt檢驗socket這個時候是否有錯誤
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SERVER_ADDRESS "127.0.0.1"
#define SERVER_PORT     3000
#define SEND_DATA       "helloworld"

int main(int argc, char* argv[])
{
    創(chuàng)建一個socket
    int 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 信號中斷了動作,再次嘗試connect
                std::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;
    使用select函數(shù)來判斷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(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;
    else
        std::cout << "connect to server error." << std::endl;

    close(clientfd);

    return 0;
}

基本流程的TCP網(wǎng)絡編程


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


Linux select函數(shù)的用法和原理


socket的阻塞方式和非阻塞方式(send和recv函數(shù)在阻塞和非阻塞方式中的表現(xiàn))


在阻塞和非阻塞模式下,connect函數(shù)的行為


在接收緩沖區(qū)獲得相應的socket可讀信息量。




本文僅代表作者觀點,版權歸原創(chuàng)者所有,如需轉載請在文中注明來源及作者名字。

免責聲明:本文系轉載編輯文章,僅作分享之用。如分享內容、圖片侵犯到您的版權或非授權發(fā)布,請及時與我們聯(lián)系進行審核處理或刪除,您可以發(fā)送材料至郵箱:service@tojoy.com