webrtc源码学习 - Network

network 支持功能

1、本地网络
2、适配器
3、dns
4、网络的开销

获取本机的网络

1、调用 GetAdaptersAddresses函数检索与本地计算机上的适配器关联的地址。
2、遍历适配器信息
- 2.1 判断操作状态,如果是启动才进行处理
-

bool BasicNetworkManager::CreateNetworks(bool include_ignored,
                                         NetworkList* networks) const {
  NetworkMap current_networks;
  // MSDN recommends a 15KB buffer for the first try at GetAdaptersAddresses.
  size_t buffer_size = 16384;
  std::unique_ptr<char[]> adapter_info(new char[buffer_size]);
  PIP_ADAPTER_ADDRESSES adapter_addrs =
      reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get());

  // 1. 获取适配器的信息,存放到adapter_info中,如果存储不下,重新分配内存适应
  int adapter_flags = (GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_ANYCAST |
                       GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_INCLUDE_PREFIX);
  int ret = 0;
  do {
    adapter_info.reset(new char[buffer_size]);
	//adapter_addrs 指向缓冲区的指针,该缓冲区包含成功返回时IP_ADAPTER_ADDRESSES结构的链表。
    adapter_addrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get());
    ret = GetAdaptersAddresses(AF_UNSPEC, adapter_flags, 0, adapter_addrs,
                               reinterpret_cast<PULONG>(&buffer_size));
  } while (ret == ERROR_BUFFER_OVERFLOW);
  if (ret != ERROR_SUCCESS) {
    return false;
  }

  // 2. 遍历适配器信息,
  int count = 0;
  while (adapter_addrs) {
	// 2.1 判断操作状态,如果是启动才进行处理
    if (adapter_addrs->OperStatus == IfOperStatusUp) {
	  // 2.1.1 第一个单播地址指针
      PIP_ADAPTER_UNICAST_ADDRESS address = adapter_addrs->FirstUnicastAddress;
      PIP_ADAPTER_PREFIX prefixlist = adapter_addrs->FirstPrefix;
	  // 2.1.2 获取适配器名称和描述
      std::string name;
      std::string description;
#if !defined(NDEBUG)
      name = ToUtf8(adapter_addrs->FriendlyName,
                    wcslen(adapter_addrs->FriendlyName));
#endif
      description = ToUtf8(adapter_addrs->Description,
                           wcslen(adapter_addrs->Description));

	  // 2.1.3 遍历所有的地址
      for (; address; address = address->Next) {
#if defined(NDEBUG)
        name = rtc::ToString(count);
#endif

		// 2.1.3.1 判断IPv4 和 v6 
        IPAddress ip;
        int scope_id = 0;
        std::unique_ptr<Network> network;
        switch (address->Address.lpSockaddr->sa_family) {
          case AF_INET: {
            sockaddr_in* v4_addr =
                reinterpret_cast<sockaddr_in*>(address->Address.lpSockaddr);
            ip = IPAddress(v4_addr->sin_addr);
            break;
          }
          case AF_INET6: {
            sockaddr_in6* v6_addr =
                reinterpret_cast<sockaddr_in6*>(address->Address.lpSockaddr);
            scope_id = v6_addr->sin6_scope_id;
            ip = IPAddress(v6_addr->sin6_addr);

            if (IsIgnoredIPv6(InterfaceAddress(ip))) {
              continue;
            }

            break;
          }
          default: {
            continue;
          }
        }

		// 2.1.3.2 判断网络是否存在,设置接口类型
        IPAddress prefix;
        int prefix_length = GetPrefix(prefixlist, ip, &prefix);
        std::string key = MakeNetworkKey(name, prefix, prefix_length);
        auto existing_network = current_networks.find(key);
        if (existing_network == current_networks.end()) {
          AdapterType adapter_type = ADAPTER_TYPE_UNKNOWN;
          switch (adapter_addrs->IfType) {
            case IF_TYPE_SOFTWARE_LOOPBACK:
              adapter_type = ADAPTER_TYPE_LOOPBACK;
              break;
            case IF_TYPE_ETHERNET_CSMACD:
            case IF_TYPE_ETHERNET_3MBIT:
            case IF_TYPE_IEEE80212:
            case IF_TYPE_FASTETHER:
            case IF_TYPE_FASTETHER_FX:
            case IF_TYPE_GIGABITETHERNET:
              adapter_type = ADAPTER_TYPE_ETHERNET;
              break;
            case IF_TYPE_IEEE80211:
              adapter_type = ADAPTER_TYPE_WIFI;
              break;
            case IF_TYPE_WWANPP:
            case IF_TYPE_WWANPP2:
              adapter_type = ADAPTER_TYPE_CELLULAR;
              break;
            default:
              // TODO(phoglund): Need to recognize other types as well.
              adapter_type = ADAPTER_TYPE_UNKNOWN;
              break;
          }

		  // 2.1.3.3 保存网络信息
          std::unique_ptr<Network> network(new Network(
              name, description, prefix, prefix_length, adapter_type));
          network->set_default_local_address_provider(this);
          network->set_mdns_responder_provider(this);
          network->set_scope_id(scope_id);
          network->AddIP(ip);
          bool ignored = IsIgnoredNetwork(*network);
          network->set_ignored(ignored);
          if (include_ignored || !network->ignored()) {
            current_networks[key] = network.get();
            networks->push_back(network.release());
          }
        } else {
          (*existing_network).second->AddIP(ip);
        }
      }
      // Count is per-adapter - all 'Networks' created from the same
      // adapter need to have the same name.
      ++count;
    }
    adapter_addrs = adapter_addrs->Next;
  }
  return true;
}

获取本机地址和端口

1、由于有多个接口,所以先建立链接,然后在获取本机的地址,是通过getsockname获取的。

SocketAddress Win32Socket::GetLocalAddress() const {
  sockaddr_storage addr = {0};
  socklen_t addrlen = sizeof(addr);
  int result =
      ::getsockname(socket_, reinterpret_cast<sockaddr*>(&addr), &addrlen);
  SocketAddress address;
  if (result >= 0) {
    SocketAddressFromSockAddrStorage(addr, &address);
  } else {
    RTC_LOG(LS_WARNING) << "GetLocalAddress: unable to get local addr, socket="
                        << socket_;
  }
  return address;
}

dns 获取

DnsLookup* dns = new DnsLookup;
  if (!sink_) {
    // Explicitly create the sink ourselves here; we can't rely on SetAsync
    // because we don't have a socket_ yet.
    CreateSink();
  }
  // TODO: Replace with IPv6 compatible lookup.
   // 异步调用, 通过msg 的方式返回,sink_->handle() 是窗口的句柄,专门用来接收socket 的异步消息
  dns->handle = WSAAsyncGetHostByName(sink_->handle(), WM_DNSNOTIFY,
                                      addr.hostname().c_str(), dns->buffer,
                                      sizeof(dns->buffer));

  if (!dns->handle) {
    RTC_LOG_F(LS_ERROR) << "WSAAsyncGetHostByName error: " << WSAGetLastError();
    delete dns;
    UpdateLastError();
    Close();
    return SOCKET_ERROR;
  }

socket 的信号是通过,消息循环机制接收,接收WM_DNSNOTIFY消息,说明已经返回了dns 结果

bool Win32Socket::EventSink::OnMessage(UINT uMsg,
                                       WPARAM wParam,
                                       LPARAM lParam,
                                       LRESULT& result) {
  switch (uMsg) {
    case WM_SOCKETNOTIFY:
    case WM_TIMER:
      return OnSocketNotify(uMsg, wParam, lParam, result);
    case WM_DNSNOTIFY:
      return OnDnsNotify(wParam, lParam, result);
  }
  return false;

处理dns 返回的结果,调用DoConnect 进行链接

void Win32Socket::OnDnsNotify(HANDLE task, int error) {
  if (!dns_ || dns_->handle != task)
    return;

  uint32_t ip = 0;
  if (error == 0) {
    hostent* pHost = reinterpret_cast<hostent*>(dns_->buffer);
    uint32_t net_ip = *reinterpret_cast<uint32_t*>(pHost->h_addr_list[0]);
    ip = NetworkToHost32(net_ip);
  }

  RTC_LOG_F(LS_INFO) << "(" << IPAddress(ip).ToSensitiveString() << ", "
                     << error << ")";

  if (error == 0) {
    SocketAddress address(ip, dns_->port);
    error = DoConnect(address);
  } else {
    Close();
  }

  if (error) {
    error_ = error;
    SignalCloseEvent(this, error_);
  } else {
    delete dns_;
    dns_ = nullptr;
  }
}

网络的开销

根据类型设置的开销,如下

static const uint16_t kNetworkCostMax = 999;
static const uint16_t kNetworkCostHigh = 900;
static const uint16_t kNetworkCostUnknown = 50;
static const uint16_t kNetworkCostLow = 10;
static const uint16_t kNetworkCostMin = 0;

uint16_t ComputeNetworkCostByType(int type) {
  switch (type) {
    case rtc::ADAPTER_TYPE_ETHERNET:
    case rtc::ADAPTER_TYPE_LOOPBACK:
      return kNetworkCostMin;
    case rtc::ADAPTER_TYPE_WIFI:
      return kNetworkCostLow;
    case rtc::ADAPTER_TYPE_CELLULAR:
      return kNetworkCostHigh;
    case rtc::ADAPTER_TYPE_ANY:
      // Candidates gathered from the any-address/wildcard ports, as backups,
      // are given the maximum cost so that if there are other candidates with
      // known interface types, we would not select candidate pairs using these
      // backup candidates if other selection criteria with higher precedence
      // (network conditions over the route) are the same. Note that setting the
      // cost to kNetworkCostUnknown would be problematic since
      // ADAPTER_TYPE_CELLULAR would then have a higher cost. See
      // P2PTransportChannel::SortConnectionsAndUpdateState for how we rank and
      // select candidate pairs, where the network cost is among the criteria.
      return kNetworkCostMax;
    case rtc::ADAPTER_TYPE_VPN:
      // The cost of a VPN should be computed using its underlying network type.
      RTC_NOTREACHED();
      return kNetworkCostUnknown;
    default:
      return kNetworkCostUnknown;
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
通过更改Chrome的隐私设置来配置WebRTC的网络流量。 在Chrome的隐私设置中配置WebRTC流量路由选项。 ★它做什么: 这配置WebRTC不使用某些IP地址或协议: - 公共互联网不可见的私人IP地址(例如地址192.168.1.2) - 与不用于网络流量的网络接口相关联的任何公共IP地址(例如,当通过VPN浏览时,ISP提供的地址) - 要求WebRTC流量通过Chrome中配置的代理服务器。由于大多数代理服务器不处理UDP,所以这会有效地关闭UDP,直到Chrome中提供UDP代理支持,并且这些代理被广泛部署。   当扩展程序安装在M48之前的Chrome版本上时,WebRTC将仅使用与用于Web通信的接口关联的公共IP地址,通常是已经提供给浏览器HTTP请求中的站点的相同地址。对于Chrome版本M48以及之后的版本,此扩展提供了一个允许WebRTC使用默认公共地址的配置,对于NAT后面的机器,则使用与公共地址关联的默认私有地址。在Chrome M48的全新安装扩展之后,所述行为将是默认的。对于升级方案,以前选择的配置不应该改变。 该扩展也可能会禁用非代理UDP,但默认情况下不会启用,并且必须使用扩展的“选项”页面进行配置。 ★注意事项: 此扩展可能会影响使用WebRTC进行音频/视频或实时数据通信的应用程序的性能。因为它限制了潜在的网络路径和协议,所以WebRTC可能选择导致明显更长的延迟或更低质量(例如,通过VPN)的路径,或者仅通过代理服务器使用TCP,这对于实时通信不是理想的。我们正试图确定这是多么普遍。 安装此项目即表示您同意Google服务条款和隐私权政策,网址为https://www.google.com/intl/zh-CN/policies/。 支持语言:English

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值