精华内容
下载资源
问答
  • 测试偶尔访问指定网站速度慢的原因1 现象 某业务在客户服务器上,开发人员反映周期性速度慢,开发人员反馈,由于需要到xxx.com...4 最终原因 操作系统启用了TCP ECN,而目的地路由器未使用ECN 导致TCP握手时间延长n...

    测试偶尔访问指定网站速度慢的原因
    1 现象 某业务在客户服务器上,开发人员反映周期性速度慢,开发人员反馈,由于需要到xxx.com去取数据,慢的原因是取数据慢
    直接访问该站点下载文件发下下载速度很快
    2 测试脚本如下

    3 测试结果发现 是每次第一次访问xxx.com的时候的 建立连接的时间很慢,需要9秒以上

    4 最终原因 操作系统启用了TCP ECN,而目的地路由器未使用ECN 导致TCP握手时间延长
    netsh interface tcp set global ecncapability=disabled 关闭后正常

    5 没有介绍TCP ECN 只是介绍如何发现问题原因


    #!/bin/env python
    # -*- coding: utf-8-*-
    #author: skybug
    #date: 2017-12-2
    #web_perf_test
    import urllib2,sys,pycurl,json,StringIO
    import os,subprocess
    import platform,_winreg
    #ipvip = socket.gethostbyname ("www.xxx.com")#获取DNS解析值 本次未用
    reload(sys)
    sys.setdefaultencoding('utf-8')
    iplist = ["113.x.x.1","113.x.x.x","x.x.x.x","x.x.x.x","x.x.x.x"]#vipgate,vip,cnki,cnki2,chaoxing
    urllist=["http://x.com","http://a.com"]
    UA = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Mobile Safari/537.36"
    headers = {}
    def header_function(header_line):  #获取响应头,本次未调用
        header_line = header_line.decode('iso-8859-1')
        if ':' not in header_line:
            return
        name, value = header_line.split(':', 1)
        name = name.strip()
        value = value.strip()
        name = name.lower()
        headers[name] = value
    def webperf_keep(url,times=1): #获取访问页面的性能数据
        b = StringIO.StringIO() #定义个IO流
        pc=pycurl.Curl()#创建pycurl对象
        cnt=0
        alldata=[]
        for i in range(int(times)):
            pc.setopt(pycurl.URL,url) #设置访问url
            pc.setopt(pycurl.HTTPHEADER, ['Content-Type: application/json'])
            pc.setopt (pycurl.USERAGENT,UA)#设置UA
            pc.setopt(pycurl.MAXREDIRS,50) #MAX REDIRECT count#设置最大重定向次数
            pc.setopt(pycurl.WRITEFUNCTION, b.write)#把相应内容写到流里
            pc.setopt( pycurl.FOLLOWLOCATION,1)#跟踪重定向
            pc.setopt(pycurl.FORBID_REUSE, 0)#允许复用连接
            pc.setopt(pycurl.FRESH_CONNECT,0)
            pc.setopt (pycurl.HEADERFUNCTION, header_function)#把头信息写到头函数里
            print "testing access {0} {1} times.....".format (url, cnt)
            pc.perform()#执行pycurl
            cnt+=1
            dns_time = pc.getinfo(pycurl.NAMELOOKUP_TIME)#dns解析时间
            conn_time = pc.getinfo(pycurl.CONNECT_TIME)#建立连接的时间(TCP握手)
            ttfb = pc.getinfo(pycurl.STARTTRANSFER_TIME)#TTFB的时间
            total_time = pc.getinfo(pycurl.TOTAL_TIME)#总时间
            http_code = pc.getinfo(pycurl.HTTP_CODE)#返回code
            http_conn_code= pc.getinfo(pycurl.HTTP_CONNECTCODE)#
            redirect_count = pc.getinfo(pycurl.REDIRECT_COUNT)#重定向次数
            size_upload = pc.getinfo(pycurl.SIZE_UPLOAD)
            size_download = pc.getinfo(pycurl.SIZE_DOWNLOAD)
            size_header = pc.getinfo(pycurl.HEADER_SIZE)
            size_request = pc.getinfo(pycurl.REQUEST_SIZE)
            content_type = pc.getinfo(pycurl.CONTENT_TYPE)
            reponse_code = pc.getinfo(pycurl.RESPONSE_CODE)
            transfer_time = pc.getinfo(pycurl.PRETRANSFER_TIME) #传输时间
            startrans_time= pc.getinfo(pycurl.STARTTRANSFER_TIME)#开始传输时间
            speed_download = pc.getinfo(pycurl.SPEED_DOWNLOAD)#下载速度
            speed_upload = pc.getinfo(pycurl.SPEED_UPLOAD)#上传速度
            redirect_time = pc.getinfo(pycurl.REDIRECT_TIME)#重定向时间
            num_conn = pc.getinfo(pycurl.NUM_CONNECTS)#建立连接的次数
            last_socket= pc.getinfo(pycurl.LASTSOCKET)#最后一个socker
            data = []
            perfdata={"dns_time":dns_time,"ttfb":ttfb,"total_time":total_time,"http_code":http_code,"redirect_count":redirect_count
         ,"size_upload":size_upload,"size_download":size_download,"size_header":size_header,"size_request":size_request
         ,"content_type":content_type,"reponse_code":reponse_code,"conn_time":conn_time,"transfer_time":transfer_time,"speed_download":speed_download
        ,"speed_upload":speed_upload,"startrans_time":startrans_time,"redirect_time":redirect_time,"http_conn_code":http_conn_code,"num_conn":num_conn,"last_socket":last_socket}
            data.append(url)
            data.append(perfdata)
            alldata.append(cnt)
            alldata.append(data)
            #pc.close()
            #b.close()
            jsondata=json.dumps({"perfdata":alldata},indent=4)
        pc.close()
        b.close()
        return jsondata
    
    def getos():#获取操作系统版本
        os = {}
        if sys.platform == "win32":
            try:
                reg_key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion")
                if reg_key:
                    ProductName = _winreg.QueryValueEx(reg_key, "ProductName")[0] or None
                    EditionId = _winreg.QueryValueEx(reg_key, "EditionId")[0] or None
                    ReleaseId = _winreg.QueryValueEx(reg_key, "ReleaseId")[0] or None
                    CurrentBuild = _winreg.QueryValueEx(reg_key, "CurrentBuild")[0] or None
                    BuildLabEx = _winreg.QueryValueEx(reg_key, "BuildLabEx")[0][:9] or None
                    os = {"ProductName": ProductName, "EditionId": EditionId, "ReleaseId": ReleaseId,
                          "CurrentBuild": CurrentBuild, "BuildLabEx": BuildLabEx}
                jsondata = json.dumps({"OS": os}, indent=4)
                return jsondata
            except Exception as e:
                print e.message.decode(DEFAULT_LOCALE_ENCODING)
    def getcmd(shell):#执行cmd
        ps = subprocess.Popen(shell, shell=True, stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
        out, err = ps.communicate()
        return  out.decode('cp936').encode('utf-8')
    def writelog(str):
        with open("result.txt",'a+') as fr:
            fr.write(str)
            fr.write("################################")
    if len(sys.argv) ==2 and sys.argv[1] == "full":
        cnt = 0
        print "test setp {0},Collect routing information....".format(cnt)
        cmd="route print "
        writelog(getcmd(cmd))#获取路由表
        print "test setp {0} ,Collect routing information....OK".format(cnt)
        cnt = cnt+1
        print "test setp {0},Collecting network information....".format(cnt)
        cmd="ipconfig /all  "#获取网卡配置
        writelog(getcmd(cmd))
        print "test setp {0},Collecting network information....OK".format(cnt)
        cnt = cnt+1
        print "test setp{0},Collecting TCP information....".format(cnt)
        cmd = "netsh  int  tcp  show  global"#获取TCP全局配置
        writelog(getcmd(cmd))
        print "test setp{0},Collecting TCP information....OK".format(cnt)
        cnt=+1
        print  "test setp{0},Collecting OS information....".format(cnt)
        writelog(getos())#获取操作系统版本
        print  "test setp{0},Collecting OS information....OK".format(cnt)
        for index,item in enumerate(iplist):
            cmd="tracert  "+item#获取路由跟踪
            print "test setp {0},Collecting route tracking information....".format(cnt)
            writelog(getcmd(cmd))
            print "test setp {0},Collecting route tracking information....OK".format(cnt)
            cnt=cnt+1
        for index,item in enumerate(urllist):
            print "test setp {0},Collecting web to access information data....".format(cnt)
            writelog(webperf_keep(item))
            print "test setp {0},Collecting web to access information data....OK".format(cnt)
            cnt=cnt+1
        print "All test data collection is completed!"
    if len(sys.argv) ==3:
        url = sys.argv[1]
        times = sys.argv[2]
        print "pre test access {0} {1} times.....".format(url,times)
        writelog(webperf_keep(url,times))
    if len(sys.argv)==1:
        print "Please run web.perf.test full to full test \nor run web.perf.test 'http://www.xxx.com/' 10 ro run 10 times access test"

    转载于:https://blog.51cto.com/skybug/2047690

    展开全文
  • 1 ECN简介 首先看看ECN握手报文的特点,根据RFC3168,ECN握手报文IP头部不能够设置ECT和CE位的 SYN报文TCP标志字段的CWR和ECE位被置1 ...服务器端在接收到有CE标志的报文后,立即构造带有ECE标志的...

    1 ECN简介

    首先看看ECN握手报文的特点,根据RFC3168,ECN握手报文IP头部不能够设置ECT和CE位的

    SYN报文TCP标志字段的CWR和ECE位被置1

     

    SYN-ACK报文的CWR位被置0,ECE位被置1

    报文在网络上传输的过程中,如果路由器判断自身发生拥塞则在报文的IP首部设置CE标志

    服务器端在接收到有CE标志的报文后,立即构造带有ECE标志的ACK报文,服务器端在接收到该ACK报文后进入TCP_CA_CWR状态,在该状态下发送窗口每两个ACK减1。

     发生拥塞之前的报文都被确认后,客户端会走出TCP_CA_CWR状态,转入TCP_CA_Open状态,重新开始拥塞避免,并向服务端发送CWR标志,终止服务端向客户端发送ECE报文。

     

    2 ECN在Linux上的实现

    以下所有分析基于Linux内核3.16.38

    Linux内核通过调整tcp_sock结构体的ecn_flags来标识ECN所处的状态,在文件include/net/tcp.h, line 393内,Linux定义了ECN可能的4种状态,本文将通过这4中状态的转化把ECN从协议栈中肢解出来。

    393 #define TCP_ECN_OK              1  //套接字支持ECN协议
    394 #define TCP_ECN_QUEUE_CWR       2  //发送端在接收到ECE报文后,设置该标志,并将拥塞状态机设置为TCP_CA_CWR状态
    395 #define TCP_ECN_DEMAND_CWR      4  //接收端处于该状态,将在所有ACK报文中添加ECE,直到接收到CWR报文
    396 #define TCP_ECN_SEEN            8  //是否接收到过ECT报文

    2.1 实现握手

    STEP1 :客户端发送SYN,用户态程序调用connect后,内核态通过tcp_connect构造SYN报文,tcp_connect会调用TCP_ECN_send_syn函数,该函数通过系统配置sysctl_tcp_ecn判断是否启用了ECN协议,如果启用了ECN协议,则在SYN报文中添加ECE和CWR标志,并临时设置该套接字为TCP_ECN_OK,这里说临时的原因为在ECN握手失败后,该标志还可能被取消。

    3046 /* Build a SYN and send it off. */
    3047 int tcp_connect(struct sock *sk)
    3048 {
            ...
    3070         TCP_ECN_send_syn(sk, buff);
    3071 
            ...
    3089 }

     

    328 /* Packet ECN state for a SYN.  */
    329 static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb)
    330 {
    331         struct tcp_sock *tp = tcp_sk(sk);
    332 
    333         tp->ecn_flags = 0;
    334         if (sock_net(sk)->ipv4.sysctl_tcp_ecn == 1) {              //通过 /proc/sys/net/ipv4/tcp_ecn进行配置
    335                 TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ECE | TCPHDR_CWR;    //SYN报文需要添加ECE和CWR
    336                 tp->ecn_flags = TCP_ECN_OK;                    //握手阶段ecn_flags设为支持ECN通信,如果握手失败TCP_ECN_OK会被取消
    337         }
    338 }

    STEP2 :服务端处理SYN, tcp_rcv_state_process函数是接收数据时TCP层上的必经之路,它会根据报文类型调用不同函数来处理,所有握手报文都会交给tcp_v4_conn_request,而tcp_v4_conn_request又会调用TCP_ECN_create_request进行ECN-SYN报文,当SYN报文符合ECN-SYN标准时,套接字添加支持ECN标识。

     
    
    
    5611 int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
    5612                       const struct tcphdr *th, unsigned int len) 
    5613 {
            ...
    5623 switch (sk->sk_state) { 5624 case TCP_CLOSE: 5625 goto discard; 5626 5627 case TCP_LISTEN: 5628 if (th->ack) 5629 return 1; 5630 5631 if (th->rst) 5632 goto discard; 5633 5634 if (th->syn) { 5635 if (th->fin) 5636 goto discard; 5637 if (icsk->icsk_af_ops->conn_request(sk, skb) < 0)    //调用tcp_v4_conn_request
    5638 return 1; 5639 5657 kfree_skb(skb); 5658 return 0; 5659 } 5660 goto discard; 5661
                ...
    5662         case TCP_SYN_SENT:
    5663                 queued = tcp_rcv_synsent_state_process(sk, skb, th, len);
    5672         }
    1257 int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
    1258 {
            ...
    1326         if (!want_cookie || tmp_opt.tstamp_ok)
    1327                 TCP_ECN_create_request(req, skb, sock_net(sk));
            ...1398 }
    737 static inline void
    738 TCP_ECN_create_request(struct request_sock *req, const struct sk_buff *skb,
    739                 struct net *net)
    740 {
    741         const struct tcphdr *th = tcp_hdr(skb);
    742 
    743         if (net->ipv4.sysctl_tcp_ecn && th->ece && th->cwr &&        //服务端也配置了ECN,同时SYN报文中函授ECE和CWR
    744             INET_ECN_is_not_ect(TCP_SKB_CB(skb)->ip_dsfield))
    745                 inet_rsk(req)->ecn_ok = 1;                   //套接字设置支持ECN标识 
    746 }

     STEP3 :客户端处理SYN-ACK报文,首先调用tcp_rcv_synsent_state_process,继而调用TCP_ECN_rcv_synack来完成ECN握手。

    5611 int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
    5612                       const struct tcphdr *th, unsigned int len) 
    5613 {
    
            ...
    5662         case TCP_SYN_SENT:
    5663                 queued = tcp_rcv_synsent_state_process(sk, skb, th, len);
    5672         }
            ...
    5672 } 
    5384 static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
    5385                                          const struct tcphdr *th, unsigned int len)
    5386 {
                ...
    5446                 TCP_ECN_rcv_synack(tp, th);
                ...5602 }
    246 static inline void TCP_ECN_rcv_synack(struct tcp_sock *tp, const struct tcphdr *th)
    247 {
    248         if ((tp->ecn_flags & TCP_ECN_OK) && (!th->ece || th->cwr))          //SYN-ACK报文含有CWR或不含ECE则握手失败,客户端撤销TCP_ECN_OK
    249                 tp->ecn_flags &= ~TCP_ECN_OK;
    250 }

    2.2 客户端发送带有ECT的报文

    所有支持ECN通信的流,在传输层 tcp_transmit_skb -> TCP_ECN_send -> INET_ECN_xmit的流程中都会打上ECT(0)标记。

    350 static inline void TCP_ECN_send(struct sock *sk, struct sk_buff *skb,
    351                                 int tcp_header_len)
    352 {
    353         struct tcp_sock *tp = tcp_sk(sk);
    354 
    355         if (tp->ecn_flags & TCP_ECN_OK) {      //ECN通信添加ECT
    356                 /* Not-retransmitted data segment: set ECT and inject CWR. */
    357                 if (skb->len != tcp_header_len &&
    358                     !before(TCP_SKB_CB(skb)->seq, tp->snd_nxt)) {
    359                         INET_ECN_xmit(sk);
    360                         if (tp->ecn_flags & TCP_ECN_QUEUE_CWR) {
    361                                 tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR;
    362                                 tcp_hdr(skb)->cwr = 1;
    363                                 skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
    364                         }
    365                 } else {
    366                         /* ACK or retransmitted segment: clear ECT|CE */
    367                         INET_ECN_dontxmit(sk);
    368                 }
    369                 if (tp->ecn_flags & TCP_ECN_DEMAND_CWR)
    370                         tcp_hdr(skb)->ece = 1;
    371         }
    372 }
     51 static inline void INET_ECN_xmit(struct sock *sk)
     52 {
     53         inet_sk(sk)->tos |= INET_ECN_ECT_0;
     54         if (inet6_sk(sk) != NULL)
     55                 inet6_sk(sk)->tclass |= INET_ECN_ECT_0;
     56 }

    2.3 路由器处理ECT报文

    根据设计思路,路由器在认为发生拥塞时,给所有支持ECN协议的流打上CE标记,然而路由器如何判断拥塞发生并没有一个统一的标准,一般来说为平滑后的队列长度超过一定阈值,以RED队列为例,它维护一个队列长度的移动平均值,在该值大于设置的阈值,之后以一定概率给过往的报文打上CE标记(没有启用ECN时为以一定概率丢弃报文)。

     59 static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch)
     60 {
            ...
     72         switch (red_action(&q->parms, &q->vars, q->vars.qavg)) {    //根据平均队列长度决定如何处理报文
     73         case RED_DONT_MARK:
     74                 break;
     75 
     76         case RED_PROB_MARK:                          //标记报文
     77                 sch->qstats.overlimits++;
     78                 if (!red_use_ecn(q) || !INET_ECN_set_ce(skb)) {     //没有启用ECN,或者打CE标记失败则丢弃报文
     79                         q->stats.prob_drop++;
     80                         goto congestion_drop;            
     81                 }
     82 
     83                 q->stats.prob_mark++;
     84                 break;
     85 
     86         case RED_HARD_MARK:
     87                 sch->qstats.overlimits++;
     88                 if (red_use_harddrop(q) || !red_use_ecn(q) ||
     89                     !INET_ECN_set_ce(skb)) {
     90                         q->stats.forced_drop++;
     91                         goto congestion_drop;
     92                 }
     93 
     94                 q->stats.forced_mark++;
     95                 break;
     96         }
            ...

    110 }

    2.4 服务器端处理CE报文

    服务器端在收到带有CE标志的IP报文后,将套接字结构体tp->ecn_flags置TCP_ECN_DEMAND_CWR,并进入quick ack模式,之后所有ack报文都置有ECE标志,直到接收端接收到CWR报文后,取消TCP_ECN_DEMAND_CWR。

    STEP1 : 转入TCP_ECN_DEMAND_CWR状态。具体流程为tcp_rcv_established -> tcp_event_data_recv -> TCP_ECN_check_ce,在TCP_ECN_check_ce中检查报文是否包含CE标记,在遇到CE标记时转入TCP_ECN_DEMAND_CWR状态。

    220 static inline void TCP_ECN_check_ce(struct tcp_sock *tp, const struct sk_buff *skb)
    221 {
    222         if (!(tp->ecn_flags & TCP_ECN_OK))
    223                 return;
    224 
    225         switch (TCP_SKB_CB(skb)->ip_dsfield & INET_ECN_MASK) {
    226         case INET_ECN_NOT_ECT:
    227                 /* Funny extension: if ECT is not set on a segment,
    228                  * and we already seen ECT on a previous segment,
    229                  * it is probably a retransmit.
    230                  */
    231                 if (tp->ecn_flags & TCP_ECN_SEEN)
    232                         tcp_enter_quickack_mode((struct sock *)tp);
    233                 break;
    234         case INET_ECN_CE:
    235                 if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) {
    236                         /* Better not delay acks, sender can have a very low cwnd */
    237                         tcp_enter_quickack_mode((struct sock *)tp);    //进入quick ack模式,立即构造ack报文
    238                         tp->ecn_flags |= TCP_ECN_DEMAND_CWR;        //在ecn_flags中添加TCP_ECN_DEMAND_CWR状态
    239                 }
    240                 /* fallinto */
    241         default:
    242                 tp->ecn_flags |= TCP_ECN_SEEN;
    243         }
    244 }

    STEP2 :构造ECE - ACK。在构造ACK报文时,tcp_transmit_skb 调用 TCP_ECN_send判断是否处于TCP_ECN_DEMAND_CWR状态,并决定是否在ACK报文中添加ECE标志。

    350 static inline void TCP_ECN_send(struct sock *sk, struct sk_buff *skb,
    351                                 int tcp_header_len)
    352 {
    353         struct tcp_sock *tp = tcp_sk(sk);
    354 
    355         if (tp->ecn_flags & TCP_ECN_OK) {
    356                 /* Not-retransmitted data segment: set ECT and inject CWR. */
    357                 if (skb->len != tcp_header_len &&
    358                     !before(TCP_SKB_CB(skb)->seq, tp->snd_nxt)) {
    359                         INET_ECN_xmit(sk);
    360                         if (tp->ecn_flags & TCP_ECN_QUEUE_CWR) {
    361                                 tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR;
    362                                 tcp_hdr(skb)->cwr = 1;
    363                                 skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
    364                         }
    365                 } else {
    366                         /* ACK or retransmitted segment: clear ECT|CE */
    367                         INET_ECN_dontxmit(sk);
    368                 }
    369                 if (tp->ecn_flags & TCP_ECN_DEMAND_CWR)       //在CWR状态时,给ACK报文添加ece标志 
    370                         tcp_hdr(skb)->ece = 1;
    371         }
    372 }

    STEP3 :退出TCP_ECN_DEMAND_CWR状态。具体流程为tcp_rcv_established -> tcp_data_queue -> TCP_ECN_accept_cwr,在TCP_ECN_accept_cwr中,判断接收到的报文中是否有CWR标志,并决定是否退出TCP_ECN_DEMAND_CWR状态。

    209 static inline void TCP_ECN_accept_cwr(struct tcp_sock *tp, const struct sk_buff *skb)
    210 {
    211         if (tcp_hdr(skb)->cwr)  //退出TCP_ECN_DEMAND_CWR状态
    212                 tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR;
    213 }

    2.5 客户端处理ECE报文

    客户端首先要根据ACK报文中的ECE调整TCP拥塞状态机到TCP_CA_CWR状态,并开始减小发送窗口,在拥塞发生之前的所有报文都被确认后,恢复TCP_CA_Open状态,并向服务器端发送CWR终止服务器端的TCP_ECN_DEMAND_CWR,结束整个流程。

    STEP1 :处理ACK报文,并确定是否包含ECE标志,流程为tcp_rcv_established -> tcp_ack 。

     

    3360 static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
    3361 {
            ...
    3407         if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) {
              ...
    3419 } else { 3420 if (ack_seq != TCP_SKB_CB(skb)->end_seq) 3421 flag |= FLAG_DATA; 3422 else 3423 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPPUREACKS); 3424 3425 flag |= tcp_ack_update_window(sk, skb, ack, ack_seq); 3426 3427 if (TCP_SKB_CB(skb)->sacked) 3428 flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una, 3429 &sack_rtt_us); 3430 3431 if (TCP_ECN_rcv_ecn_echo(tp, tcp_hdr(skb)))  //确定ACK报文是否含有ECE标志 3432 flag |= FLAG_ECE;         3433 3434 tcp_ca_event(sk, CA_EVENT_SLOW_ACK); 3435 }
            ...
    3508 }

     STEP2 : 调整拥塞控制状态机。具体流程为tcp_rcv_established -> tcp_ack -> tcp_fastretrans_alert -> tcp_try_to_open,其中tcp_fastretrans_alert 函数为整个TCP拥塞控制状态机的核心,而tcp_try_to_open函数则根据flag中是否包含FLAG_ECE标志,确定是否将拥塞状态机调整为TCP_CA_CWR状态。拥塞控制状态机进入TCP_CA_CWR状态后,协议栈需要调用tcp_enter_cwr函数来保存当前snd_nxt等重要的变量,之后发送窗口大致为每两个ack减1。

    2557 static void tcp_try_to_open(struct sock *sk, int flag, const int prior_unsacked)
    2558 {
    2559         struct tcp_sock *tp = tcp_sk(sk);
    2560 
    2561         tcp_verify_left_out(tp);
    2562 
    2563         if (!tcp_any_retrans_done(sk))
    2564                 tp->retrans_stamp = 0;
    2565 
    2566         if (flag & FLAG_ECE)        //将拥塞控制状态机从OPEN或REORDER状态调整为CWR状态
    2567                 tcp_enter_cwr(sk, 1);
    2568 
    2569         if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) {
    2570                 tcp_try_keep_open(sk);
    2571         } else {
    2572                 tcp_cwnd_reduction(sk, prior_unsacked, 0);
    2573         }
    2574 }

    STEP3 : 退出CWR状态。上面介绍过Linux的拥塞控制状态机主要由tcp_fastretrans_alert 控制,在STEP2中记录的snd_nxt之前的报文都被确认后,拥塞状态机也将退出TCP_CA_CWR状态,并转入TCP_CA_Open状态。

    2774 static void tcp_fastretrans_alert(struct sock *sk, const int acked,
    2775                                   const int prior_unsacked,
    2776                                   bool is_dupack, int flag)
    2777 {
            ...
    2801         /* D. Check state exit conditions. State can be terminated
    2802          *    when high_seq is ACKed. */
    2803         if (icsk->icsk_ca_state == TCP_CA_Open) {
    2804                 WARN_ON(tp->retrans_out != 0);
    2805                 tp->retrans_stamp = 0;
    2806         } else if (!before(tp->snd_una, tp->high_seq)) {
    2807                 switch (icsk->icsk_ca_state) {
    2808                 case TCP_CA_CWR:
    2809                         /* CWR is to be held something *above* high_seq
    2810                          * is ACKed for CWR bit to reach receiver. */
    2811                         if (tp->snd_una != tp->high_seq) {      //退出TCP_CA_Cwr
    2812                                 tcp_end_cwnd_reduction(sk);
    2813                                 tcp_set_ca_state(sk, TCP_CA_Open);
    2814                         }
    2815                         break;
    2816 
                    ...
    2824 } 2825 }
            ...
    2886 }

    转载于:https://www.cnblogs.com/codingMozart/p/6389165.html

    展开全文
  • H85-SVP-06-03AX_ECN_M076.zip

    2020-11-09 10:19:29
    windows平台下可视化服务器管理软件,通过简单配置以后即可对服务器进行监控以及管理。此链接为第四部分。
  • H85-SVP-06-03AX_ECN_M076.z01

    2020-11-07 11:54:16
    windows平台下可视化服务器管理软件,通过简单配置以后即可对服务器进行监控以及管理。此链接为第一部分。
  • H85-SVP-06-03AX_ECN_M076.z03

    2020-11-07 19:09:58
    windows平台下可视化服务器管理软件,通过简单配置以后即可对服务器进行监控以及管理。此链接为第三部分。
  • H85-SVP-06-03AX_ECN_M076.z02

    2020-11-07 12:57:45
    windows平台下可视化服务器管理软件,通过简单配置以后即可对服务器进行监控以及管理。此链接为第二部分。
  • 抓包分析如下:  对比本地,多了两次TCP[SYN,ECN,CWR]请求 查看 服务器ECN 关闭ECN功能 在请求 工行 directbank.icbc.com.cn:

    抓包分析如下:

     对比本地,多了两次TCP[SYN,ECN,CWR]请求

    查看 服务器ECN

    关闭ECN功能

    在请求 工行 directbank.icbc.com.cn:

    展开全文
  • 假设iperf服务端为主机tian04,使用TCP协议,那么在控制台执行以下两个命令开启服务器进程。 iperf-s -p 12000 -i1 iperf-s -p 12001 -i1 假设iperf客户端为主机tian05,tian06。注意,与1G的实验环境使用的命令不同...

    1.  准备知识


    1.1  Iperf命令

    假设iperf服务端为主机tian04,使用TCP协议,那么在控制台执行以下两个命令开启服务器进程。

    iperf-s -p 12000 -i1

    iperf-s -p 12001 -i1

    假设iperf客户端为主机tian05,tian06。注意,与1G的实验环境使用的命令不同,当关闭网卡TSOGSO时,R320服务器无法使用一个进程达到满带宽(约为9.42 Gbps),命令和结果如下:

    iperf -c 192.168.9.4 -p 12000 -i1 -t 15


    为了利用全部带宽,至少需要在客户端开启两个进程。命令和结果如下:

    iperf-c 192.168.9.4 -p 12002 -i1 -t 15 -P 2


    在拥塞实验中,tian05和tian06同时对tian04发包,客户端只能分享到接近5Gbps的带宽,因此上述两种客户端命令对实验结果并无影响。

    1.1  开启Linux内核ECN特性

    三台主机均需执行:

    sudosysctl -w net.ipv4.tcp_ecn=1

    当Linux内核开启ECN特性之后,iperf会在TCP握手时自动协商,使得该TCP连接启用ECN。


    2.  配置交换机

    以下大多数知识在华为文档QoS配置指南的第3章和第5章。

    2.1  本交换机的独特特性

    与之前用过的交换机不一样(暂未写完)

    2.2  配置WRED丢弃模板

    system-view

    drop-profile drop-profile-name

    color { green | non-tcp | red | yellow } low-limitlow-limit-percentage high-limit high-limit-percentage discard-percentagediscard-percentage

                      low-limit-percentage:当队列中的报文长度占队列长度达到此百分比时,开始进行WRED丢弃。

                      discard-percentage:指定WRED的最大丢弃概率。

    commit

    2.3  应用WRED丢弃模板

    配置WRED丢弃模板后,需要在接口或端口队列上应用,WRED丢弃模板才会生效。以下描述在端口队列上应用WRED丢弃模板

    system-view

    interface interface-type interface-number 进入接口视图

    qos queue queue-index wred drop-profile-name 将WRED丢弃模板应用于端口队列

    commit

    2.4  应用ECN

    队列仅当应用WRED丢弃模板后才可以使能(enable)该队列的显式拥塞通知功能。

    system-view

    interface interface-type interface-number 进入接口视图

    qos queue queue-index ecn 指定队列显式拥塞通知功能

    commit

    2.5  检查配置结果

    display drop-profile [ brief | drop-profile-name ]查看WRED丢弃模板的配置结果。

    display qos configuration interface [ interface-typeinterface-number ] 查看接口上所有的QoS配置信息。

    2.6  命令综合运用

    #创建wred模板

    system-view

    drop-profile drop-profile-tyz

    DCTCP ECN 配置方法:

    color green low-limit 2 high-limit 2discard-percentage 100

    commit

    quit

     

    #以下开始配置各个端口的ECN(配了客户端没用,客户端不会拥塞)

    int 10ge1/0/4

    qos queue 0 wred drop-profile-tyz  #查看3.5服务等级与端口队列索引关系,可知发往队列0

    qos queue 0 ecn

    commit

    quit

     

    int 10ge1/0/5

    qos queue 0 wred drop-profile-tyz

    qos queue 0 ecn

    commit

    quit

     

    int 10ge1/0/6

    qos queue 0 wred drop-profile-tyz

    qos queue 0 ecn

    commit

    quit

     

    #查看配置结果

    display drop-profile drop-profile-tyz

    display qos configuration int 10ge1/0/4

    display qos configuration int 10ge1/0/5

    display qos configuration int 10ge1/0/6


    3.  实验

    首先,服务端tian04按照1.1节内容开启服务器进程。另外,服务端需要让10G网卡进入混杂模式并抓包。使用tcpdump完成这个工作。

    sudotcpdump -i p1p1 -s 80 -w tian01.pcap

    其中,-s80参数表示只抓取每个数据包的前80个字节,这已经抓取了完整的数据包头。注意到Ethernet、IP、TCP包头长度分别为14、20、20字节,而TCP经常启用了选项(option)字段,因此设为80字节是合理的。

    不抓取完整数据包的原因:在1G实验环境中,如果抓取完整数据包,内核就会偶尔出现负载过大丢弃数据包的情况,极大影响了实验效果。

    两个客户端tian05、tian06同时分别执行

    iperf-c 192.168.9.4 -p 12000 -i1 -t 15

    iperf-c 192.168.9.4 -p 12001 -i1 -t 15

    15秒后运行完毕,终止tian04的tcpdump,并把pcap文件送往有图形界面的R730服务器中作分析。

    scptian01.pcap commonuser@192.168.1.51:/home/commonuser/tyz/tian01.pcap

    在wireshark中寻找IP包头CE 两个bit为11 = 0x3的数据包,过滤器设置ip.dsfield == 0x3。示例如下:



    展开全文
  • 转一个windows下使用syslog的文章,没有时间测试了。 1 winodws服务器的配置 ...下载地址为:https://engineering.purdue.edu/ECN/Resources/Documents/UNIX/evtsys/ https://code.google.com/p/eventlog-to
  • Windows server 2012服务器的网站...在网上查找原因,发现原来Windows server 2012默认打开了ECN功能(从Windows server 2008之后都默认打开),个人操作系统却没有打开,而当网络拥塞不小的时候,就会造成这种效果。
  • 开始 运行 cmd 输入 netsh interface tcp set global autotuninglevel=disabled netsh int tcp set global ecn=disable 关闭后访问网页的速度正常
  • 场景为:上层服务器防火墙为金盾防火墙,系统为新安装的的2012安装板server 2012系统数据里有时候会带有ECN标志位,这个标志位防火墙不识别会拦截,系统cmd下用命令关闭ecn标识:netsh int tcp set global ...
  • server2008之后的系统默认开启了ecn的功能,导致内网客户端连接外网的服务器建立连接的过程要10几秒,无法忍受。 cmd控制台输入netsh命令即可禁用该功能:netsh interface tcp set global ecn=disabled 不可能让...
  • Windows Server 2016 服务器 telnet远程设备,需要等9秒多才能连上,ping 正常,网上找各种原因,尝试了反向域名解析的方法,还是无效。 后来通过抓包发现: 第一次,发送等待3秒,失败;第二次发送等待6秒,失败,...
  • 实施服务器端 添加对ECN的支持 添加对HTTP / 3的支持 安装 要在项目中成功包含ex_quic ,您需要安装: cmake zlib 该软件包可以通过添加安装ex_quic你在依赖列表mix.exs : def deps do [ { :ex_quic , " ~> ...
  • dos 实用命令收集

    2015-04-29 11:38:00
    解决win2012服务器上网慢:netsh int tcp set global ecn=disable 导出指定类型的文件列表:dir /b /s d:\Data\*.mdb>d:\1.txt /B 获取CPU ID命令: wmic cpu get ProcessorId ...
  • 由于所在实验室的server实在是太多了…而且一般中间还有两个jumpserver…这个人又实在是太懒了,就瞎扣jio写了个差不多能用的expect脚本来方便登录各个服务器 #!/usr/bin/expect set timeout -1 send_user "...
  • Django Hello World app

    2012-11-21 00:49:16
    写hello world程序,可以参考:http://djangobook.py3k.cn/chapter02/ecn/ 第一章和第二章。里面讲到了安装和建立demo project. 注意,按照例子做的话,这个...开发服务器 Django includes a built-in, lightweigh
  • 文件可以上传的服务器,问题是上传完毕程序在睡眠期间本地文件删不掉,提示错误是java虚拟机在占用本地文件资源,求大神看看怎么在程序休眠期间可以删除本地文件,帐号只有10金币了,求大神看看

空空如也

空空如也

1 2
收藏数 24
精华内容 9
关键字:

服务器ecn