站在5年后的今天再审视这个议题,我们会发现情况在发生变化,据艾瑞咨询《2018年中国智能家居研究报告》[2] 中的调研结果,智能家居从业者眼中最看好的用户入口排名如下:

调研显示的结果极为分散,经过对“入口”概念的漫长争夺,智能家居从业者对入口仍无共识。
王学集表示,自己在创业初期也在寻找入口级设备的机会,直到半年后才逐渐意识到智能家居行业可能并没有一个确定的入口。他认为:
“智能家居是以AI的技术驱动了多设备联动,形成围绕式人机合一体验,目前看来很难有一个非常明确的设备能做到这样的水平。”
站在5年后的今天再审视这个议题,我们会发现情况在发生变化,据艾瑞咨询《2018年中国智能家居研究报告》[2] 中的调研结果,智能家居从业者眼中最看好的用户入口排名如下:

调研显示的结果极为分散,经过对“入口”概念的漫长争夺,智能家居从业者对入口仍无共识。
王学集表示,自己在创业初期也在寻找入口级设备的机会,直到半年后才逐渐意识到智能家居行业可能并没有一个确定的入口。他认为:
“智能家居是以AI的技术驱动了多设备联动,形成围绕式人机合一体验,目前看来很难有一个非常明确的设备能做到这样的水平。”
NTP 是 Network Time Protocol 的简称,也就是网络时间协议。而 NTP 服务器是可以通过网络来同步时间的服务器。Windows 自带的 NTP 服务器都在美国,有时间经常无法访问。再加上有朋友跟我留言,想让我收集一下 NTP 服务器,所以建立了此页面。
本页优先提供国内可以使用的 NTP 服务器地址,然后也收集了一些国外知名的 NTP 服务器地址,提供给大家选择。
个人建议,国内用阿里云、国外用谷歌或者苹果。也有朋友经过测试苹果在国内也是可以使用的,大家可以试试看。
附:Windows 10 修改时间服务器的方法
如果有什么问题或建议可以跟我留言,戳⇒ 联系我
国内知名公共 NTP 服务器地址
Chinese Public NTP Server
[国内 NTP 服务器] · 国际 NTP 服务器
国家授时中心 NTP 服务器
NTSC NTP Server
ntp.ntsc.ac.cn
中国 NTP 快速授时服务
NTP ORG CN
cn.ntp.org.cn
教育网
edu.ntp.org.cn
国际 NTP 快速授时服务
Pool NTP ORG
cn.pool.ntp.org
阿里云公共 NTP 服务器
Aliyun NTP Server
time.pool.aliyun.com
time1.aliyun.com
time2.aliyun.com
time3.aliyun.com
time4.aliyun.com
time5.aliyun.com
time6.aliyun.com
time7.aliyun.com
腾讯云公共 NTP 服务器
Tencent Cloud NTP Server
time1.cloud.tencent.com
time2.cloud.tencent.com
time3.cloud.tencent.com
time4.cloud.tencent.com
time5.cloud.tencent.com
教育网(高校自建)
EDU NTP Server
ntp.sjtu.edu.cn
ntp.neu.edu.cn
ntp.bupt.edu.cn
ntp.shu.edu.cn
国际 NTP 服务器
Global Public NTP Server
[国际 NTP 服务器] · 国内 NTP 服务器
国际 NTP 快速授时服务
Pool NTP ORG
pool.ntp.org
0.pool.ntp.org
1.pool.ntp.org
2.pool.ntp.org
3.pool.ntp.org
asia.pool.ntp.org
谷歌公共 NTP 服务器
Google NTP Server
time1.google.com
time2.google.com
time3.google.com
time4.google.com
苹果公司公共 NTP 服务器
Apple NTP Server
time.apple.com
time1.apple.com
time2.apple.com
time3.apple.com
time4.apple.com
time5.apple.com
time6.apple.com
time7.apple.com
微软 Windows NTP 服务器
Microsoft Windows NTP Server
time.windows.com
美国标准技术研究院 NTP 服务器
NIST NTP Server
time.nist.gov
time-nw.nist.gov
time-a.nist.gov
time-b.nist.gov
香港天文台公共 NTP 服务器
Hong Kong Observator NTP Server
stdtime.gov.hk
Chrome和Firefox为用户提供了在浏览器中管理已注册Service Worker的选项,包括从浏览器中删除Service Worker的选项。
服务工作者是大多数现代浏览器支持的一项新兴功能,使站点和服务无需在浏览器中打开即可与浏览器进行交互。
将它们视为按需流程,可以使用推送通知和数据同步,或者使站点脱机工作。
当前没有将Web浏览器设计为在Service Worker在浏览器中注册时始终提示用户。当前,大多数情况下,这是作为后台进程发生的。

服务工作者可以自动注册,也可以在用户接受提示后注册。Pinterest是在Chrome或Firefox中访问该网站时会自动注册的网站。
用户不清楚这是因为它发生在后台。
Chrome和Firefox没有提供有关如何管理以前添加到浏览器的Service Worker的明确信息。尽管存在功能,但它们在此时或多或少对用户隐藏了,如果需要从浏览器中删除以前注册的工作人员,这将是一个问题。
本指南为您提供了在Firefox和Chrome中管理工作人员的方法。
有用的信息

Firefox用户可以通过以下方式在浏览器中管理所有注册的Service Worker:
在Mozilla Firefox中禁用服务工作者

Firefox用户可以通过以下方式(通过我们广泛的Firefox隐私和安全设置指南列表)禁用浏览器中的Service Worker :
要撤消更改,请重复此过程,但请确保在完成操作后将首选项的值设置为true。

在Google Chrome中禁用服务人员
目前似乎没有办法在Chrome浏览器中禁用该功能。如果您找到了一种方法,请在下面发表评论,我将尽快更新文章。
越 来越多的家庭和企业转向WiFi网络作为其首选的互联网接入的提供方式。无线网络对于终端用户更为便捷,使每个人都能够充分利用其移动设备的优势。无线网络相比传统的有线网络而言,也免除了线接的烦扰和限制。
从管理员的角度来说,WiFi网络虽然有很多的优势,但同时也伴随有一系列必须予以解决的其他挑战。这不仅仅只是为您的所有用户提供充足的连接的问题。您还需要了解您的网络的其他方面,如覆盖区域和信道重叠。
对于我们部分使用家庭WiFi网络的用户而言,我们就是自己的网络管理员。如果您是这样的情况或只是一位具有好奇心的终端用户,您需要了解的您的网络的其中一大特性就是WiFi信号强度。这个值对于您的网络活动效率是一个决定性的因素。让我们深度了解一下WiFi信号以及它们是如何影响您的无线网络使用的。
WiFi网络使用无线电波来在不同的设备之间建立通信。这些设备可能包括计算机,移动手机,平板电脑或网络路由器。无线网络路由器是互联网或其他以太网络有线连接和无线连接设备之间的接口。
路由器对从WiFi网络用户那里接收来的无线电信号进行解码并将它们传至互联网。反过来,路由器会将从互联网接收的数据由二进位数据转换成无线电波,传送至使用同一网络的设备。
产生WiFi信号的无线电波使用的2.4 GHz和5 GHz的频带。这些频率要高于电视或手机所使用的频率,相对较低频率能够传递更多的数据。
WiFi信号在传输数据时使用的是802.11网络标准。WiFi网络采用了一系列不同协议的变体。您将会了解到的部分最常见的协议包括2.4GHz频带所使用的802.11n以及5GHz频带主要使用的802.11ac。其他协议您可能还会看到802.11b,它与802.11g是最慢标准。
整个网络覆盖区域内的WiFi信号强度直接影响着用户高效处理各种网络活动的能力。在深入探析怎样的信号强度才适合您进行相应的WiFi网络活动之前,让我们讨论一下 WiFi信号强度是如何测量的。
信号强度是以dBm为单位的。它指的是分贝毫瓦,以从0到-100内的负值表示。因此,-40的信号相比-80的信号更强,因为-80距离0更远,因此是一个更小的数字。
dBm是一个对数性的,而不是线性的,这意味着信号强度之间的变化并不是平滑渐进式的。从这个层面来说,3 dBm的不同会使之前的信号强度减半或提升一倍。
能够影响到您的WiFi表现的背景噪音等级也是用dBm表示的。对于噪音等级而言,数值越接近0,就表示噪音等级越高。经测量的-10 dBm的噪音要高于-40 dBm的噪音。
下表揭示了您应当努力实现的最低信号强度,只有达到才能将您的WiFi网络用于各种不同目的。
| 信号强度 | 限定符 | 适合用途 |
|---|---|---|
| -30 dBm | 极好 | 这是可实现的最大信号强度,适用于任何一种使用情景。 |
| -50 dBm | 极好 | 此极好的信号强度适于各种网络使用情形。 |
| -65 dBm | 非常好 | 建议为智能手机和平板电脑提供支持。 |
| -67 dBm | 非常好 | 此信号强度对于网络电话和流媒体视频的使用是足够的。 |
| -70 dBm | 可接受 | 该等级是确保实现稳定的数据包传输的最低信号强度要求,对于网页冲浪和收发邮件的使用是足够的。 |
| -80 dBm | 不良 | 实现基本连接,但数据包传输不稳定。 |
| -90 dBm | 非常差 | 大多都是噪音,抑制大多数功能的实现。 |
| -100 dBm | 最差 | 全是噪音。 |
能够影响到您的网络WiFi信号的有 一系列不同因素。其中部分因素有:
路由器位置的各个不同方面会影响到良好信号的传输表现。这些包括:
将您的路由器的设置改成自动固件升级以保持其处于高效运作状态。阶段性地重启您的路由器也是一个比较好的做法,有利于实现良好的信号覆盖。
需要较强信号的设备,如那些用于玩游戏或观看视频的设备,将它们放在靠近路由器的位置可能会获得更好的信号表现。在一些情况下,您可能需要通过使用像路由器这样的附加设备来 扩展您的WiFi信号范围以增强WiFi信号强度。
UPDATE w_zshop_goods_sku_images SET path = REPLACE(path, ‘http://qq.com’,’https://qq.com’);
UPDATE w_zshop_commodities SET details = REPLACE(details, ‘http://qq.com’,’https://qq.com’);
UPDATE w_zshop_commodities SET params = REPLACE(params, ‘http://qq.com’,’https://qq.com’);
UPDATE w_users SET profile = REPLACE(profile, ‘http://qq.com’,’https://qq.com’);
UPDATE w_zshop_banners SET pic = REPLACE(pic, ‘http://qq.com’,’https://qq.com’);
UPDATE w_zshop_order_coms SET pic = REPLACE(pic, ‘http://qq.com’,’https://qq.com’);
虽然已经用 coturn 来作为 webrtc 的转发服。 但是我们只做了一个最基本的静态key的加密校验而已。但是对于转发的流量和转发的时长,却没法统计。
但是事实上,对于转发的流量和时长对于我们的业务来说是非常必要的。
刚好 coturn 有提供了一个统计的redis配置,redis-statsdb,这个是就是 turnserver 会将一些统计的数据存到 redis 中。 然后我们去取就行了。
所以要在配置文件里面加上这一个配置:
| 1 | redis-statsdb=”ip=59.57.xx.xx dbname=13 port=6379 connect_timeout=30″ |
具体文档:
-O, –redis-statsdb Redis status and statistics database connection string, if used (default – empty, no Redis stats DB used). This database keeps allocations status information, and it can be also used for publishing and delivering traffic and allocation event notifications. The connection string has the same parameters as redis-userdb connection string.https://github.com/coturn/coturn/wiki/turnserver
也就是这个参数是用来做状态统计的。 可以用来发布和传递流量, 还有断开和连接的webhook通知。通过这个统计的redis db,我们可以得到这一次转发的开始时间,结束时间,以及转发的流量。
大概的一个截图就是:

这边还有更详细的说明: schema.stats.redis
状态的key就是:
| 1 | turn/user/<username>/allocation/<id>/status |
举例:
| 1 | turn/realm/pano/user/1531994598:fe909a0a4cde20be0a7bb9fbfdc8d6dc_21_24_18154723/allocation/003000000000002028/status |

他的值有可能是 new lifetime=… 或者是 refreshed lifetime=…
一个用户名下可能有多个状态。
然后是订阅:
如果是订阅所有的配置,那么就是 turn/realm/*/user/*/allocation/*/total_traffic
因为不能过期,所以redis 的配置文件,要配置这两个:
| 1 2 | timeout 0 tcp-keepalive 60 |
假设我们已经在使用webrtc的应用上连接上turn server了,并且已经在转发了。那我们就可以看下这个redis跑的统计数据都是什么样的?
接下来先在redis 先sub一下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | 127.0.0.1:6379[13]> psubscribe turn/realm/* Reading messages… (press Ctrl-C to quit) 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417691:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003326/status” 4) “new lifetime=600” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417569:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003324/status” 4) “new lifetime=600” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417569:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/003000000000003700/status” 4) “refreshed lifetime=0” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417569:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/003000000000003700/status” 4) “deleted” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417569:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/003000000000003700/total_traffic” 4) “rcvp=0, rcvb=0, sentp=0, sentb=0” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417569:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003324/traffic” 4) “rcvp=1610, rcvb=1607159, sentp=438, sentb=22052” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417569:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003324/traffic” 4) “rcvp=1385, rcvb=1404252, sentp=663, sentb=31187” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417569:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003324/traffic” 4) “rcvp=1407, rcvb=1442093, sentp=641, sentb=30066” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417569:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003324/traffic” 4) “rcvp=1383, rcvb=1408780, sentp=665, sentb=31146” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417691:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003326/status” 4) “refreshed lifetime=0” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417691:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003326/status” 4) “deleted” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417691:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003326/total_traffic” 4) “rcvp=0, rcvb=0, sentp=0, sentb=0” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417569:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003324/status” 4) “refreshed lifetime=0” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417691:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003327/status” 4) “new lifetime=600” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417691:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/003000000000003705/status” 4) “new lifetime=600” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417569:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003324/status” 4) “deleted” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417569:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003324/total_traffic” 4) “rcvp=5785, rcvb=5862284, sentp=2407, sentb=114451” |

可以看到进行一次连接的话,会分配好几条临时会话。 从下图来看的话,可以看到有 4 条,其实这四条都属于同一个连接。
接下来我们一条一条来分析:
总结一下:
每个 channel 刚开始创建的时候,生命周期只有 600s, 这个可以在 配置文件设置:
| 1 2 3 4 5 | # Uncomment to set the lifetime for the channel. # Default value is 600 secs (10 minutes). # This value MUST not be changed for production purposes. # #channel-lifetime=600 |
而且刚开始创建就会有状态通知,内容就是 new lifetime=600。
虽然每个channel的生命周期都是 600s, 但是并不意味着,600s 之后,这个channel就会被删除,其实不是的,这个是可以被续的,也就是如果这个 channel 被续了,那么就会有这个状态通知:
| 1 2 3 4 | 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532403222:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/004000000000003897/status” 4) “refreshed lifetime=600” |
这个说明被续了一个周期了。当然也有不续的,这时候也会有这个状态,不过这时候 lifetime 是 0:
| 1 2 3 4 | 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532415366:07a9939e437c9bca97f67b4b74de6a2f_21_24_22819787/allocation/004000000000003905/status” 4) “refreshed lifetime=0” |
一旦 lifetime 为0, 就说明这个channel要被删除了。 这时候就会收到 delete 状态:
| 1 2 3 4 | 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532415366:07a9939e437c9bca97f67b4b74de6a2f_21_24_22819787/allocation/000000000000001816/status” 4) “deleted” |
这时候就说明这条channel已经被删除了。
而且每一个channel 的最长生命周期是可以配置的,默认是 3600s:
| 1 2 3 4 5 | # Uncomment if you want to set the maximum allocation # time before it has to be refreshed. # Default is 3600s. # #max-allocate-lifetime=3600 |
所以一个完整的 channel 周期就是 创建-> 续周期(一次以上) -> 删除 (如果续的是 0)
针对这个,我后面试了一下, 在一次长达 一个多小时的webrtc连接, 那个转发流量的channel, 续周期续了7次, 一次 600s, 总的是 7 * 600 = 4200, 比3600 还大了,但是也还没有断开,所以这个也有点奇怪???
每一条channel 在生命周期之内,如果有进行流量转发的话,那么就会每隔一段时间就会有 traffic 这个状态过来,注意,如果是 stun 或者 local 这种不走转发的,那么是没有这个事件的:
| 1 2 3 4 | 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417569:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003324/traffic” 4) “rcvp=1383, rcvb=1408780, sentp=665, sentb=31146” |
而且每次的channel 的生命周期结束之后,也就是 delete 状态,也会收到这一条生命周期的所有的转发流量数据。
| 1 2 3 4 | 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532417569:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003324/total_traffic” 4) “rcvp=5785, rcvb=5862284, sentp=2407, sentb=114451” |
跟 traffic 不一样, traffic 是真的是转发有流量,才会每隔一段时间抛一次,而 total_traffic 是必会有的,不管是穿透还是转发, 只不过如果是穿透的话,那就是都是 0,比如:
| 1 2 3 4 | 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532415366:07a9939e437c9bca97f67b4b74de6a2f_21_24_22819787/allocation/004000000000003905/total_traffic” 4) “rcvp=0, rcvb=0, sentp=0, sentb=0” |
每一个 delete 状态,都会跟着一个 total_traffic 事件。 而里面的 这些参数,其实都是 traffic 的所有对应参数的总和。
这四个参数分别是:
| 1 2 3 4 | rcvp: 收到的数据包 rcvb: 收到的字节(byte) sentp: 发送的数据包 sentb: 发送的字节(byte) |
所以我们如果要统计这一次转发的时长的话,那么就要记录这次连接的所有的channel。也就是如果这一次的转发,有5个channel,那么就第一个channel创建的时候,就是开始时间, 当所有的channel 都断开的时候,那么就是结束时间。 一定要所有的channel 都断开,才算转发结束,
而且中间还会有不断的新的channel被创建,这些新的channel也要加入到map里面去。然后每一个channel断开,就从map里面去掉, 一直到最后map为空的话,才算转发结束。算转发的总流量也是一样,每一个channel都会有一段流量。 当所有的channel都断开的时候,加起来就是总的转发流量。
刚开始是这样子写的:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | package main import ( “errors” “fmt” “github.com/garyburd/redigo/redis“ “iGong/util/log” “strconv” “strings” “sync” “time” ) type OnlineTimeBucket struct { Data map[string]*OnlineTimeBucketSub Locker *sync.Mutex } func NewOnlineTimeBucket() *OnlineTimeBucket { return &OnlineTimeBucket{ Data: make(map[string]*OnlineTimeBucketSub), Locker: &sync.Mutex{}, } } type OnlineTimeBucketSub struct { Timer map[string]*OnlineTime } type OnlineTime struct { Start int64 End int64 Delete bool TotalTraffIc bool Rcvp int Rcvb int Sentp int Sentb int } var onlineTimeBucket *OnlineTimeBucket var serverTime = time.Now().Unix() /* turn/realm/pano/user/1531882310:7ed1019263ce5e09f3d40a1ca15ae992_21_24_18152992/allocation/000000000000000495/status new lifetime=600 turn/realm/pano/user/1531881513:7ed1019263ce5e09f3d40a1ca15ae992_21_24_18152992/allocation/001000000000000462/status refreshed lifetime=0 turn/realm/pano/user/1531882310:7ed1019263ce5e09f3d40a1ca15ae992_21_24_18152992/allocation/004000000000000899/status deleted turn/realm/pano/user/1531881513:7ed1019263ce5e09f3d40a1ca15ae992_21_24_18152992/allocation/001000000000000462/total_traffic rcvp=18612, rcvb=894124, sentp=104268, sentb=114206669 turn/realm/pano/user/1531881926:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/004000000000000896/traffic rcvp=1847, rcvb=2052114, sentp=201, sentb=10652 */ func TurnServerStats() { conn, err := RedisTurn.GetConn() sub := redis.PubSubConn{Conn: conn} if err != nil { log.Error(err) } defer conn.Close() onlineTimeBucket = NewOnlineTimeBucket() sub.PSubscribe(“turn/realm/*”) for { switch n := sub.Receive().(type) { //case redis.Message: // fmt.Printf(“Message: %s %s\n”, n.Channel, n.Data) case redis.PMessage: err = forwardStats(n) if err != nil { continue } case error: fmt.Printf(“error: %v\n”, n) return } } } func forwardStats(data redis.PMessage) (err error) { fmt.Printf(“PMessage: %s %s %s\n”, data.Pattern, data.Channel, data.Data) event, deviceId, channel, err := decodeChannel(data.Channel) if err != nil { log.Error(err) return err } log.Info(event, deviceId) switch event { case “status”: //统计时长 和在线状态 onlineStatus := decodeDataWithStatus(data.Data) log.Info(onlineStatus) addOnlineTime(deviceId, channel, onlineStatus) case “total_traffic”: //统计流量 这个事件过来说明转发已经结束 并且只有一个会话是有值的 trafficMap, err := decodeDataWithTraffic(data.Data) if err != nil { return err } //rcvp 接收到的包数量 rcvb 接收到的流量 sentp 发送的包数量 sentb 发送的包流量 log.Info(trafficMap) addFlow(deviceId, channel, trafficMap) } return } func decodeChannel(channel string) (event string, deviceId, channelId string, err error) { args := strings.Split(channel, “/”) if len(args) != 8 { err = errors.New(“channel fail .”) return } event = args[7] deviceId = strings.Split(args[4], “:”)[1] channelId = args[6] return } func decodeDataWithStatus(data []byte) (onlineStatus int) { args := strings.Split(string(data), “=”) switch args[0] { //新建 case “new lifetime”: onlineStatus = 0 //刷新 case “refreshed lifetime”: onlineStatus = 1 //移除 case “deleted”: onlineStatus = 2 default: onlineStatus = 1 } return } func decodeDataWithTraffic(data []byte) (stats map[string]int, err error) { args := strings.Split(string(data), “,”) if len(args) != 4 { err = errors.New(“traffic data fail”) return } stats = make(map[string]int) for _, v := range args { statsInfo := strings.Split(v, “=”) s, _ := strconv.Atoi(statsInfo[1]) stats[strings.TrimLeft(statsInfo[0], ” “)] = s } return } //记录转发时长 func addOnlineTime(deviceId, channelId string, onlineStatus int) { if onlineStatus == 1 { return } onlineTimeBucket.Locker.Lock() timer := time.Now().Unix() if _, ok := onlineTimeBucket.Data[deviceId]; !ok { j := new(OnlineTimeBucketSub) j.Timer = make(map[string]*OnlineTime) onlineTimeBucket.Data[deviceId] = j } switch onlineStatus { case 0: log.Info(“new life_time”) var onlineModel = new(OnlineTime) onlineModel.Start = timer onlineTimeBucket.Data[deviceId].Timer[channelId] = onlineModel case 2: log.Info(“delete life_time”) if _, ok := onlineTimeBucket.Data[deviceId].Timer[channelId]; !ok { var onlineModel = new(OnlineTime) onlineModel.Start = serverTime onlineTimeBucket.Data[deviceId].Timer[channelId] = onlineModel } onlineTimeBucket.Data[deviceId].Timer[channelId].End = timer onlineTimeBucket.Data[deviceId].Timer[channelId].Delete = true } onlineTimeBucket.Locker.Unlock() } //记录转发流量并入库 func addFlow(deviceId, channelId string, trafficMap map[string]int) { onlineTimeBucket.Locker.Lock() if _, ok := onlineTimeBucket.Data[deviceId]; !ok { j := new(OnlineTimeBucketSub) j.Timer = make(map[string]*OnlineTime) onlineTimeBucket.Data[deviceId] = j } onlineTimeBucket.Data[deviceId].Timer[channelId].Rcvb = trafficMap[“rcvb”] onlineTimeBucket.Data[deviceId].Timer[channelId].Rcvp = trafficMap[“rcvp”] onlineTimeBucket.Data[deviceId].Timer[channelId].Sentb = trafficMap[“sentb”] onlineTimeBucket.Data[deviceId].Timer[channelId].Sentp = trafficMap[“sentp”] onlineTimeBucket.Data[deviceId].Timer[channelId].TotalTraffIc = true var isDelete = true for _, v := range onlineTimeBucket.Data[deviceId].Timer { if v.Delete == false || v.TotalTraffIc == false { isDelete = false } } if isDelete { //计算时间,,流量 var rcvb, rcvp, sentb, sentp int var end int64 start := time.Now().Unix() for _, v := range onlineTimeBucket.Data[deviceId].Timer { rcvb += v.Rcvb rcvp += v.Rcvp sentp += v.Sentp sentb += v.Sentb if start > v.Start { start = v.Start } if end < v.End { end = v.End } } accountInfo := strings.Split(deviceId, “_”) if len(accountInfo) < 4 { log.Info(“deviceId len fail “, deviceId) } total_time := onlineTimeBucket.Data[deviceId].Timer[channelId].End – onlineTimeBucket.Data[deviceId].Timer[channelId].Start err := InsertTurnServerLogs(accountInfo[3], accountInfo[0], accountInfo[1], accountInfo[2], start, end, total_time, rcvp, rcvb, sentp, sentb) if err != nil { log.Error(err) } onlineTimeBucket.Data[deviceId].Timer = nil delete(onlineTimeBucket.Data, deviceId) } onlineTimeBucket.Locker.Unlock() } |
按照上面的算法来做的话,当我在用web测试的时候,会出现一个情况:
就是如果 coturn 的连接断开了。但是对于这个username, 他还是会保持一两条临时 channel
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532433896:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/000000000000001857/traffic” 4) “rcvp=1466, rcvb=1325047, sentp=582, sentb=29696” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532433896:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003357/status” 4) “refreshed lifetime=0” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532433896:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003357/status” 4) “deleted” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532433896:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003357/total_traffic” 4) “rcvp=0, rcvb=0, sentp=0, sentb=0” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532433896:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/000000000000001857/status” 4) “refreshed lifetime=0” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532433896:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/003000000000003734/status” 4) “new lifetime=600” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532433896:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/001000000000003358/status” 4) “new lifetime=600” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532433896:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/000000000000001857/status” 4) “deleted” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532433896:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/000000000000001857/total_traffic” 4) “rcvp=1466, rcvb=1325047, sentp=582, sentb=29696” |

明明我连接断开了,但是又重新连接了两条。而且这两条根本不会释放
这个就会导致 isDelete 的条件没法成立,因为总有新的链接没有释放。
而且后面还发现,一次转发,虽然有好几条channel存在,但是真正转发流量的channel只有一条,而且过了一个多小时,还是没有断。所以原则上我们只要去判断这一条channel,就可以知道本次转发的时长和流量了。 其他的channel都不要管。但是如果是stun这种穿透的,因为没有转发流量,所以根本不知道那一条的channel,才是起作用的那一条????
后面发现这种情况其实是一个bug, 之所以浏览器刷新还保持两条turn channel 是因为浏览器在刷新的时候,其实没有明确的给手机端发送断开webrtc的信号。导致手机端其实还不知道webrtc断开了。所以手机端其实是对turnserver连接进行重连了, 这也是为啥会有新的两条channel 的问题。
我试了其他端,比如 ios 端,如果是断开的话,是不会有遗留turnserver 的channel 的,最后全部都会被清掉。因此对于web端,在刷新浏览器,或者是退出页面的时候,都要给手机的发送断开webrtc的信号,并且断开本地的webrtc连接。
所以web端的代码得改下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // 关掉 webrtc stopWebRtcServer: function () { var self = this; // 给手机端发送一个webrtc 关闭的指令 self.mqttSocket.pub( self.subCommonStr + ‘toTarget’, { “method”: “webrtc.stop”, }, { useAes: true, } ).done(function (data) { console.log(“%c accept stop:” + JSON.stringify(data), “color:red”); }); // 清空状态统计的定时 clearTimeout(self.rtcStateMap.timeId); // 关闭signal长连接 self.mqttSocket.close(); // 关闭webrtc 连接 self.rtcSocket.close(); }, |
其中 rtcSocket 的 close 事件为:
| 1 2 3 4 5 6 7 | close: function(){ // 停止 video 传输 var video = this._pc.getRemoteStreams()[0].getVideoTracks()[0]; video.stop(); // 关掉 pc 对象 this._pc.close(); } |

先停止video传输,再释放掉 pc 对象。这时候本来 webrtc work 的时候,是这样的:
看到的消息就是:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532677507:ac5fa606abf5ae9d02bd4206625b4911_21_24_18152992/allocation/001000000000004071/status” 4) “new lifetime=600” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532677507:ac5fa606abf5ae9d02bd4206625b4911_21_24_18152992/allocation/004000000000004390/status” 4) “new lifetime=600” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532677507:ac5fa606abf5ae9d02bd4206625b4911_21_24_18152992/allocation/000000000000002210/status” 4) “new lifetime=600” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532677507:ac5fa606abf5ae9d02bd4206625b4911_21_24_18152992/allocation/004000000000004390/status” 4) “refreshed lifetime=0” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532677507:ac5fa606abf5ae9d02bd4206625b4911_21_24_18152992/allocation/004000000000004390/status” 4) “deleted” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532677507:ac5fa606abf5ae9d02bd4206625b4911_21_24_18152992/allocation/004000000000004390/total_traffic” 4) “rcvp=0, rcvb=0, sentp=0, sentb=0” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532677507:ac5fa606abf5ae9d02bd4206625b4911_21_24_18152992/allocation/001000000000004071/traffic” 4) “rcvp=1546, rcvb=1442311, sentp=502, sentb=24802” |


就是建了3条 channel ,然后删掉一条 390 ,保留两条, 后面分别是 210 和 071
这时候我点击 停止webrtc 按钮,图片传输就会停止了。这时候webrtc 就断开了。
这时候就收到了断开的消息了, 210 和 071 都断开了:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532677507:ac5fa606abf5ae9d02bd4206625b4911_21_24_18152992/allocation/000000000000002210/status” 4) “refreshed lifetime=0” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532677507:ac5fa606abf5ae9d02bd4206625b4911_21_24_18152992/allocation/001000000000004071/status” 4) “refreshed lifetime=0” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532677507:ac5fa606abf5ae9d02bd4206625b4911_21_24_18152992/allocation/000000000000002210/status” 4) “deleted” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532677507:ac5fa606abf5ae9d02bd4206625b4911_21_24_18152992/allocation/000000000000002210/total_traffic” 4) “rcvp=0, rcvb=0, sentp=0, sentb=0” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532677507:ac5fa606abf5ae9d02bd4206625b4911_21_24_18152992/allocation/001000000000004071/status” 4) “deleted” 1) “pmessage” 2) “turn/realm/*” 3) “turn/realm/pano/user/1532677507:ac5fa606abf5ae9d02bd4206625b4911_21_24_18152992/allocation/001000000000004071/total_traffic” 4) “rcvp=4595, rcvb=4367095, sentp=1549, sentb=74756” |

这时候channel 就全部为空了。
所以要这样才可以。 但是问题来了,刚才是我们手动点击 停止 webrtc 按钮的,当然流程是对的。
但是如果是直接刷新浏览器呢,那可是来不及处理的????
事实上也是有这个问题,如果直接刷新浏览器,并且不作处理的时候,就会出现最早之前的那种情况,就是手机端认为还连着,所以 turnserver 又建了两条新的 channel 。
所以我后面加了这个事件 onbeforeunload:
| 1 2 3 4 5 6 | // 这时候要设置一个unload事件,不然如果直接浏览器刷新的话,手机端是不知道webrtc不用了,他还会连接 turnserver, 导致turnserver 的session 一直在,后面没法算时间 // 设置unonload, 防止直接刷新浏览器的时候,没有传 webrtc.stop 指令 window.onbeforeunload = function(){ self.stopWebRtcServer(); return true; }; |

每次用户刷新的时候,这时候就会弹出这个窗口,当用户点击 重新加载的时候, 这时候 stop 操作就已经处理完了。
因此就成功关闭了,缺点就是用户每次刷新都会弹窗,并且要点击重新加载。
所以服务端来说的话,整个连接过程中创建的channel 都要做判断,只有当channel 全部断掉的时候, 才判断这个连接结束,这时候才要算时间。虽然每一次连接都有一条channel 在发送流量。所以如果 traffic 有值的话,那么就是这一条有流量统计。所以如果有收到有流量的 total_traffic 的事件 ,那么应该就是 relay 的连接断开了。这时候就可以计算时长并入库了。
所以修改后的代码如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | package main import ( “errors” “fmt” “github.com/garyburd/redigo/redis“ “iGong/util/log” “strconv” “strings” “sync” “time” ) type OnlineTimeBucket struct { Data map[string]*OnlineTimeBucketSub Locker *sync.RWMutex } func NewOnlineTimeBucket() *OnlineTimeBucket { return &OnlineTimeBucket{ Data: make(map[string]*OnlineTimeBucketSub), Locker: &sync.RWMutex{}, } } type OnlineTimeBucketSub struct { Timer map[string]*OnlineTime } //map 存在线时间,结束时间-开始时间,,结束之后再存入表 type OnlineTime struct { Start int64 RefreshedFlow int64 End int64 Delete bool TotalTraffIc bool Rcvp int Rcvb int Sentp int Sentb int } var onlineTimeBucket *OnlineTimeBucket var serverTime = time.Now().Unix() /* turn/realm/pano/user/1531882310:7ed1019263ce5e09f3d40a1ca15ae992_21_24_18152992/allocation/000000000000000495/status new lifetime=600 turn/realm/pano/user/1531881513:7ed1019263ce5e09f3d40a1ca15ae992_21_24_18152992/allocation/001000000000000462/status refreshed lifetime=0 turn/realm/pano/user/1531882310:7ed1019263ce5e09f3d40a1ca15ae992_21_24_18152992/allocation/004000000000000899/status deleted turn/realm/pano/user/1531881513:7ed1019263ce5e09f3d40a1ca15ae992_21_24_18152992/allocation/001000000000000462/total_traffic rcvp=18612, rcvb=894124, sentp=104268, sentb=114206669 turn/realm/pano/user/1531881926:26e4cd38fa6fc39fa8fc40fb25fe558c_21_24_18152649/allocation/004000000000000896/traffic rcvp=1847, rcvb=2052114, sentp=201, sentb=10652 */ func TurnServerStats() { conn, err := RedisTurn.GetConn() sub := redis.PubSubConn{Conn: conn} if err != nil { log.Error(err) } defer conn.Close() onlineTimeBucket = NewOnlineTimeBucket() sub.PSubscribe(“turn/realm/*”) for { switch n := sub.Receive().(type) { //case redis.Message: // fmt.Printf(“Message: %s %s\n”, n.Channel, n.Data) case redis.PMessage: err = forwardStats(n) if err != nil { continue } case error: fmt.Printf(“error: %v\n”, n) return } } } func forwardStats(data redis.PMessage) (err error) { fmt.Printf(“PMessage: %s %s %s\n”, data.Pattern, data.Channel, data.Data) event, deviceId, channel, err := decodeChannel(data.Channel) if err != nil { log.Error(err) return err } log.Info(event, deviceId) switch event { case “status”: //统计时长 和在线状态 onlineStatus := decodeDataWithStatus(data.Data) log.Info(onlineStatus) addOnlineTime(deviceId, channel, onlineStatus) case “traffic”, “total_traffic”: //统计流量 这个事件过来说明转发已经结束 并且只有一个会话是有值的 trafficMap, err := decodeDataWithTraffic(data.Data) if err != nil { return err } //rcvp 接收到的包数量 rcvb 接收到的流量 sentp 发送的包数量 sentb 发送的包流量 log.Info(trafficMap) addFlow(deviceId, channel, trafficMap, event) } return } func decodeChannel(channel string) (event string, deviceId, channelId string, err error) { args := strings.Split(channel, “/”) if len(args) != 8 { err = errors.New(“channel fail .”) return } event = args[7] deviceId = strings.Split(args[4], “:”)[1] channelId = args[6] return } func decodeDataWithStatus(data []byte) (onlineStatus int) { args := strings.Split(string(data), “=”) switch args[0] { //新建 case “new lifetime”: onlineStatus = 0 //刷新 case “refreshed lifetime”: onlineStatus = 1 //移除 case “deleted”: onlineStatus = 2 default: onlineStatus = 1 } return } func decodeDataWithTraffic(data []byte) (stats map[string]int, err error) { args := strings.Split(string(data), “,”) if len(args) != 4 { err = errors.New(“traffic data fail”) return } stats = make(map[string]int) for _, v := range args { statsInfo := strings.Split(v, “=”) s, _ := strconv.Atoi(statsInfo[1]) stats[strings.TrimLeft(statsInfo[0], ” “)] = s } return } //记录转发时长 func addOnlineTime(deviceId, channelId string, onlineStatus int) { if onlineStatus == 1 { return } timer := time.Now().Unix() if _, ok := onlineTimeBucket.Data[deviceId]; !ok { j := new(OnlineTimeBucketSub) j.Timer = make(map[string]*OnlineTime) onlineTimeBucket.Locker.Lock() onlineTimeBucket.Data[deviceId] = j onlineTimeBucket.Locker.Unlock() } onlineTimeBucket.Locker.RLock() switch onlineStatus { case 0: log.Info(“new life_time”) var onlineModel = new(OnlineTime) onlineModel.Start = timer onlineTimeBucket.Data[deviceId].Timer[channelId] = onlineModel case 2: log.Info(“delete life_time”) if _, ok := onlineTimeBucket.Data[deviceId].Timer[channelId]; !ok { var onlineModel = new(OnlineTime) onlineModel.Start = serverTime onlineTimeBucket.Data[deviceId].Timer[channelId] = onlineModel } onlineTimeBucket.Data[deviceId].Timer[channelId].End = timer onlineTimeBucket.Data[deviceId].Timer[channelId].Delete = true } onlineTimeBucket.Locker.RUnlock() } //记录转发流量并入库 func addFlow(deviceId, channelId string, trafficMap map[string]int, event string) { if _, ok := onlineTimeBucket.Data[deviceId]; !ok { j := new(OnlineTimeBucketSub) j.Timer = make(map[string]*OnlineTime) j.Timer[channelId].Start = time.Now().Unix() onlineTimeBucket.Locker.Lock() onlineTimeBucket.Data[deviceId] = j onlineTimeBucket.Locker.Unlock() } else { } onlineTimeBucket.Locker.RLock() if event == “total_traffic” { onlineTimeBucket.Data[deviceId].Timer[channelId].Rcvb = trafficMap[“rcvb”] onlineTimeBucket.Data[deviceId].Timer[channelId].Rcvp = trafficMap[“rcvp”] onlineTimeBucket.Data[deviceId].Timer[channelId].Sentb = trafficMap[“sentb”] onlineTimeBucket.Data[deviceId].Timer[channelId].Sentp = trafficMap[“sentp”] onlineTimeBucket.Data[deviceId].Timer[channelId].TotalTraffIc = true var isDelete = true if trafficMap[“rcvb”] == 0 { //当穿透的时候流量为0,并且不会保存回话,所以需要判断所有会话是否关闭 当转发的时候,流量会大于0 ,但是可能会保留回话,所以转发的时候只需要判断流量过来就可以结束 for _, v := range onlineTimeBucket.Data[deviceId].Timer { if v.Delete == false || v.TotalTraffIc == false { isDelete = false } } } if isDelete { onlineTimeBucket.Locker.RUnlock() insertFlowLogs(deviceId) return } } else { onlineTimeBucket.Data[deviceId].Timer[channelId].RefreshedFlow = time.Now().Unix() } onlineTimeBucket.Locker.RUnlock() } func insertFlowLogs(deviceId string) { log.Info(“start insertFlowLogs=>”,deviceId) var rcvb, rcvp, sentb, sentp int var end int64 start := time.Now().Unix() for _, v := range onlineTimeBucket.Data[deviceId].Timer { rcvb += v.Rcvb rcvp += v.Rcvp sentp += v.Sentp sentb += v.Sentb if start > v.Start { start = v.Start } if end < v.End { end = v.End } } accountInfo := strings.Split(deviceId, “_”) if len(accountInfo) < 4 { log.Info(“deviceId len fail “, deviceId) } err := InsertTurnServerLogs(accountInfo[3], accountInfo[0], accountInfo[1], accountInfo[2], start, end, end-start, rcvp, rcvb, sentp, sentb) if err != nil { log.Error(err) } onlineTimeBucket.Locker.Lock() onlineTimeBucket.Data[deviceId].Timer = nil delete(onlineTimeBucket.Data, deviceId) onlineTimeBucket.Locker.Unlock() } //程序关闭时调用,,记录 使用时长 func forceInsertTurnServerUseLogs() { onlineTimeBucket.Locker.Lock() log.Info(“start forceInsertTurnServerUseLogs”) for k, v := range onlineTimeBucket.Data { //取其中一个的开始时间就可以 var start = time.Now().Unix() var end = time.Now().Unix() var rcvb, rcvp, sentb, sentp int for _, v := range v.Timer { rcvb += v.Rcvb rcvp += v.Rcvp sentp += v.Sentp sentb += v.Sentb if start > v.Start { start = v.Start } } useTime := end – start accountInfo := strings.Split(k, “_”) if len(accountInfo) < 4 { log.Info(“deviceId len fail “, k) } err := InsertTurnServerLogs(accountInfo[3], accountInfo[0], accountInfo[1], accountInfo[2], start, end, useTime, rcvp, rcvb, sentp, sentb) if err != nil { log.Error(err) } } onlineTimeBucket.Locker.Unlock() } |
如果是穿透的话,因为没有流量,所以每次收到 total_traffic的时候,都要判断是不是所有的channel 都断开了。如果是的话,那么就是连接断开了。这时候就统计时长并且入统计。
使用ssh客户端(如:putty)连接Linux服务器,可能会等待10-30秒才有提示输入密码。严重影响工作效率。登录很慢,登录上去后速度正常,这种情况主要有两种可能的原因:
OpenSSH在用户登录的时候会验证IP,它根据用户的IP使用反向DNS找到主机名,再使用DNS找到IP地址,最后匹配一下登录的IP是否合法。如果客户机的IP没有域名,或者DNS服务器很慢或不通,那么登录就会很花时间。
解决办法:在目标服务器上修改sshd服务器端配置,并重启sshd
用ssh -v user@server 可以看到登录时有如下信息:
注:ssh -vvv user@server 可以看到更细的debug信息
解决办法:
修改sshd服务器端配置
可以使用ssh -o GSSAPIAuthentication=no user@server登录
GSSAPI ( Generic Security Services Application Programming Interface) 是一套类似Kerberos 5的通用网络安全系统接口。该接口是对各种不同的客户端服务器安全机制的封装,以消除安全接口的不同,降低编程难度。但该接口在目标机器无域名解析时会有问题
使用strace查看后发现,ssh在验证完key之后,进行authentication gssapi-with-mic,此时先去连接DNS服务器,在这之后会进行其他操作
OpenSSH_6.6.1, OpenSSL 1.0.1e-fips 11 Feb 2013
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 56: Applying options for *
debug1: Connecting to kr.worthcloud.cn [107.150.126.57] port 36000.
debug1: Connection established.
debug1: identity file /home/fredzeng/.ssh/id_rsa type -1
debug1: identity file /home/fredzeng/.ssh/id_rsa-cert type -1
debug1: identity file /home/fredzeng/.ssh/id_dsa type -1
debug1: identity file /home/fredzeng/.ssh/id_dsa-cert type -1
debug1: identity file /home/fredzeng/.ssh/id_ecdsa type -1
debug1: identity file /home/fredzeng/.ssh/id_ecdsa-cert type -1
debug1: identity file /home/fredzeng/.ssh/id_ed25519 type -1
debug1: identity file /home/fredzeng/.ssh/id_ed25519-cert type -1
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_6.6.1
debug1: Remote protocol version 2.0, remote software version OpenSSH_7.4
debug1: match: OpenSSH_7.4 pat OpenSSH* compat 0x04000000
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr hmac-sha1-etm@openssh.com none
debug1: kex: client->server aes128-ctr hmac-sha1-etm@openssh.com none
debug1: kex: curve25519-sha256@libssh.org need=20 dh_need=20
debug1: kex: curve25519-sha256@libssh.org need=20 dh_need=20
debug1: sending SSH2_MSG_KEX_ECDH_INIT
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ECDSA 66:cc:4d:4a:e0:88:3d:77:5f:a4:fd:5f:ff:05:5c:94
debug1: Host ‘[kr.worthcloud.cn]:36000’ is known and matches the ECDSA host key.
debug1: Found key in /home/fredzeng/.ssh/known_hosts:3
debug1: ssh_ecdsa_verify: signature correct
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: Roaming not allowed by server
debug1: SSH2_MSG_SERVICE_REQUEST sent
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Trying private key: /home/fredzeng/.ssh/id_rsa
debug1: Trying private key: /home/fredzeng/.ssh/id_dsa
debug1: Trying private key: /home/fredzeng/.ssh/id_ecdsa
debug1: Trying private key: /home/fredzeng/.ssh/id_ed25519
debug1: Next authentication method: password
6月18日,一位网名为“蓝色海岸”的业内人士,先后在c114论坛发文《不懂国内为什么那么看好5G?》,阐述了他不看好5G的8个理由,引发众多移动通信业界人士回帖反驳。6月22日,“蓝色海岸”再发文《不懂国内为什么那么看好5G之二—绝地反击》,阐述了他不看好5G的另外6个理由,再次引发众多移动通信业界人士回帖反驳。
这场辩论很精彩,很多地方都说得有理有据,有些观点/说法也具有一定的思辨性,下文就摘录其中的精彩内容,供大家参考。
网名为“蓝色海岸”的业内人士:
1、5G网速达10G, 不可能,即使能达到,也毫无意义,因为没有需要,现在光宽带的网速,EPON是1000兆,GPON是2500兆,可实际开通的一般是20兆,有很少部分用户开通到了100兆,为什么不开通2500兆,因为没必要,没意义,现在高清视频的带宽一般在2至3兆,就算下载需要更快一点,但也有限,因为人眼和人脑是有带宽的,太高了人的眼睛和大脑接受不了,就没意义了。既然光宽带都不需要那么高的网速,手机会需要吗?手机的屏幕就那么小,4K清晰度有意义吗?超过人眼能够识别的极限,标清和4K不是一样吗?
2、千兆无线路由器早已有之,但是市场反映平淡,很显然,只增加最后一公里的带宽,骨干网带宽不增加,也就没有意义了,这就好比只加宽家门口的马路,不加宽主干街道、国道和省道的公路,速度能提高吗?运营商和设备商就是这样愚弄用户的,说是增加到百兆带宽了,可是实际上只是增加了一点点。
3、服务器和手机的处理能力有限,宽带网一端连接的是服务器,也就是电脑吧,一端连接的是手机,电脑的PCIE总线速度已达6G以上,但是硬盘速度也就几百兆,而且这样一台服务器要连接很多用户,就算把电脑的处理能力全部用于一个用户,极限也就几百兆,而手机的处理能力就更弱了,这时候电脑的处理能力变成瓶颈了,网络两端的速度上不去,只是一味的增加中间部分,会有效果吗?
4、现在5G的宣传都说下载一部高清视频只要几秒云云,实际上只要下载视频的速度大于播放的速度,人就感觉不到网速的快慢,手机是一边放视频,一边下载的,你让手机下载那么快干什么呢?让手机几秒钟下载完,就可以歇着了,你心疼它累吗?
5、九几年的时候,上网很卡,后来带宽增加了,上网不卡了,看视频还是很卡,用的很不爽,运营商就告诉用户,是带宽不足,你要把56K猫换成ADSL,有了ADSL,又说要换光宽带,有了光宽带,又说要换4G,这似乎已经形成习惯和趋势了,实际上,上网和看视频,ADSL足够了。为什么ADSL不行,那是骨干网带宽不足,为什么骨干网带宽不足,是因为运营商之间互掐,以及骨干带宽资费不肯下调。接入网的带宽早已远超需要,GPON,EPON,千兆以太网,千兆无线路由器,10G以太网,这些技术早就成熟了,可是下载高清视频的速度也没有说就几秒啊,5G同样是在接入网段的技术,凭什么这么一个接入网段的技术,就能大幅度的提升网速呢?现在有个口号,叫4G改变生活,5G改变社会,的确,3G的带宽只有2兆多一点,而且是很多人分着用,是少了一点儿,但是4G看来是足够了,在没有Iphone的时候,3G搞了10年也发展不起来,那是因为没有需要,同样的5G想要发展起来,需求在哪里呢?
6、现在有了高清视频,有了1080P,甚至有了4K电视,网络快一点,还是有那么一点点道理,离开了大屏电视,就手机那么一个小小的屏幕,它的显示面积就那么一点点,它要那么大带宽干什么呢?再说了,有多少人在室外一边走路一边抱个手机看电影?恐怕没有吧,一般都是看看微信呀,上个网什么的,就这么点需要,难道上百兆的4G还满足不了?恐怕几兆就足够了吧。
7、我们的网速到底有多快,我可以告诉,平均每个用户就100K多一点,但是这是平均值,实际上由于统计复用的原因,并不是所有人都在不停的占用带宽,而是轮流使用的,所以大家使用的实际带宽还是挺大的,几兆应该是有的,如果用户和服务器同处网络边缘,也就是通过CDN加速,再宽一些也是可以达到的。这就好比马路就那么宽,但并不是所有人都站在马路上一样。你要更宽,那就变成经济问题了, 并不是技术实现的问题,试想如果带宽像空气和阳光一样随处可得,尽管没人离得开空气,可是又有谁能把空气变成钱呢?这种事情运营商会干吗?这就是说有价值并不等于有价格,没有价格也就是没有经济趋动力,没有经济趋动力谁肯干呢?骨干网平均带宽100多K,接入网要上一万兆,这意义又在哪里呢?
8、 这些都撤远了,就说通信行业,九十年代炒的火热的ISDN,那时候互联网还不普及,ISDN可以通两部电话,还可以通可视电话,可是可视电话因为视频压缩算法不过关,带宽低图像质量差,画面小,无法激起消费者的购买欲望,很多公司投入几亿几十亿美金,都丢到水里了。阚凯力阚大炮当时看准了ISDN没有未来,ISDN技术可以在一根电话线上装两部电话,可是他认为只要再接一条电话线就可以办到了,那样显然更便宜,何必为这个要搞一代新技术,更何况有多少家庭会需要两部电话啊?接下来是ATM,ATM把主要吸引点放在视频业务上,结果同样因为视频技术不过关,ATM无用武之地,胎死腹中。
楼主并不是说5G永远没价值,至少是在目前能看得见的未来,价值还体现不出来,这就很危险了,你说现在看不到也想不到的应用,就炒得火热,到处宣传到处试点,搞了几个试点是花了好几亿,这是在糊弄老百姓啊,还是在套取国家资金啊?阚大炮当年认为3G是皇帝的新装,结果3G的投资的确打了水漂,有人辩解说3G积累的技术,在5G时代用得上了,还要领先国际水平,可是阚大炮的眼光是很毒的,被他识破的东西要想翻身如同登天,3G时代积累的那些技术能否用在5G上,看来很大的可能性还得落空。
9、 5G现在的确吹的有点邪乎了,刚开始说要搞1G带宽,后来4G+出来了,能上300多兆,这样看来1G带宽好像也不是什么太有吸引力的概念了,然后就搞出个10G出来,这简直就是放卫星了。固网和光宽带现在实用带宽也就几十兆,现在10G的光宽带也已经实用化了,据说到2019 100G的PON标准也将发布,可是用户实际开通的带宽到底有多少呢?这种脱离实际应用,单纯的技术引导能走得远吗? 论坛里有人说5G是低延迟,这恐怕说的是基站到用户之间100多米的延迟吧,这100多米产生的延迟在整个通信链路中微不足道,基站到城域网,再到骨干网,用的就是光纤了,请问这段延迟是怎么解决的?这早就超过5G技术的范围了。决定延迟的根本原因,还是在于城域网和骨干网,这都不是5G技术能解决的问题了,你说5G能解决,那就明确说明这部分是怎么解决,你不要说那些通信专家肯定考虑到了,他们到底是怎么考虑的?
5G号称低延迟,连郎咸平都出来说话了,说5G的速度快于人的神经的反应速度,在胳膊上扎一针,大脑还没感觉,5G网另一端就已经知道了,这种说法的确够让人震惊,可是光通信的速度早就有这么快了,可就是没人那么说,这不是故弄玄虚糊弄无知群众么?5G厂商够厉害,连著名经济学家都搬出来造势了。5G要想实现低于光宽带的延迟,那得费九牛二虎之力,这一点连任正飞自己都承认还解决不了,可是媒体上都吹的跟真的一样了。
10、5G所使用的频段是毫米波,在这个波段,电波基本是直线传播,绕射和透射能力都很差了,另外5G基站的覆盖范围也很小,可能只有几百米吧,发射功率和带宽呈正相关,带宽加大,发射功率急剧增加,而手机的发射功率是有限的,这就决定了5G基站的覆盖范围很小,大概100多米到几百米的样子吧(网上有文章号称 5G基站能覆盖20公里,到了那个距离,带带还剩多少,还有什么使用价值,有良心的工程师自己知道),这其实比WIFI的覆盖范围也多不了多少了。面积与覆盖半径的平方成正比,这就意味着5G基站的数量和密度可能是4G的5到10倍,这正是设备商努力鼓吹5G的原因了,可是那么密集的基站,手机即使很低的移动速度,也会频繁切换,而切换又会产生很多的延迟和中断,这些问题又怎么解决?这么多的技术缺陷,注定5G如同无线输电一样,描绘的很好,却是个迟早都会破的大泡沫。
11、再说物联网,物联网是5G炒作者最重要的支撑基础,什么万物互联,物物互联。通信说白了,最重要的指标无非就是延迟、带宽和丢包率,这三个指标是基本指标,光通信这三个指标都远优于5G,在这方面有天生的优势,可以说已到了理想化的程度,对5G来说,那是一道永远也不可能突破的墙,现在5G到处宣传,给人感觉好像是什么划时代的技术,可以轻松超越光通信。WIFI加光宽带足以实现物联网的需要,没有WIFI的地方还可以用4G,没有5G物联就实现不了啦,不会吧,不要尽搞些新概念吓唬人好不好。网上有人说5G的频谱利用率有多高,就这一点足以说明5G是个好技术,请问5G提升频谱利用率的最终目的不就是在有限的频谱内提升带宽吗?可是如果连提升带宽都变得没有意义了,那提高频谱利用率的价值何在呢?
12、有人说楼主不懂,服务器和电脑不一样,服务器里面的硬盘早就使用光纤连接了,但是光纤连接的仍然是硬盘啊,硬盘的速度是瓶颈,你用什么连接速度也上不去,这就是木桶理论了。实际上,现在使用的服务器大多仍是PC机,只是PC机集群而已,但也有极少量的小型机,硬盘仍是最主要的存贮介质,你说可以搞个缓存,那样存取速度就会提高,但那毕竟是极少量的,缓存的容量跟硬盘怎么比啊,那是成千上万倍的差距啊,没有大规模推广的技术,证明是没有商业价值的。
13、有人又说到AR,VR,反正这些技术还没走进人们的生活,大家但吹无妨,这两种技术可能需要三十多兆的带宽,4K高清需要16兆带宽,也就是这样了,这也不需要10G带宽啊,有人又说了,基站的带宽是大家共享的,你以为光宽带的带宽就不是共享的吗?这种AR,VR要戴个大眼镜捂住双眼,你不怕在外面走路会撞电线杆吗?这AR,VR恐怕还只能在家里用用吧,在家里用当然是WIFI和光宽带更好了,5G信号要穿透家里的墙,那丢包率和延迟还不得蹭蹭的往上窜啊。回到物联网的问题,物联网所连的物,绝大部分应该还是在室内吧,室内当然是光宽带和WIFI的地盘了,5G信号穿墙到室内,那信号还不知道差到哪里去了?
14、通信行业这些年的走向,让人摸不着头脑了,就说SDH,明明在延迟、带宽、丢包率三个指标上都远优于PTN,也远优于IP网,却被说成是淘汰技术,许多地方拆了SDH上PTN,结果E1线路经常帧失步,你说这不是在开历史的倒车么?这说明一些人的确可以颠倒黑白,指鹿为马啊?我们还要被那些所谓的技术专家糊弄到哪里去?这已经到了对那些技术专家万分警惕的时刻了,弄不好就会被他们带进坑里去了。
网名为“winnyterry”的业内人士:
唉,再见文科生另一神论,其实论调和理据和上一篇一样,只是写得长了一点。回复较为费时。
首先,这篇神论第一段的逻辑就有问题:楼主的逻辑是:任何技术的发展,都必须先有大需求,再去发展技术。否则就是冒天下之大不讳。但我回忆了一下中学小学学过的中国五千年,和世界近两百年的发展。中国和世界都是在矛盾和失败中前行。人类的每一个成功的发明,一开始的需求其实都和移动通信技术很相似,需求不明显,但发明出来后,这个需求就极之可能变种成爆发式的增涨。
其次,楼主纠结国内为什么看好5G,我想说,移动通信技术从电报通信开始,一直到现在的4.5G,就不只是国内的事,而是全世界的事。5G技术也不只是国内在准备,全世界都在准备,看不看好另说。但如果全世界都5G,就中国4G,我就一定不看好了。中国从电报通信到现在,一直在全球通信产业中都处于模仿跟进付专利费的地位,这个局面直到3G开始有了松动,4G开始有点点的话语权,再到5G话语权又会再增加一点。这种进步对于中国通信产业的意义并不是4G有300Mb/s,5G有1Gb/s这么简单的对比可以概括的了。
再次,wifi与5G对比的问题。坦白说,wifi通信和移动数据通信其实分属于两种不同的群组技术,wifi是计算机通信群组技术,5G是传统移动数据通信技术。这两种技术从2G时代起就一直在对抗,希望获得移动通信的话语权。但自己从传统移动通信技术不停的更新迭代,wifi的速率和容量优势早已不复存在。再加上现在全球特别是中国的通信资费以火箭速度下降,wifi注定在未来是小众应用,只剩下企业内网和大型mall用于宣传之用。根本不可能再回复在2G、3G时代的火爆。可以预料,在5G时代,wifi衰落的速度会更快。作为我本人,从2008年起就很少用到wifi了,除非我所在的那个地方完全没有3、4G信号。但这基本上在我全国跑的经历看,这不可能出现。
最后,我实在无法理解楼主说的:“请问5G提升频谱利用率的最终目的不就是在有限的频谱内提升带宽吗?可是如果连提升带宽都变得没有意义了,那提高频谱利用率的价值何在呢?”再次强调,频谱利用率的要考虑是主要是如何在有限的无线频谱下,容纳更多的并发数据。这点比速率的提升更重要。如果GSM一个载扇能容纳200个客户在线,但WCDMA一个载扇能容纳400个客户在线并能保持超过2G的速率,FDD一个载扇能容纳800个客户在线并能保持3G的速率……你还会认为频谱提升没有意义吗?!
网名为“jeffyko”的业内人士:
个人角度,看5G这个问题,如下几点:
(1)相比4G,物理层上没有重大突破,速率的增加无非是通过更高阶mimo更大带宽来实现,
(2)时延上的改进一是架构的优化,二是芯片技术的提高
(3)iot/mtc未来可能会有很大应用价值,毕竟与每个人的生活息息相关
(4)如楼主所述,路铺的宽又如何,应用在哪里?
所以,不要把5g吹的太悬,最终它也要走下神坛。如同volte一样
网名为“winnyterry”的业内人士:
唉,又见文科生神论!通篇的着眼点只有:速度。太片面了。每一代移动通信技术的革新,其它有三点是最重要的,按重要程度排序是:频谱利用率,时延,网速。
频谱资源不论什么时代在移动通信领域都是最为稀缺的,如何在有限不可再生的无线频谱下,容纳更多的并发数据,这是每一代移动通信进步最重要的出发点。特别是物联网时代,万物互联,频谱利用率不提高,一切都是空谈。
其次是时延,现在4g时延基本上能在20毫秒内,对于打游戏,是够了,但如果是VR应用和智能导航呢,又太慢了,测试要在8毫秒内,智能导航才不会错过执行指令的最佳时点。而5g据说时延能控制在5毫秒内。
而网速仅仅是每一代移动通信技术中重要性排在第三位的,可以说只是在提高频谱利用率和降低时延时顺便提高一下而已。对于用户而言,网速的感知最为明显,运营商设备商的宣传着墨于此不难理解,而前面的两点对于用户的感知远远没有第三点的网速明显,但切勿因此就认为移动通信技术就只是网速的提高,这样就大错特错了。
网名为“heipang”的业内人士:
有人说楼主是文科生观点,其实很多通信业内从业多年的人也会有类似观点。说几个自己的想法:
1. 视频是推动宽带发展的需求,但真的作用有限,有些厂商在大肆鼓吹视频和IPTV,其实无非是想多卖设备带宽,体验、运维这些问题在IP网络里没有提供有效的方案解决。
2. 有些需求真的是我们普通上班族体验不到的,每天早出晚归,三四十岁的人了,哪有时间玩游戏,VR/AR这些将来一定对网络的质量要求很高,也许要等到它们渗透到每个生活的角落,你才能感受到。
3. 物联网,个人觉得在部分场景里用处比较大,比如工业、农业、娱乐园区里,家里那点东西真的需要都联网么,有那个精力多陪孩子读点书吧。
4. 法律法规的建设如果不完善,大家怎么放心去联网,家里装个IP摄像头被入侵了咋办,放在云上的视频被流出怎么办:)当然这个担心有点多余,我们的发展模式一直都是野蛮生长再逐步约束。
网名为“risse”的业内人士:
不知道楼主为何这么抵触。带宽大延迟低,不好吗?难道想回到56K的时代?一张图片显示出来都要10来秒!
标清、高清、4K的视频真的是有很大的差别,不要看到现在网站上的在线播放视频,那些都是压缩了的,只是分辨率没有变而已,有机会你下载北京烤鸭完整版的4K视频看看,就知道区别了。
看了你所说的那么多,感觉你就像老一辈的那种没技术的技术而已。
时代的进步,离不开网络的发展,2G的时候你用手机玩游戏?3G的时候你用手机看视频?4G的时候这些都有了吧!5G的时候就不是简简单单的这些应用了。
网名为“jiu_mao”的业内人士:
各位,技术发展和业务的发展是相辅相成的,没有业务强有力的驱动,不会这么快产生一代又一代的通信技术的。5G也是如此,相信现在有很多炒作的概念,但我觉得更主要的动力还是来自于整个社会的进步、人们更高的需求。
楼主,从你鼓吹5G不如wifi加光宽带这一点来看,我觉得你可能是资深的工程师,但绝不会是移动通信相关的工程师!
网名为“frewave”的业内人士:
3GPP定义的5G最大速度是20G,这是指整个基站的速率,分配到个人的没那么多,5G的进步是通过新的技术极大提升频谱效率和基站容量,对于现有的技术,运营商为何不敢像固网那样包月?到了5G极快的的速率,低廉甚至包月的流量,极大的扩展了移动互联网的使用范围(包括万物互联),这些比固网更便利,基础设施上去了,应用才能推广,在2G时代,不可能有微信这类的应用。对于VR、AR这些应用,就像3G时代的智能手机,只有硬件条件到了,才会推广应用。4K的VR只是入门,楼主说的十几兆就够了,这是经过200倍的视频压缩比才能到的,在对延迟不敏感的视频场景问题不大,对直播或游戏就有问题了,这也是为何HTC的VR要有线连接。一两年后8K的VR才是基本配置。
楼主可能只是做固网的,对移动通信的理解还是不深!
网名为“lovebugzhang”的业内人士:
我觉得楼主还是有很多地方没理解上一贴那么多人反驳你的地方,特别是对频谱利用率,还有服务器的传输速度的理解有点问题。5G有很多优势,,低延迟只是其中之一,而且你逻辑并不清晰,低延迟是优势,自动驾驶是应用,不可混为一谈.你不可能因为自动驾驶这个应用距目前太遥远,就认为整个5G是忽悠的.
网名为“winddt”的业内人士:
立场影响观点。
在4G时代,就有wifi+光取代LTE的说法,结果大家都清楚了,各自都发展的很好。这个时代是你可以发展的很好,但你的光芒不是一定要让别人暗淡无光。
5G时代,wifi+光本就已经纳入5G系统的一部分了,这个在去年的IEEE802会议上已经确定了,以前还可以说lte和wifi两者互为补充,5G时代移动宽带和无线宽带深度融合,均成为整个5G系统的的重要组成部分。
网名为“cano”的业内人士:
之前在公众号上看过一篇关于5G的批评文章,有理有据,深以为然。这次本来是抱着寻找同道中人的念头入坑,没想到大失所望。
拜读了LZ第一篇文章之后,我就有了一个猜测,也闻到了一股熟悉的味道。在读了第二篇后,我觉得,我的猜测和那股味道终于被证实了。
楼主应该是搞固网接入和光通信的吧,从这两篇中大谈ISDN、ADSL、EPON、GPON、STN、PTN这些就能看出来。另外,楼主应该是北邮某教授的铁粉吧,第一篇中只是闻到的味道,第二篇中直接就点出了,呵呵。不过自从在某教授狂喷3G的文章中发现一个初中生都不会错的大漏洞后,我和某教授的文章基本就拜拜了。
我觉得LZ对于无线通信的基础知识,对于5G的基本目标和场景都缺乏最基本的认识。
有线通信和无线通信最大的不同在于信道。有线通信可以毫不费力的搞到一组正交信道,无线就要头拱地;有线通信发现一根管子不够了,再加一根就是了,无线还是头拱地……
对于5G的三大场景,或许那些回复也没说清楚,还请LZ自己回去看看。另外,请楼主注意,现在4G的基站也是对用户数和并发业务数有限制的,而且没你想象的那么多。
这三家我都有使用
先说 使用感受
这几天有想法 测一下 这三家提供的 mysql 读写性能如何, 于是写了下面的脚本。
先说一下这三家 mysql 的配置:
所以这是一个不严谨的测试,因为这些机器都是早就买好的。所以无法做到测试环境一模一样。
每家各测试多次,结果比较稳定,就选取其中的一次结果:
INSERT ONE 3.25666999817
INSERT MANY 0.217604875565
QUERY 3.51868581772
INSERT ONE 5.17626905441
INSERT MANY 1.33850288391
QUERY 2.40842795372
INSERT ONE 5.36786603928
INSERT MANY 0.239859104156
QUERY 5.58612704277
# -*- coding: utf-8 -*- import os import time import random import base64 import MySQLdb MYSQL_HOST = '127.0.0.1' MYSQL_PORT = 3306 MYSQL_USER = 'root' MYSQL_PASSWORD = 'root' MYSQL_DB = 'bench_test' max_num = 10000 conn = MySQLdb.connect( host=MYSQL_HOST, port=MYSQL_PORT, db=MYSQL_DB, user=MYSQL_USER, passwd=MYSQL_PASSWORD ) # 数据库需要提前建立好,但是表不用 cursor = conn.cursor() sql = """create table if not exists test ( id integer not null primary key, age integer not null, name varchar(255) not null )""" cursor.execute(sql) conn.commit() cursor.close() # 生成测试数据 DATA = [] for i in range(max_num): DATA.append((i+1, i+1, base64.b64encode(os.urandom(64)))) def insert_one_test(): cursor = conn.cursor() cursor.execute("delete from test") start = time.time() for value in DATA: cursor.execute('insert into test (id, age, name) values (%s, %s, %s)', value) conn.commit() cursor.close() print "INSERT ONE", time.time() - start def insert_many_test(): cursor = conn.cursor() cursor.execute("delete from test") start = time.time() start_index = 0 batch_amount = 2000 while start_index < max_num: values = DATA[start_index: start_index+batch_amount] cursor.executemany("insert into test (id, age, name) values (%s, %s, %s)", values) start_index += batch_amount conn.commit() cursor.close() print "INSERT MANY", time.time() - start def query_test(): cursor = conn.cursor() start = time.time() for i in range(10000 * 1): _id = random.randint(1, max_num) cursor.execute("select id, age, name from test where id = %s", (_id,)) result = cursor.fetchone() assert result[1] == _id print "QUERY", time.time() - start if __name__ == '__main__': insert_one_test() insert_many_test() query_test()
https://cn.v2ex.com/t/233000
机遇与挑战并存。用这句话来形容近两年的CDN行业再合适不过:一方面流量持续爆发,前景看好;另一方面竞争加剧,行业一片红海。这样的行业背景下,即将召开的2017年亚太CDN峰会具有特殊的意义。
“GFIC——2017亚太CDN峰会”由DVBCN&AsiaOTT(众视网)主办,将于2017年4月12日至13日在北京凯宾斯基大酒店(亮马桥50号)2楼举行。帝联科技作为CDN行业的领军企业之一,已经连续第五年深度参与亚太CDN峰会,自首届起从未缺席。
本次峰会,帝联科技将作为金牌赞助商,携重量级产品与技术亮相并发表演讲,与众多行业同仁一起,分享其对于行业发展的见解。

历届亚太CDN峰会全球顶级CDN合作伙伴
作为一家创立12年的老牌网络平台服务商,帝联科技成长、蜕变以及云服务平台形成的内在逻辑,本就代表着CDN行业生态化、精细化和智能化的方向,具有行业指导性意义。
帝联科技依靠分布式数据中心(IDC)起步,积累了广泛的客户群体,为开展CDN业务打下坚实基础。随着行业发展,公司业务重心逐步转向CDN行业。2007年,帝联科技推出7*24全国统一400客户服务热线,CDN平台储备带宽超250G,这也标志着帝联的第一次转型完成,CDN业务占据主导。
随后几年,借着互联网行业流量爆发的热潮,帝联科技资源和技术实力高速提升。截止2016年,公司500+CDN节点遍布全国,海外节点64个,带宽储备超过6.5T,形成了覆盖广、稳定强、价格优的高品质互联网资源,综合实力跃居行业前列。
随着流媒体业务剧增以及行业竞争的日趋激烈,传统CDN服务面临着前所未有的挑战。流量爆发之下,CDN平台构建必须进行升级。帝联科技投入了巨额资金,配置了大量优质设备和带宽资源,聘请了以CTO为首的业内知名技术人才,优化技术团队。
经过一年的努力,帝联科技逐步做到了资源部署精细化和网络链路动态选择智能化。其中,DnDns系统更是较大程度地实现了运维自动化,引领了CDN行业的技术趋势。
据帝联科技CTO洪克柱介绍:DnDns系统由帝联科技投入大量研发资源,完全自主开发而成。DnDns系统基础解系包含UDP/TCP,IPV4/6,泛域名,edns0-client-subnet,高性能Zone文件解析等;智能解析则包含精准动态更新的地址库,高效区域(view)拓扑分级策略,灵活简易的区域配置:个位数的配置文件,DNS切量迅速收敛:IP Ratio等。各项技术指标均处于行业前列。
从央视春晚直播到315晚会,再到近期火热的世界杯预选赛,DnDns系统已经在热点网络视频直播中发挥重要作用,大大的缩短了响应时间,为客户带来更流畅更快捷的服务。
十二年来,一步一个脚印的发展使帝联科技形成了稳固的资源、技术以及人才优势,也积累了超3000 家客户,其中包括腾讯、百度、阿里巴巴、360、京东、搜狐、新浪、网易、央视国际、广电集团、苏宁集团、中国移动、中国安全部门等一系列行业代表企业。并以良好的服务态度与技术升级赢得了客户赞许,在腾讯供应商评分中位居第一。
基础扎实是起飞的前提。帝联云存储、帝联弹性计算平台、帝联监控报警、帝联运营一体化系统等产品和系统方案将会为帝联科技向前发展持续提供动力。未来,帝联科技正在逐步成长为一家集数据存储、分发、计算、安全为一身的云服务平台。
关于2017亚太CDN峰会
“GFIC——2017亚太CDN峰会”由DVBCN&AsiaOTT(众视网)主办,是GFIC系列峰会中,围绕CDN如何为“宽带中国战略”做好基础服务,为电子政务,移动直播,在线视频,虚拟现实,智慧城市,人工智能,互联网金融行业等提供加速传输,云计算,云存储,大数据,安全防护,应用推广,流量变现等专业服务为主题的亚太区最大规模年度盛会。
亚太CDN峰会汇聚了全球多个国家,500多家企业,数千人参与。伴随着互联网高速发展的红利,“亚太CDN峰会”专注于聚焦内容分发领域,邀请来自Akamai、Fastly、Level3、Limelight、Telefonica、Orange、TWC、网宿、蓝汛、帝联、UCloud、云帆加速、阿里云、腾讯云、百度云、乐视、爱奇艺、PPTV聚力、高德地图、京东云、东方明珠、芒果TV、华数传媒等行业内的领袖企业,共同探索下一个互联网时代的内容分发新格局。