linux下载文件一直超时,Linux下connect超时处理(总结)

发布时间:2021-10-27 10:20:44

1、前言


最*在写一个测试工具,要求快速的高效率的扫描出各个服务器开放了哪些端口。当时想了一下,ping只能检测ip,判断服务器的网络是连通的,而不能判断是否开放了端口。我们知道端口属于网络的传输层,因此需要用ip和端口来探测,这个时候就可以用connect来探测一下,针对TCP协议,connect函数要进行TCP三次握手,如果connect成功,则说明服务器开放了某个端口,如果connect失败,则说明服务器没有开放某个端口。而connect失败是通过超时来控制的,在规定的时间内,connect会发起多次连接,一直执行到超时,才返回错误。默认情况下,connect是阻塞的,而且默认的超时时间为75s,正常情况下,检测网络的连通性都是毫秒级,如果要判断10万台服务器的,用阻塞的默认的connect去做,效率非常低下。因此采用非阻塞的connect,而且需要自定义超时间(我自定义超时时间为5s)。


2、非阻塞connect


对于阻塞式套接字,调用connect函数将激发TCP的三次握手过程,而且仅在连接建立成功或者出错时才返回;对于非阻塞式套接字,如果调用connect函数会之间返回-1(表示出错),且错误为EINPROGRESS,表示连接建立,建立启动但是尚未完成;如果返回0,则表示连接已经建立,这通常是在服务器和客户在同一台主机上时发生。


select是一种IO多路复用机制,它允许进程指示内核等待多个事件的任何一个发生,并且在有一个或者多个事件发生或者经历一段指定的时间后才唤醒它。connect本身并不具有设置超时功能,如果想对套接字的IO操作设置超时,可使用select函数。


对于select和非阻塞connect,注意两点:[1] 当连接成功建立时,描述符变成可写; [2] 当连接建立遇到错误时,描述符变为即可读,也可写,遇到这种情况,可调用getsockopt函数。


3、实现步骤


(1) 创建socket,并利用fcntl将其设置为非阻塞


(2) 调用connect函数,如果返回0,则连接建立;如果返回-1,检查errno ,如果值为 EINPROGRESS,则连接正在建立。


(3) 为了控制连接建立时间,将该socket描述符加入到select的可读可写集合中,采用select函数设定超时。


(4) 如果规定时间内成功建立,则描述符变为可写;否则,采用getsockopt函数捕获错误信息


(5) 恢复套接字的文件状态并返回。


测试代码如下所示:


#include


#include


#include


#include


#include /* See NOTES */


#include


#include


#include


#include


int main(int argc, char **argv)


{


if (argc < 3) {


printf("please input ip and port, for example ./main 120.12.34.56 80.
");


return -1;


}


char *ipaddr = argv[1];


unsigned int port = atoi(argv[2]);


int fd = 0;


struct sockaddr_in addr;


fd_set fdr, fdw;


struct timeval timeout;


int err = 0;


int errlen = sizeof(err);


fd = socket(AF_INET,SOCK_STREAM,0);


if (fd < 0) {


fprintf(stderr, "create socket failed,error:%s.
", strerror(errno));


return -1;


}


bzero(&addr, sizeof(addr));


addr.sin_family = AF_INET;


addr.sin_port = htons(port);


inet_pton(AF_INET, ipaddr, &addr.sin_addr);


/*设置套接字为非阻塞*/


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


if (flags < 0) {


fprintf(stderr, "Get flags error:%s
", strerror(errno));


close(fd);


return -1;


}


flags |= O_NONBLOCK;


if (fcntl(fd, F_SETFL, flags) < 0) {


fprintf(stderr, "Set flags error:%s
", strerror(errno));


close(fd);


return -1;


}


/*阻塞情况下linux系统默认超时时间为75s*/


int rc = connect(fd, (struct sockaddr*)&addr, sizeof(addr));


if (rc != 0) {


if (errno == EINPROGRESS) {


printf("Doing connection.
");


/*正在处理连接*/


FD_ZERO(&fdr);


FD_ZERO(&fdw);


FD_SET(fd, &fdr);


FD_SET(fd, &fdw);


timeout.tv_sec = 10;


timeout.tv_usec = 0;


rc = select(fd + 1, &fdr, &fdw, NULL, &timeout);


printf("rc is: %d
", rc);


/*select调用失败*/


if (rc < 0) {


fprintf(stderr, "connect error:%s
", strerror(errno));


close(fd);


return -1;


}


/*连接超时*/


if (rc == 0) {


fprintf(stderr, "Connect timeout.
");


close(fd);


return -1;


}


/*[1] 当连接成功建立时,描述符变成可写,rc=1*/


if (rc == 1 && FD_ISSET(fd, &fdw)) {


printf("Connect success
");


close(fd);


return 0;


}


/*[2] 当连接建立遇到错误时,描述符变为即可读,也可写,rc=2 遇到这种情况,可调用getsockopt函数*/


if (rc == 2) {


if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {


fprintf(stderr, "getsockopt(SO_ERROR): %s", strerror(errno));


close(fd);


return -1;


}


if (err) {


errno = err;


fprintf(stderr, "connect error:%s
", strerror(errno));


close(fd);


return -1;


}


}


}


fprintf(stderr, "connect failed, error:%s.
", strerror(errno));


return -1;


}


return 0;


}



以上就是本文的全部内容,希望对大家的学*有所帮助,也希望大家多多支持脚本之家。

相关文档

  • 什么是不计免赔险不计免赔险无效情况
  • Java知识点??初识
  • 销售团队晨会励志口号
  • 基于ISO,26000的煤炭企业社会责任的初探|企业的社会责任包括哪些
  • 关于海洋公园观后感范文
  • 女生宿舍的关系有多复杂如何看待女生宿舍的关系
  • 我国上市公司资产重组绩效评价的研究分析论文
  • 三星手机号码突然没了怎么办
  • 2021武汉日夜精品观后感学生
  • 英语四六级高分攻略
  • access更新查询非汉族加分_【2019更新版】大连理工大学计算机软件考研信息汇总...
  • shell下cat EOF中变量$处理
  • 快手怎么把动作放慢
  • 青团可以常温保存吗,青团常温保存几天!
  • 庆六一辅导员讲话
  • 中秋节的成语蹉跎岁月的近义词和反义词及造句
  • 三星smg9650参数
  • 仙人球的生命力
  • 未结婚财产怎么分配
  • 乡愁课文教学过程
  • 给罗思小朋友的一封信
  • 同时有苯环和双键怎么命名
  • 三角剪纸荷花的步骤简单易懂
  • 端午节的风俗作文
  • linux信号捕捉
  • 关于礼物的作文600字 爱的礼物
  • 微信可以办身份证是不是真的
  • 关于中考的抒情散文推荐
  • 人生格言语录大全精选2017
  • 唯美昵称女生简短好听
  • 猜你喜欢

    电脑版