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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

如何解决Connect超时导致的阻塞问题

發布時間:2025/4/5 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何解决Connect超时导致的阻塞问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

版權聲明:本文為博主原創文章,遵循 CC 4.0 by-sa 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/clirus/article/details/50577352
????????這幾天發現一個現象,客戶端正常連接服務器connect顯然不會出現問題。

????????在異常情況下,如果是服務器出現異常,connect能夠立即返回失敗;但是當客戶端出現異常的情況下,分為兩種情況:

????????一種是不插網線,客戶端沒有獲得ip地址,在這種情況下,connect也可以立即返回錯誤;

????????二是但是當客戶端插上網線,但是連接網絡失敗,也就是說能夠獲取到ip地址,但是和服務器是ping不通的。這種情況下connect就可能會發生阻塞,因為按照《UNIX 網絡編程》中講解,connect的在進行三次握手,如果失敗情況,需要等待75s的超市時間的。

????????我們主要討論第二種情況如何解決,可以讓connect快速返回結果,不至于阻塞等待超長的時間。

????????如下是我的代碼

/******************************
* Time out for connect()
******************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
?
?
#define TIME_OUT_TIME 20 //connect超時時間20秒
?
bool setBlockOpt(int m_fd,bool blocked)
{
?? ??? ??? ?
#ifndef WIN32
?? ?int ?flags;
?? ?flags = fcntl(m_fd, F_GETFL, 0);
?? ?if(flags < 0)
?? ?{
?? ??? ?return false;
?? ?}
?? ?if(blocked)
?? ?{?? ?
?? ??? ?printf("Set BLOCK !!!\n");
?? ??? ?flags &= ~O_NONBLOCK;
?? ?}
?? ?else
?? ?{
?? ??? ?printf("Set NONBLOCK !!!\n");
?? ??? ?flags |= O_NONBLOCK;
?? ?}
?? ?if(fcntl(m_fd, F_SETFL, flags) < 0)
?? ?{
?? ??? ?return false;
?? ?}
?? ?
#else
?? ?u_long ulValue;
?? ?if(blocked)
?? ?{
?? ??? ?ulValue = 1;
?? ?}
?? ?else
?? ?{
?? ??? ?ulValue = 0;
?? ?}?? ?
?? ?int n = ioctlsocket(m_fd, FIONBIO, &ulValue);
?? ?if (n != 0)
?? ?{
?? ??? ?return false;
?? ?}
#endif
?? ?return true;
}
?
int connectWithTimeout(int m_fd,int timeout)
{
?? ?int selectFlag = -1;
?? ?int error=-1, len;
?? ?len = sizeof(int);
?? ?bool ret = false;
?? ?int connectFlag = -1;
?? ?
?? ?const char* m_ip = "115.239.210.27";
?? ?int m_port = 80;
?? ?
?? ?if("" == m_ip || 0 > m_port)
?? ?{
?? ??? ?return -1;
?? ?}
?? ?
?? ?if(m_fd < 0 && "" != m_ip && m_port >=0)
?? ?{
?? ??? ?m_fd = ?socket(AF_INET, SOCK_STREAM, 0);
?? ??? ?if(m_fd < 0)
?? ??? ?{
?? ??? ??? ?return -1;
?? ??? ?}
?? ?}
?? ?
?? ?if(m_fd < 0)
?? ?{
?? ??? ?return -1;
?? ?}
?
?? ?struct sockaddr_in servAddr;
?? ?memset(&servAddr, 0, sizeof(servAddr));
?? ?servAddr.sin_family = AF_INET;
?? ?servAddr.sin_port = htons((unsigned short)m_port);
?? ?servAddr.sin_addr.s_addr = inet_addr(m_ip);
?
?? ?setBlockOpt(m_fd,false);?? ?//設置為非阻塞模式
?? ?if( (connectFlag= connect(m_fd, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0))
?? ?{
?? ??? ?if(errno != EINPROGRESS)
?? ??? ?{
?? ??? ??? ?goto done;
?? ??? ?}
?? ?}
?? ?else
?? ?{
?? ??? ?ret = true;
?? ??? ?goto done;
?? ?}
?? ?timeval tm;
?? ?tm.tv_sec = timeout/1000;
?? ?tm.tv_usec = timeout%1000;
?? ?fd_set rest, west;
?? ?FD_ZERO(&rest);
?? ?FD_ZERO(&west);
?? ?FD_SET(m_fd, &rest);
?? ?FD_SET(m_fd, &west);
?
?? ?if( (selectFlag = select(m_fd+1, &rest, &west, NULL, &tm)) > 0)
?? ?{
?? ??? ?//如果套接口及可寫也可讀,需要進一步判斷
?? ??? ?if(FD_ISSET(m_fd, &rest) && FD_ISSET(m_fd, &west))?
?? ??? ?{
?? ??? ??? ?if(getsockopt(m_fd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len) < 0)
?? ??? ??? ?{
?? ??? ??? ??? ?printf("getsockopt error!!!\n");
?? ??? ??? ?}
?? ??? ??? ?else
?? ??? ??? ?{
?? ??? ??? ??? ?if(error == 0)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?ret = true;
?? ??? ??? ??? ?}
?? ??? ??? ??? ?else?
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?printf("connect getsockopt error!!! %d\n",error);
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ??? ?//如果套接口可寫不可讀,則鏈接完成
?? ??? ?else if(FD_ISSET(m_fd, &west) && !FD_ISSET(m_fd, &rest))?
?? ??? ?{?
?? ??? ??? ?ret = true;
?? ??? ?}
?? ?}
?? ?else if(selectFlag == 0)
?? ?{
?? ??? ?printf("connect select timeout!!!\n");
?? ?}
?? ?else?
?? ?{
?? ??? ?printf("connect select error!!!\n");
?? ?}
?? ?
done:
?? ?setBlockOpt(m_fd,true);// 設置為阻塞模式
?? ?if(!ret)
?? ?{
?? ??? ?return -1;
?? ?}
?? ?return 0;
}
?
?
int main(int argc,char* argv[])
{
?? ?if(argc <= 1)
?? ?{
?? ??? ?printf("input error!!!\n");
?? ??? ?exit(1);
?? ?}
?? ?int sockfd = socket(AF_INET, SOCK_STREAM, 0);
?? ?if(sockfd < 0)?
?? ?{
?? ??? ?exit(1);
?? ?}
?? ?if(connectWithTimeout(sockfd,atoi(argv[1])) == 0)
?? ?{
?? ??? ?printf("connect sucess!!!\n");
?? ?}
?? ?else
?? ?{
?? ??? ?printf("connect filed!!!\n");
?? ?}
?? ?close(sockfd);
?? ?
?? ?
?? ?return 0;
}


??????

???????原理很簡單,就是先把套接字設置為非阻塞,因為在非阻塞情況下,connect的結果是立即返回的,然后我們再使用select或者poll等機制來檢測套接字一定的時間,如果在超時時間內不可寫,則認為connect失敗,然后需要把套接字重新設置為阻塞,當然如果你不需要在阻塞模式下工作,可以不用設置。

??????如上,我們就可以對connect的超時進行可控。
---------------------?
版權聲明:本文為CSDN博主「clirus」的原創文章,遵循CC 4.0 by-sa版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/clirus/article/details/50577352

總結

以上是生活随笔為你收集整理的如何解决Connect超时导致的阻塞问题的全部內容,希望文章能夠幫你解決所遇到的問題。

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