码迷,mamicode.com
首页 > 其他好文 > 详细

Jump The Great Firewall【step16 优化丢包率】

时间:2015-06-13 21:42:23      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:

一、为何会丢包

经过博主长期使用的经验所得,使用UDP协议在互联网上传输数据时,存在一定的丢包率。尤其是在晚间繁忙时段,丢包率更为明显,那么我们如何进行优化来降低丢包率呢?

二、如何解决

  1. 服务器端与客户端同时进行校验,在一定时间内如果发现有丢包时,发送一条新的消息通知对方重新发送该条消息
  2. 服务器端与客户端在发送消息时,每次都将一条消息发送多次

我们先来看下第一种方案:这种方案属于最传统的方式,不过该方法有一个缺点。当网络状况非常差时,发出去的请求重发消息也可能会丢失,因此对端可能会再次请求丢失的那个请求重发的报文。与TCP类似,这将导致整个网络变的更差。

让我们来看下第二种方案:对于每一条消息,两端都进行了多次的发送,理论上整体带宽将被降低。在网络状况不好的情况下,假设一条消息我们发送5次,实际上并不会这么巧合的这5次都被丢包了。因此我更倾向于这个方案,在实际测试过程中我们发现带宽并没有降低,反而下载文件的速度比以前更稳定了。

三、如何实现

    1. 首先修改最底层的发包函数write_c
      ssize_t write_c(client_t* client, const void* buf, size_t count) {
          unsigned char i;
          unsigned char successed = 0;
          for (i = 0; i < qtun->multi_send; ++i) {
              if (qtun->use_udp) {
                  if (sendto(qtun->remotefd, buf, (int)count, 0, (struct sockaddr*)&client->addr, sizeof(client->addr)) >= 0)
                      ++successed;
              } else {
                  const char* ptr = buf;
                  size_t left = count;
                  while (left) {
                      ssize_t written = write(client->fd, ptr, (unsigned int)left);
                      if (written == 0)
                          return 0;
                      else if (written == -1) {
                          if (errno == EAGAIN || errno == EWOULDBLOCK) continue;
                          return -1;
                      }
                      ptr  += written;
                      left -= written;
                  }
                  ++successed;
              }
          }
          return count;
      }
      这里我们根据配置文件中的multi_send参数来决定要发送多少次,在TCP模式中multi_send参数总是为1
    2. 我们定义一个msg_state_t结构来保存每一个收到的消息
      typedef struct {
          unsigned int   ident;
          unsigned short idx;
          unsigned char  used;
      } msg_state_t;
      
    3. 在client_t结构中我们总是记录MSG_MAX_TTL条收到的消息id
          msg_state_t        recv_msgs[MSG_MAX_TTL];
      
    4. 在收到一条消息时,我们需要优先检查对应client_t结构中的recv_msg表内是否已记录了该消息的序号,如果该表中已包含了该消息的序号,则需要将该消息丢掉

四、增强安全性

为了增强安全性,在新版本中qtun默认禁止局域网内与其他主机通信,通过在配置文件中指定use_local_forward标志来开机局域网内的通信。具体的实现方法为:在server_process函数中检查数据包的源地址与目的地址是否都为当前局域网内的,如果都是当前局域网内的数据包,则直接进行丢包

            if (!qtun->use_local_forward &&
                check_ip_by_mask(ipHdr->saddr, qtun->localip, qtun->netmask) &&
                check_ip_by_mask(ipHdr->daddr, qtun->localip, qtun->netmask)) {
                return;
            }

五、完整代码

完整代码可到step16中查看

版本号:1.1.0

日期:2015-06-13

Jump The Great Firewall【step16 优化丢包率】

标签:

原文地址:http://www.cnblogs.com/lwch/p/4574105.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!