最近在linux做服务器开发的时候,发现了一个现象:服务器在启动的时候调用了 connect 函数,因为连接了一个不可用的端口,导致connect最后报出了 “Connection timed out” 的错误。但是这中间过了六十多秒的时间。

为何会等待这么长的时间才超时呢?这个时间又在哪里设置?

《UNIX网络编程(第一卷)——套接口 API 和 X/Open 传输接口 API》一书的4.3节有写到:

  对于TCP套接口来说,函数 connect 激发TCP的三路握手过程,且仅在链接成功建立或出错时才返回,返回的错误可能有如下几种情况:

  1. 如果TCP客户没有收到SYN分节的响应,则返回ETIMEDOUT。例如在4.4BSD中,当调用函数 connect 时,发出一个SYN,若无响应,等待6秒之后再发一个;若仍无响应,24秒钟之后再发一个。若总共等待了75秒钟之后仍未响应,则返回错误...

从书中可以看到 connect 建立TCP链接的过程中,会发送SYN包,如果没有收到SYN包的回包,内核会多次发送SYN包,并且每次重试的间隔会逐渐增加,避免发送太多的SYN包影响网络。

在CentOS上,这个重试次数是可以设置的:

$ sysctl net.ipv4 | grep tcp
net.ipv4.tcp_timestamps =
net.ipv4.tcp_window_scaling =
net.ipv4.tcp_sack =
net.ipv4.tcp_retrans_collapse =
net.ipv4.tcp_syn_retries = 5
net.ipv4.tcp_synack_retries =
net.ipv4.tcp_max_orphans =
net.ipv4.tcp_max_tw_buckets =
net.ipv4.tcp_keepalive_time =
net.ipv4.tcp_keepalive_probes =
net.ipv4.tcp_keepalive_intvl =
net.ipv4.tcp_retries1 =
net.ipv4.tcp_retries2 =
net.ipv4.tcp_fin_timeout =
net.ipv4.tcp_syncookies =
net.ipv4.tcp_tw_recycle =
net.ipv4.tcp_abort_on_overflow =
net.ipv4.tcp_stdurg =
net.ipv4.tcp_rfc1337 =
net.ipv4.tcp_max_syn_backlog =
net.ipv4.tcp_orphan_retries =
net.ipv4.tcp_fack =
net.ipv4.tcp_reordering =
net.ipv4.tcp_ecn =
net.ipv4.tcp_dsack =
net.ipv4.tcp_mem =
net.ipv4.tcp_wmem =
net.ipv4.tcp_rmem =
net.ipv4.tcp_app_win =
net.ipv4.tcp_adv_win_scale =
net.ipv4.tcp_tw_reuse =
net.ipv4.tcp_frto =
net.ipv4.tcp_frto_response =
net.ipv4.tcp_low_latency =
net.ipv4.tcp_no_metrics_save =
net.ipv4.tcp_moderate_rcvbuf =
net.ipv4.tcp_tso_win_divisor =
net.ipv4.tcp_congestion_control = cubic
net.ipv4.tcp_abc =
net.ipv4.tcp_mtu_probing =
net.ipv4.tcp_base_mss =
net.ipv4.tcp_workaround_signed_windows =
net.ipv4.tcp_challenge_ack_limit =
net.ipv4.tcp_limit_output_bytes =
net.ipv4.tcp_dma_copybreak =
net.ipv4.tcp_slow_start_after_idle =
net.ipv4.tcp_available_congestion_control = cubic reno
net.ipv4.tcp_allowed_congestion_control = cubic reno
net.ipv4.tcp_max_ssthresh =
net.ipv4.tcp_thin_linear_timeouts =
net.ipv4.tcp_thin_dupack =
net.ipv4.tcp_min_tso_segs =
net.ipv4.tcp_invalid_ratelimit =

其中的 net.ipv4.tcp_syn_retries 选项控制着SYN的重试次数,可以通过如下命令来查看和设置:

$ sysctl net.ipv4.tcp_syn_retries       #查看
net.ipv4.tcp_syn_retries =
$ sudo sysctl -w net.ipv4.tcp_syn_retries=1 #设置
net.ipv4.tcp_syn_retries =

下面用一个简单的程序,来验证各种次数下的connect超时时间:

#include <iostream>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h> long long GetCurrentMSecond()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * + tv.tv_usec / ;
} int main()
{
int fd = ;
struct sockaddr_in addr; fd = socket(AF_INET, SOCK_STREAM, ); socklen_t bufSize = * ;
int retCode = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufSize, sizeof(bufSize));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.207.128");
addr.sin_port = htons(); //连接一个不用的端口,以保证会触发超时
long long llBeginTime = GetCurrentMSecond();
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -)
{
long long llEndTime = GetCurrentMSecond();
std::cout << "connect failed, errno: " << errno << ", error: " << strerror(errno)
<< ", cost time: " << llEndTime - llBeginTime << std::endl;
return ;
}
std::cout << "connect success" << std::endl;
}

通过设置不同的重试次数,探究各种重试次数下的time out时间:

$ g++ connect.cpp -o main
$ sudo sysctl -w net.ipv4.tcp_syn_retries=1
net.ipv4.tcp_syn_retries = 1
$ ./main
connect failed, errno: 110, error: Connection timed out, cost time: 3000
$ sudo sysctl -w net.ipv4.tcp_syn_retries=2
net.ipv4.tcp_syn_retries = 2
$ ./main
connect failed, errno: 110, error: Connection timed out, cost time: 7000
重试次数 超时时间(单位:毫秒)
1 3000  
2 7000
3 14999
4 31000
5 63001
6 126999

从表格中可以看到,当前设置重试次数为5的时候,超时时间是63秒,可以通过修改重试次数的方式,来改变connect的超时时间。

linux下connect超时时间探究的更多相关文章

  1. Linux下connect超时处理【总结】

    1.前言 最近在写一个测试工具,要求快速的高效率的扫描出各个服务器开放了哪些端口.当时想了一下,ping只能检测ip,判断服务器的网络是连通的,而不能判断是否开放了端口.我们知道端口属于网络的应用层, ...

  2. Linux下connect超时处理

    1.前言 最近在写一个测试工具,要求快速的高效率的扫描出各个服务器开放了哪些端口.当时想了一下,ping只能检测ip,判断服务器的网络是连通的,而不能判断是否开放了端口.我们知道端口属于网络的传输层, ...

  3. 设置linux中tcp默认的20秒connect超时时间(转)

    无论你用任何语言或者是网络库,你都可以设置网络操作的超时时间,特别是connect.read.write的超时时间. 你可以在代码中把超时时间设置任意大小值,但是connect方法会有一点特殊. co ...

  4. Linux下获得系统时间的C语言实现

    Linux下获得系统时间的C语言的实现方法 #include<time.h> //C语言的头文件#include<stdio.h> //C语言的I/O   int main() ...

  5. 解决Linux下SSH超时自动断开

    title: 解决Linux下SSH超时自动断开 comments: false date: 2019-08-19 19:22:55 description: Linux 下 SSH 超时自动断开?? ...

  6. linux 设置connect 超时代码[select/epoll]

    转载请注明来源:https://www.cnblogs.com/hookjc/ linux下socket编程有常见的几个系统调用: 对于服务器来说, 有socket(), bind(),listen( ...

  7. linux 设置connect 超时

    转载请注明来源:https://www.cnblogs.com/hookjc/ 将一个socket 设置成阻塞模式和非阻塞模式,使用fcntl方法,即: 设置成非阻塞模式: 先用fcntl的F_GET ...

  8. VC socket Connect 超时时间设置

    设置connect超时很简单,CSDN上也有人提到过使用select,但却没有一个令人满意与完整的答案.偶所讲的也正是select函数,此函数集成在winsock1.1中,简单点讲,"作用使 ...

  9. Linux下修改系统时间并写入BIOS

    我们一般使用“date -s”命令来修改系统时间.比如将系统时间设定成2005年7月26日的命令如下. #date -s 07/26/2005 将系统时间设定成下午11点12分0秒的命令如下. #da ...

随机推荐

  1. php7+Redis+Windows7安装 (phpstudy)

    1.首先去github网站上下载https://github.com/dmajkic/redis/downloads: 2.根据实际情况,将64bit的内容cp到自定义盘符目录,如D:\Redis; ...

  2. 微信小程序(1)——小程序的特点以及结构

    简单的,用完即走的应用 低频应用 性能要求不高的应用 应用程序入口(app.js   app.json  app.wxss) 一级页面:wxml,wxss,js,json 二级页面:wxml,wxss ...

  3. 【angularJS】Filter 过滤器

    当从后台获取到的数据呈现到视图上时,此时可能需要对数据进行相应的转换,此时我们可以通过过滤器在不同页面进行不同数据的格式抓换,在AngularJS中有常见默认的过滤器,当然若不满足所需,我们可以自定义 ...

  4. 【剑指offer】Q14:调整数组顺序使奇数位于偶数前面

    def isOdd(n): return n & 1 def Reorder(data, cf = isOdd): odd = 0 even = len( data ) - 1 while T ...

  5. centos6.6安装SVN服务器(2015/3/7)

    一.安装#yum install subversion  判断是否安装成功  [root@]# svnserve --version有了SVN软件后还需要建立SVN库.#mkdir /opt/svn/ ...

  6. 7个去伪存真的JavaScript面试题

    1.创建JavaScript对象的两种方法是什么? 这是一个非常简单的问题,如果你用过JavaScript的话.你至少得知道一种方法.但是,尽管如此,根据我的经验,也有很多自称是JavaScript程 ...

  7. 工业标准接口OPC Server

    工业标准接口OPC  Server OPC Server服务器软件,简称OPCServer,是针对企业生产过程中所涉及到的各种DCS.PLC.组态软件.电力综合自动化等控制系统.测量系统.其它辅助生产 ...

  8. Charles-断点

    一.添加Charles断点 1.用Charles抓包发起一次接口请求 2.对要打断点的接口右键,选择[Breakpoints] 二.Charles断点设置 1.点击Charles菜单-[Proxy]- ...

  9. java代码----I/O流从控制台输入信息判断并抛出异常

    package com.a.b; import java.io.*; public class Yu { public static void main(String[] args) throws I ...

  10. java项目-----客户端与客户端通信--实现群聊功能的代码

    这是这个网络聊天室项目的原理图: 很简单,首先ABCD是4个客户端,当A发送信息给服务器,服务器实现以广播的形式把信息全发给每个人---群发群聊 客户端代码: package com.aa; impo ...