作音視頻開發,咱們常常須要模擬弱網環境,觀察 app 在弱網下的表現,好比,丟包、延遲、抖動、限制帶寬條件等,Mac 系統有一個弱網工具 APP,叫作 「Network Link Conditioner 」 ,支持可視化地完成弱網的模擬和配置,很好用,很是推薦你使用這個工具來完成弱網的模擬。html
可是若是你指望使用命令行或者使用腳原本實現弱網環境的配置,就不得不研究一下它背後的原理了,本文就是介紹 Network Link Conditioner 背後使用的系統相關的命令和服務,教你們如何使用命令行完成弱網環境的配置。微信
Mac OS X 10.10 之後,系統主要使用的是 `PF (Packet Filter, the BSD firewall)` 和 `dummynet(the BSD traffic shaper)` 這兩個服務來模擬各類弱網環境。app
dummynetcurl
DUMMYNET(4) BSD Kernel Interfaces Manual DUMMYNET(4) NAME dummynet -- traffic shaper, bandwidth manager and delay emulator DESCRIPTION dummynet is a system facility that permits the control of traffic going through the various network interfaces, by applying bandwidth and queue size limitations, implementing different scheduling and queue management policies, and emulating delays and losses. The user interface for dummynet is implemented by the dnctl program, so the reader is referred to the dnctl(8) manpage for a complete description of the capabilities of dummynet and on how to use it. SEE ALSO dnctl(8), setsockopt(2), bridge(4), ip(4), sysctl(8) HISTORY dummynet was initially implemented as a testing tool for TCP congestion control by Luigi Rizzo <luigi@iet.unipi.it>, as described on ACM Computer Communication Review, Jan.97 issue. Later it has been then modified to work at the ip and bridging level, integrated with the IPFW packet fil- ter, and extended to support multiple queueing and scheduling policies.
簡單來講,`dummynet` 是一個流量/帶寬/延時的控制工具,用戶可使用 `dnctl` 命令來配置和與之交互。tcp
dnctlide
在線文檔:http://www.manpagez.com/man/8/dnctl/工具
DNCTL(8) BSD System Manager's Manual DNCTL(8) NAME dnctl -- Traffic shaper control program SYNOPSIS dnctl [-anqs] {list | show} dnctl [-f | -q] flush dnctl [-q] {delete} [number ...] dnctl {pipe | queue} number config config-options dnctl [-s [field]] {pipe | queue} {delete | list | show} [number ...] dnctl [-nq] [-p preproc [preproc-flags]] pathname DESCRIPTION The dnctl utility is the user interface for controlling the dummynet(4) traffic shaper. dummynet operates by first using a packet filter to classify packets and divide them into flows, using any match pattern that can be used in dnctl rules. Depending on local policies, a flow can contain packets for a single TCP connection, or from/to a given host, or entire subnet, or a protocol type, etc.
簡單來講,`dnctl `是一個命令行工具,用於配製`dummynet`服務。測試
$ dnctl {pipe | queue} number config config-options
`dnctl` 提供了 2 種流量控制機制,一個是 pipe,一個是 queue,前者主要用於固定帶寬條件下的弱網模擬,後者則能夠試驗不一樣 pipe 使如何搶佔和共享可用帶寬的。一般咱們選擇前者來簡單地模擬弱網。ui
`config-options` 的種類特別多,弱網條件的配置基本上都在這裏了:this
The following parameters can be configured for a pipe: bw bandwidth Bandwidth, measured in [K|M]{bit/s|Byte/s}. A value of 0 (default) means unlimited bandwidth. delay ms-delay Propagation delay, measured in milliseconds. plr packet-loss-rate a floating-point number between 0 and 1, with 0 meaning no loss, 1 meaning 100% loss. queue {slots | sizeKbytes} Queue size, in slots or KBytes. Default value is 50 slots, which is the typical queue size for Ethernet devices.
綜上所述,咱們來定義一個 pipe number id 爲 1,帶寬限制 100Kbit/s,delay 100ms,loss:50% 的弱網環境:
// 建立配置並顯示 $ sudo dnctl pipe 1 config bw 100Kbit/s delay 100 plr 0.5 $ sudo dnctl show 00001: 100.000 Kbit/s 100 ms 50 sl.plr 0.500000 0 queues (1 buckets) droptail mask: 0x00 0x00000000/0x0000 -> 0x00000000/0x0000 // 清空配置並顯示 $ sudo dnctl -q flush $ sudo dnctl show
pf
咱們再來看看另外一個工具:`pf`,它是 Mac 系統的防火牆工具,咱們利用它來把通過系統的流量轉到咱們的弱網環境進行 filter 處理。
`pf` 主要使用配置文件保存防火牆規則,語法規範上比較嚴謹,cat /etc/pf.conf,可看到如下已有內容:
# This file contains the main ruleset, which gets automatically loaded # at startup. PF will not be automatically enabled, however. Instead, # each component which utilizes PF is responsible for enabling and disabling # PF via -E and -X as documented in pfctl(8). That will ensure that PF # is disabled only when the last enable reference is released. # # Care must be taken to ensure that the main ruleset does not get flushed, # as the nested anchors rely on the anchor point defined here. In addition, # to the anchors loaded by this file, some system services would dynamically # insert anchors into the main ruleset. These anchors will be added only when # the system service is used and would removed on termination of the service. # # See pf.conf(5) for syntax. # # com.apple anchor point # scrub-anchor "com.apple/*" nat-anchor "com.apple/*" rdr-anchor "com.apple/*" dummynet-anchor "com.apple/*" anchor "com.apple/*" load anchor "com.apple" from "/etc/pf.anchors/com.apple"
下面,咱們須要來撰寫屬於咱們本身的的規則。
1. 新建一個 pf.conf 文件
$ touch pf.conf
2. 添加路由規則
規則文檔:https://www.openbsd.org/faq/pf/filter.html
action [direction] [log] [quick] [on interface] [af] [proto protocol] [from src_addr [port src_port]] [to dst_addr [port dst_port]] [flags tcp_flags] [state]
詳細參數含義能夠參考文檔,這裏簡單列出幾個關鍵的配置:
[direction]: 流量的方向,上行:out,下行:in [proto protocol]:協議,tcp/udp/icmp 等 [from src_addr [port src_port]]:源 ip 和 port,默承認以使用 any [to dst_addr [port dst_port]]:目標 ip 和 port,默承認以使用 any
這裏咱們主要示例一下如何添加規則到咱們上面建立的 dummynet pipe 1
$ vi pf.conf # 本示例的 「上行 + 下行」 都配置了弱網,也能夠配置單向測測變化 # 測試 tcp,好比:curl www.baidu.com dummynet in proto tcp from any to any pipe 1 dummynet out proto tcp from any to any pipe 1 # 測試 udp,好比:音視頻通話 dummynet in proto udp from any to any pipe 1 dummynet out proto udp from any to any pipe 1 # 測試 ping,好比:ping baidu.com dummynet in proto icmp from any to any pipe 1 dummynet out proto icmp from any to any pipe 1
3. 啓動和加載 `PF` 配置
操做 `PF` 服務,須要藉助 `pfctl ` 命令。
# Mac 系統默認把 `PF` 服務關閉了,啓動 `PF` 服務 $ sudo pfctl -e # 加載自定義防火牆規則 $ sudo pfctl -f pf.conf # 恢復原始的防火牆規則 $ sudo pfctl -f /etc/pf.conf # 注意:使用 pfctl 命令會常常出現下面的 warning,沒有影響,忽略就行了。 "No ALTQ support in kernel"
小結
關於如何在 Mac 下使用命令行配置弱網環境就分享到這裏了,若有疑問的小夥伴歡迎來信 lujun.hust@gmail.com 交流。另外,也歡迎你們關注個人新浪微博 @盧_俊 或者 微信公衆號 @Jhuster 獲取最新的文章和資訊。