当前位置: 首页 > news >正文

东莞北京网站建设价格低h5网站后台管理模板

东莞北京网站建设价格低,h5网站后台管理模板,win7iis如何做网站,北京网站建转载 主要内容#xff1a;TCP定时器概述#xff0c;超时重传定时器、ER延迟定时器、PTO定时器的实现。 内核版本#xff1a;3.15.2 我的博客#xff1a;http://blog.csdn.net/zhangskd Q#xff1a;一条TCP连接会使用多少个定时器呢#xff1f; A#xff1a;目前的答案… 转载 主要内容TCP定时器概述超时重传定时器、ER延迟定时器、PTO定时器的实现。 内核版本3.15.2 我的博客http://blog.csdn.net/zhangskd Q一条TCP连接会使用多少个定时器呢 A目前的答案是9个 超时重传定时器持续定时器ER延迟定时器PTO定时器ACK延迟定时器 SYNACK定时器保活定时器FIN_WAIT2定时器TIME_WAIT定时器。 数据结构 几种定时器的标识 #define ICSK_TIME_RETRANS 1 /* Retransmit timer */ #define ICSK_TIME_DACK 2 /* Delayed ack timer */ #define ICSK_TIME_PROBE0 3 /* Zero window probe timer */ #define ICSK_TIME_EARLY_RETRANS 4 /* Early retransmit timer */ #define ICSK_TIME_LOSS_PROBE 5 /* Tail loss probe timer */ 上述5种定时器分别为超时重传定时器、ACK延迟定时器、持续定时器、ER延迟定时器、PTO定时器。 另外还有保活定时器、FIN_WAIT2定时器、TIME_WAIT定时器、SYNACK定时器。 虽然定义了9个定时器但是内核中只用了4个实例(timer_list)所以有些定时器是共用一个实例的。 这4个实例分别是 icsk-icsk_retransmit_timer超时重传定时器、持续定时器、ER延迟定时器、PTO定时器。 icsk-icsk_delack_timerACK延迟定时器。 sk-sk_timer保活定时器SYNACK定时器FIN_WAIT2定时器。 death_row-tw_timerTIME_WAIT定时器。 创建和删除 (1) 定时器的创建 tcp_v4_init_sock |- tcp_init_sock |- tcp_init_xmit_timers |- inet_csk_init_xmit_timers 在初始化连接时设置三个定时器实例的处理函数 icsk-icsk_retransmit_timer的处理函数为tcp_write_timer() icsk-icsk_delack_timer的处理函数为tcp_delack_timer() sk-sk_timer的处理函数为tcp_keepalive_timer() void tcp_init_xmit_timers(struct sock *sk) {inet_csk_init_xmit_timers(sk, tcp_write_timer, tcp_delack_timer, tcp_keepalive_timer); } /** Using different timers for retransmit, delayed acks and probes.* We may wish use just one timer maintaining a list of expire jiffies to optimize.*/void inet_csk_init_xmit_timers(struct sock *sk, void (*retransmit_handler) (unsigned long),void (*delack_handler) (unsigned long),void (*keepalive_handler) (unsigned long)) {struct inet_connection_sock *icsk inet_csk(sk);setup_timer(icsk-icsk_retransmit_timer, retransmit_handler, (unsigned long)sk);setup_timer(icsk-icsk_delack_timer, delack_timer, (unsigned long)sk);setup_timer(sk-sk_timer, keepalive_handler, (unsigned long)sk);icsk-icsk_pending icsk-icsk_ack.pending 0; }(2) 定时器的删除 tcp_done tcp_disconnect tcp_v4_destroy_sock |- tcp_clear_xmit_timers |- inet_csk_clear_xmit_timers void inet_csk_clear_xmit_timers(struct sock *sk) {struct inet_connection_sock *icsk inet_csk(sk);icsk-icsk_pending icsk-icsk_ack.pending icsk-icsk_ack.blocked 0;sk_stop_timer(sk, icsk-icsk_retransmit_timer);sk_stop_timer(sk, icsk-icsk_delack_timer);sk_stop_timer(sk, sk-sk_timer); } 激活 icsk-icsk_retransmit_timer和icsk-icsk_delack_timer的激活函数为inet_csk_reset_xmit_timer() 共负责了5个定时器的激活工作。 /** Reset the retransmissiion timer*/ static inline void inet_csk_reset_xmit_timer(struct sock *sk, const int what,unsigned long when,const unsigned long max_when) {struct inet_connection_sock *icsk inet_csk(sk);if (when max_when) { #ifdef INET_CSK_DEBUGpr_debug(reset_xmit_timer: sk%p %d when0x%lx, caller%p\n,sk, what, when, current_text_addr()); #endifwhen max_when;}if (what ICSK_TIME_RETRANS || what ICSK_TIME_PROBE0 || what ICSK_TIME_EARLY_RETRANS || what ICSK_TIME_LOSS_PROBE) {icsk-icsk_pending what;icsk-icsk_timeout jiffies when; /*数据包超时时刻*/sk_reset_timer(sk, icsk-icsk_retransmit_timer, icsk-icsk_timeout);} else if (what ICSK_TIME_DACK) {icsk-icsk_ack.pending | ICSK_ACK_TIMER;icsk-icsk_ack.timeout jiffies when; /*Delay ACK定时器超时时刻*/sk_reset_timer(sk, icsk-icsk_delack_timer, icsk-icsk_ack.timeout);} #ifdef INET_CSK_DEBUGelse {pr_debug(%s, inet_csk_timer_bug_msg);} #endif }其中超时重传定时器(ICSK_TIME_RETRANS)在以下几种情况下会被激活 1. 发现对端把保存在接收缓冲区的SACK段丢弃时。 2. 发送一个数据段时发现之前网络中不存在发送且未确认的段。 之后每当收到确认了新数据段的ACK则重置定时器。 3. 发送SYN包后。 4. 一些特殊情况。 超时处理函数 当icsk-icsk_retransmit_timer超时后会调用其处理函数tcp_write_timer()进行处理。 staic void tcp_write_timer(unsigned long data) {struct sock *sk (struct sock *)data;bh_lock_sock(sk);if (! sock_owned_by_user(sk)) { /* sk没被用户空间占用 */tcp_write_timer_handler(sk);} else { /* 否则先设置延迟标志之后再处理 *//* delegate our work to tcp_release_cb() */if (! test_and_set_bit(TCP_WRITE_TIMER_DEFERRED, tcp_sk(sk)-tsq_flags))sock_hold(sk);}bh_unlock_sock(sk);sock_put(sk); }icsk-icsk_retransmit_timer可同时作为超时重传定时器、持续定时器、ER延迟定时器、PTO定时器 所以需要判断是哪种定时器触发的然后采取相应的处理措施。 void tcp_write_timer_handler(struct sock *sk) {struct inet_connection_sock *icsk inet_csk(sk);int event;/* 如果连接处于CLOSED状态或者没有定时器在计时 */if (sk-sk_state TCP_CLOSE || !icsk-icsk_pending)goto out;/* 如果定时器还没有超时那么继续计时 */if (time_after(icsk-icsk_timeout, jiffies)) {sk_reset_timer(sk, icsk-icsk_retransmit_timer, icsk-icsk_timeout);goto out;}event icsk-icsk_pending; /* 用于表明是哪种定时器 */switch(event) {case ICSK_TIME_EARLY_RETRANS: /* ER延迟定时器触发的 */tcp_resume_early_retransmit(sk); /* 进行early retransmit */break;case ICSK_TIME_LOSS_PROBE: /* PTO定时器触发的 */tcp_send_loss_probe(sk); /* 发送TLP探测包 */break;case ICSK_TIME_RETRANS: /* 超时重传定时器触发的 */icsk-icsk_pending 0;tcp_retransmit_timer(sk);break;case ICSK_TIME_PROBE0: /* 持续定时器触发的 */icsk-icsk_pending 0;tcp_probe_timer(sk);break;}out:sk_mem_reclaim(sk); }如果是超时重传定时器触发的就会调用tcp_retransmit_timer()进行处理。  void tcp_retransmit_timer(struct sock *sk) {struct tcp_sock *tp tcp_sk(sk);struct inet_connection_sock *icsk inet_csk(sk);/* Fast Open特性相关暂时不做分析 */if (tp-fastopen_rsk) {...}/* 如果没有发送且未确认的数据段没有等待哪来的超时直接返回 */if (! tp-packets_out)goto out; /* 如果发送队列为空显然不合理 */WARN_ON(tcp_write_queue_empty(sk));/* 发生RTO超时表明数据包的确丢失了所以不用再进行额外检测了 */tp-tlp_high_seq 0;/* 如果对端通告窗口为0sk不处于DEAD状态TCP连接不处于三次握手 *//* Receiver dastardly shrinks window. Our retransmits become zero probes,* but we should not timeout this connection. If the socket is an orphan, time it out,* we cannot allow such beasts to hang infinitely. */if (! tp-snd_wnd ! sock_flag(sk, SOCK_DEAD) ! ((1 sk-sk_state) (TCPF_SYN_SENT | TCPF_SYN_RECV))) {struct inet_sock *inet inet_sk(sk);if (sk-sk_family AF_INET) {LIMIT_NETDEBUG(KERN_DEBUG pr_fmt(Peer %pI4:%u/ %u unexpectedly shrunk window %u:%u (repaired)\n,inet-inet_daddr, ntohs(inet-inet_dport), inet-inet_num, tp-snd_una, tp-snd_nxt);}#if IS_ENABLED(CONFIG_IPV6)/* IPv6的处理此处省略 */... #endif/* 距离上次收到ACK的时间超过了最大超时时间认为有错误发生了*/if (tcp_time_stamp - tp-rcv_tstamp TCP_RTO_MAX) {tcp_write_err(sk); /* 报告错误调用tcp_done终止连接 */goto out;}/* 进入Loss状态标志丢失的数据段 */tcp_enter_loss(sk, 0);/* 重传发送队列的第一个数据段 */tcp_retransmit_skb(sk, tcp_write_queue_head(sk));__sk_dst_reset(sk); /* 更新路由缓存 */goto out_reset_timer;}/* 如果重传次数达到上限报告错误并关闭套接口。* 如果资源使用达到上限放弃本次重传。*/if (tcp_write_timeout(sk))goto out;/* 刚进入超时重传 */if (icsk-icsk_retransmits 0) {int mib_idx;/* Recovery状态中发生超时 */if (icsk-icsk_ca_state TCP_CA_Recovery) {if (tcp_is_sack(tp))mib_idx LINUX_MIB_TCPSACKRECOVERYFAIL;elsemib_idx LINUX_MIB_TCPRENORECOVERYFAIL;} else if (icsk-icsk_ca_state TCP_CA_Loss) { /* Loss状态中发生超时 */ mib_idx LINUX_MIB_TCPLOSSFAILURES;} else if (icsk-icsk_ca_state TCP_CA_Disorder) || tp-sacked_out) {/* Disorder状态中发生超时 */if (tcp_is_sack(tp))mib_idx LINUX_MIB_TCPSACKFAILURES;elsemib_idx LINUX_MIB_TCPRENOFAILURES;} else { /* Open状态或CWR状态中发生超时 */mib_idx LINUX_MIB_TCPTIMEOUTS;}NET_INC_STATS_BH(sock_net(sk), mib_idx);}/* 进入Loss状态标志丢失的数据段。* 值得注意的是不再使用tcp_enter_frto_loss()FRTO机制被重写了。*/tcp_enter_loss(sk, 0);/* 重传发送队列的第一个数据段如果失败说明是本地拥塞那么不进行指数退避 */if (tcp_retransmit_skb(sk, tcp_write_queue_head(sk)) 0) {/* Retransmission failed because of local congestion, do not backoff. */if (! icsk-icsk_retransmits)icsk-icsk_retransmits 1;inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, min(icsk-icsk_rto, TCP_RESOURCE_PROBE_INTERVAL),TCP_RTO_MAX);goto out;}icsk-icsk_backoff; /* 退避指数采集到新的RTT样本时清零 */icsk-icsk_retransmits; /* 超时次数当确认了新数据时清零 */out_reset_timer:/* 对于符合条件的Thin stream不使用指数退避重复超时6次后除外太惨了 */if (sk-sk_state TCP_ESTABLISHED (tp-thin_lto || sysctl_tcp_thin_linear_timeouts) tcp_stream_is_thin(tp) icsk-icsk_retransmits TCP_THIN_LINEAR_RETRIES) {icsk-icsk_backoff 0;icsk-icsk_rto min(__tcp_set_rto(tp), TCP_RTO_MAX); /* RTO保持原样 */} else { /* Use normal (exponential) backoff */icsk-icsk_rto min(icsk-icsk_rto 1, TCP_RTO_MAX); /* RTO翻倍 */}/* 重置超时定时器就是上文说的激活 */inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk-icsk_rto, TCP_RTO_MAX);/* 当重传多次时需要根据重传时间间隔决定是否更新路由缓存 */if (retransmits_timed_out(sk, sysctl_tcp_retries1 1, 0, 0))__sk_dst_reset(sk);out:; } 连接的超时 很明显重传不能无限的进行下去当重传的次数超过设定的上限时就会判定连接超时关闭该连接。 此后相应的socket函数比如connect和send就会返回-1errno设为ETIMEDOUT表示连接超时。 判定连接是否超时如果超过了最大等待时间就放弃此连接。 /* A write timeout has occurred. Process the after effects. */ static int tcp_write_timeout (struct sock *sk) {struct inet_connection_sock *icsk inet_csk(sk);struct tcp_sock *tp tcp_sk(sk);int retry_until;bool do_reset, syn_set false;/* 如果超时是发生在三次握手期间 */if ((1 sk-sk_state) (TCPF_SYN_SENT | TCPF_SYN_RECV)) {if (icsk-icsk_retransmits) { /* 如果之前重传过了 */dst_negative_advice(sk); /* 更新目的路由缓存 *//* SYN携带Fast Open选项或SYN携带数据 */if (tp-syn_fastopen || tp-syn_data)tcp_fastopen_cache_set(sk, 0, NULL, true);if (tp-syn_data)NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPFASTOPENACTIVEFAIL);}/* SYN的最大重传次数由TCP_SYNCNT选项和tcp_syn_retries参数决定默认是5次 */retry_until icsk-icsk_syn_retries ?: sysctl_tcp_syn_retries;syn_set true;} else {/* tcp_retries1默认为3当重传次数超过此值时表示可能遇到了黑洞需要进行PMTU* 检测同时更新路由缓存。*/if (retransmits_timed_out(sk, sysctl_tcp_retries1, 0, 0)) {/* Black hole detection */tcp_mtu_probing(icsk, sk); /* PMTU检测 */dst_negative_advic(sk); /* 更新路由缓存 */}retry_until sysctl_tcp_retries2; /* 在断开TCP连接之前最多进行多少次重传默认值为15 *//* 如果当前套接口即将关闭 */if (sock_flag(sk, SOCK_DEAD)) {const int alive (icsk-icsk_rto TCP_RTO_MAX);retry_until tcp_orphan_retries(sk, alive); /* 决定重传次数 */do_reset alive || ! retransmits_timed_out(sk, retry_until, 0, 0);/* 如果当前的孤儿socket数量超过tcp_max_orphans或者内存不够时关闭此连接 */if (tcp_out_of_resources(sk, do_reset))return 1;}}/* 判定连接是否等待过久即是否超时 */if (retransmits_timed_out(sk, retry_until, syn_set ? 0 : icsk-icsk_user_timeout, syn_set)) {/* Has it gone just too far ? */tcp_write_err(sk);return 1;} }/* Calculate maximal number or retries on an orphaned socket. */ static int tcp_orphan_retries (struct sock *sk, int alive) {int retries sysctl_tcp_orphan_retries; /* May be zero. *//* We know from an ICMP that something is wrong. */if (sk-sk_err_soft !alive)retries 0;/* However, if socket sent something recently, select some safe number of retries.* 8 corresponds to 100 seconds with minimal RTO of 200msec.*/if (retries 0 alive)retries 8;return retries; }判断连接是否超时要分为3种情况。 1. SYN包当SYN包的重传次数达到上限时判定连接超时。(默认允许重传5次初始超时时间为1s总共历时31s) 2. 非SYN包用户使用TCP_USER_TIMEOUT当数据包发出去后的等待时间超过用户设置的时间时判定连接超时。 3. 非SYN包用户没有使用TCP_USER_TIMEOUT当数据包发出去后的等待时间超过以TCP_RTO_MIN为初始超时 时间重传boundary次所花费的时间后判定连接超时。 如果返回值为真判定连接超时则关闭连接把errno设置为ETIMEDOUTSocket函数返回-1。 boundary为最大重传次数timeout为用户设置的超时时间。(通过TCP_USER_TIMEOUT选项设置) struct tcp_sock {.../* Timestamp of the last retransmit, also used in SYN-SENT to remember stamp of* the first SYN.*//* 上面的注释是错误的变量的含义为* 1. 原始SYN包的发送时间点不是重传的。* 2. 本次重传时第一个被重传的包原始包的发送时间点。* 这个变量是用来计算连接的超时关闭时间一个包发送多久还没有得到响应就判断连接超时。*/u32 retrans_stamp; ... };/* This function calculates a timeout which is equivalent to the timeout of a TCP connection* after boundary unsuccessful, exponentially backed-off retransmissions with an initial RTO* of TCP_RTO_MIN or TCP_TIMEOUT_INIT if syn_set flag is set.*/ static bool retransmits_timed_out (struct sock *sk, unsigned int boundary, unsigned int timeout,bool syn_set) {unsigned int linear_backoff_thresh, start_ts;/* 如果是SYN包则默认的初始超时时间为1s否则为200ms。*/unsigned int rto_base syn_set ? TCP_TIMEOUT_INIT : TCP_RTO_MIN;if (! inet_csk(sk)-icsk_retransmits))return false; /* 如果之前没有重传过直接返回false *//* start_ts为开始计时点注意是原始包第一次被发送时的时间戳不是重传包的 */if (unlikely(! tcp_sk(sk)-retrans_stamp)) start_ts TCP_SKB_CB(tcp_write_queue_head(sk))-when;elsestart_ts tcp_sk(sk)-retrans_stamp;/* 包括两种情况* SYN包timeout始终设置为0因为在三次握手时TCP_USER_TIMEOUT是无效的。* 非SYN包用户没有使用TCP_USER_TIMEOUT选项时。*/if (likely(timeout 0)) { /* 当rto不超过最大值时能够进行多少次指数退避。* 以SYN包为例rto_base为1s此值向上取整为7。*/linear_backoff_thresh ilog2(TCP_RTO_MAX/rto_base); /* 从计时点开始经过boundary次重传后总共花费的时间 */if (boundary linear_backoff_thresh)timeout ((2 boundary) -1) * rto_base; elsetimeout ((2 linear_backoff_thresh) -1) * rto_base (boundary - linear_backoff_thresh) * TCP_RTO_MAX;} return (tcp_time_stamp - start_ts) timeout; /* 判断等待时间是否过长即是否要放弃连接 */
http://www.pierceye.com/news/455302/

相关文章:

  • 企业专业网站设计公wordpress打开慢
  • 网站制作方案怎么做青岛住房和城乡建设部网站
  • 织梦系统做的网站忘记登录密码百家 主题 wordpress
  • 营销推广软文婚纱摄影网站seo方案
  • 上海网站制作网站建设汶川县建设局网站
  • 东莞seo网站推广怎么做能够让网站流量大
  • 郑州网站建设做推广吗灰色关键词排名方法
  • 在线推广企业网站的方法有哪些网站推广到海外怎么做
  • 怎么用视频做网站首页php网站开发职位
  • 网站平台怎么做typecho跟wordpress
  • 网站建设找什么公司微网站建设流程
  • 如何制作数据库网站哔哩哔哩推广平台
  • 免费建立手机网站网站建设下载模板之后怎么修改
  • wordpress 网站暂停做社区生意的网站
  • 渭南做网站的公司商业网站后缀名
  • 凡科建站电话邙山网站建设
  • 哪些网站可以做ppi小程序源码什么意思
  • 做公司网站都需要哪些东西产品画册设计公司
  • 网页优化与网站优西安开发网站建设
  • 大连建设监察执法网站免费icp备案服务码
  • 潮州做网站京东网站建设步骤
  • 遂宁模板建站公司懂福溶州做戒网站
  • 百度网站下拉排名农村电商平台发展现状
  • 移动端网站开发与网页开发区别wordpress首页文章显示
  • 有什么网站是layui做的wordpress 微信咨询菜单
  • 湖南网站seo营销x cache wordpress
  • 网站建设太金手指六六十八知名网站建设推荐
  • WordPress找不到站点做好评做销量的网站
  • 网站建设项目经历东莞市官网网站建设企业
  • FileZilla做网站程序开发的难点