bit.do是什么/bsd9f是什么意思

其实最近我也在某网站的开发组内讨论应用全站https事宜。&br&其原因非常简单。&br&&br&&b&因为不断接到用户投诉说网站上出现影响浏览体验的大面积广告。&/b&&br&可是网站平常只针对未登录用户在顶栏和底栏打两小条广告。而且这种露骨的广告。。。。。。&br&&br&一看就是当地运营商干的。&br&强行劫持用户浏览,往里面插入自己的广告。&br&运营商都是大爷,我们不敢惹,以往都是默默忍着,安抚用户说这不是我们投放的广告。引导用户清缓存刷新之类的。&br&&br&应该说积累了这么多年,运营商也不断变本加厉,从原来的右下角小广告到了覆盖页面的全屏广告。大家终于在2015年开始爆发了。我上次在群里聊起这个问题,大家一看换https的价格(证书、加密时的多余计算能力)居然已经低到完全可以接受了,而且还能获得一些多余的好处,比如增强穿墙性能什么的。&br&&br&于是大家一合计,开干吧。然后就默默的开始做整站迁移至https的工作。&br&&br&应该说,使用https成本的下降,尤其是计算成本的下降是2015年https爆发的主要原因,当然这和几个CA纷纷推出超低价证书甚至是免费证书也是分不开的。&br&不过最终导致大家下定决心更换https的导火索就是运营商劫持流量投放广告了。&br&&br&而且随着计算价格的不断下降,https因为加密产生的性能消耗正在被人们逐渐忽略。相反https带来的安全性正在被人们逐渐重视。&br&在未来的几年内,会有越来越多的网站启用https。
其实最近我也在某网站的开发组内讨论应用全站https事宜。其原因非常简单。因为不断接到用户投诉说网站上出现影响浏览体验的大面积广告。可是网站平常只针对未登录用户在顶栏和底栏打两小条广告。而且这种露骨的广告。。。。。。一看就是当地运营商干的。强…
&a href=&///?target=https%3A///shenfeng/nio-httpserver& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&shenfeng/nio-httpserver · GitHub&i class=&icon-external&&&/i&&/a&&br&这可能是题主所说的一个&玩具&工程 看完这个 与传统的BIO+多线程实现的Server对比下
看看因为切换成了非阻塞模型 解决了啥问题 带来了啥问题 然后看下面这两个文章&br&&br&&a href=&///?target=http%3A///developerworks/cn/linux/l-cn-zerocopy1/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Linux 中的零拷贝技术,第 1 部分&i class=&icon-external&&&/i&&/a&&br&&a href=&///?target=http%3A///developerworks/cn/linux/l-cn-zerocopy2/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Linux 中的零拷贝技术,第 2 部分&i class=&icon-external&&&/i&&/a&&br&&br&看完这两个文章了解目的 再从API上感受一下 比如传统的API跟文章中提到的哪个场景有关 用了新的API后 又对应文章中的哪个场景&br&&br&如果还是不懂 我会补充答案&br&PS.编程思想的类库介绍没有核心技术全 不过核心技术也只是讲解了下API&br&这里推荐两本书 一本了解Java的API 一本了解Unix的API&br&&a href=&///?target=http%3A///.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&《Java网络编程(第四版)》([美]Elliotte Rusty Harold(哈诺德,R.E.))【摘要 书评 试读】&i class=&icon-external&&&/i&&/a&&br&&a href=&///?target=http%3A///.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&《UNIX网络编程(卷1):套接字联网API(第3版)》([美]史蒂文斯,等)【摘要 书评 试读】&i class=&icon-external&&&/i&&/a&
这可能是题主所说的一个"玩具"工程 看完这个 与传统的BIO+多线程实现的Server对比下 看看因为切换成了非阻塞模型 解决了啥问题 带来了啥问题 然后看下面这两个文章
请搜索:self pipe trick。&br&reactor展开了写就是个等待和分发事件的过程:&br&&div class=&highlight&&&pre&&code class=&language-text&&events = selector.wait(milliseconds)
for fd, event in events:
if event & EVT_READ:
handle_read(fd)
if event & EVT_WRITE:
handle_write(fd)
&/code&&/pre&&/div&&br&问题出在wait上,没新消息它将一直等到milliseconds指定的时间为准,而此时ui上用户说了句话,点击“发送”,ui线程把待发送的内容推到了网络线程的消息队列里,而网络线程还在wait呢,没网络事件的话,只有等待这轮wait结束网络线程才有空到队列里监测并处理刚才ui线程投递过来的待发送消息。&br&&br&select等待时间过长将会让消息不能即时被处理,而过短又会占用过多cpu费电,因此在想能不能平时wait长一点,而当我ui线程刚点击了发送按钮就立即把网络线程从select的wait中唤醒让网络线程可以即时的查看自己的消息队列就方便了。&br&&br&于是大家把管道的读取端fd放入selector,那么在wait的时候这个读取端管道fd也会一起参与wait,那么ui线程往队列里塞完任务后,马上往管道的写端写入一个字节,就可以把网络线程唤醒了。&br&&br&这个方法是用来解决多个reactor之间互相唤醒的问题的,利用该技巧可以让网络线程即时处理网络事件的同时也能即时处理来自非网络(比如内部消息队列)的其它消息。&br&&br&就是所谓的self pipe trick,说白了也很简单,windows下select只能针对socket套接字,不能针对管道,一般用构造两个互相链接于localhost的socket来模拟之。不过win下select最多支持同时wait 64个套接字,你摸拟的pipe占掉一个,就只剩下63个可用了。&br&&br&所以java的nio里selector在windows下最多支持62个套接字就是被self pipe trick占掉了两个,一个用于其它线程调用notify唤醒,另一个留作jre内部保留,就是这个原因。&br&&br&说白了这其实就是个年代久远的系统层api设计考虑不周全,要应用层来给它打补丁的典型例子。&br&&br&倘若系统层直接支持这样的唤醒,就不用应用层构造什么管道了。&br&&br&--
请搜索:self pipe trick。reactor展开了写就是个等待和分发事件的过程:events = selector.wait(milliseconds)
for fd, event in events:
if event & EVT_READ:
handle_read(fd)
if event & EVT_WRITE:
handle_write(fd)问题出在wait上,没新消息它将…
&blockquote&那么问题来了:既然 select 都返回可读了,那就表示一定能读了,阻塞函数read也就能读取了也就不会阻塞了&br&&/blockquote&&br&题主队 I/O 多路复用通常搭配多阻塞 I/O 的困惑,主要来这个认知吧,可是实际上,&b&这个结论是不正确的&/b&。&br&&br&select 返回可读,和 read 去读,这是两个独立的系统调用,两个操作之间是有窗口的,也就是说 select 返回可读,紧接着去 read,不能保证一定可读。&br&&br&惊群现象,就是一个典型场景,多个进程或者线程通过 select 或者 epoll 监听一个 listen socket,当有一个新连接完成三次握手之后,所有进程都会通过 select 或者 epoll 被唤醒,但是最终只有一个进程或者线程 accept 到这个新连接,若是采用了阻塞 I/O,没有accept 到连接的进程或者线程就 block 住了。&br&&br&硬是要将 I/O 复用和阻塞 I/O 配合起来用的,在有些场景下,用一些奇技淫巧也是可行的,不过复杂度更高,效率也低下, 这块 &a data-hash=&48d0b4dd4c39eeadb62addd& href=&///people/48d0b4dd4c39eeadb62addd& class=&member_mention& data-tip=&p$b$48d0b4dd4c39eeadb62addd&&@李行&/a& 已经分析的很到位了~
那么问题来了:既然 select 都返回可读了,那就表示一定能读了,阻塞函数read也就能读取了也就不会阻塞了题主队 I/O 多路复用通常搭配多阻塞 I/O 的困惑,主要来这个认知吧,可是实际上,这个结论是不正确的。select 返回可读,和 read 去读,这是两个独立…
在参考顶楼的回答和评论后,正确获取到了弹幕,来回报下社会,代码已经放在Github上了! &a href=&///?target=https%3A///fishioon/douyu/blob/master/danmu.cc& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&douyu/danmu.cc at master · fishioon/douyu · GitHub&i class=&icon-external&&&/i&&/a&&br&代码是C写的,本来用的python,感觉C更好用(在处理数据的时候)。&br&&br&比较喜欢看yyf的dota2直播,但是最近yyf经常吹B,说有网友弹幕问“枫哥枫哥,你的XX怎么这么厉害啊”,水友们纷纷表示不信,所以就想着把弹幕爬下来,同时还有那些说赢了直播吃翔的,我通通都要记录下来!!!&br&&br&回答正题,那我们该如何弄清楚这个协议呢?&br&弹幕属于实时消息,第一反应应该用websocket实现,打开chrome,F12,websocket中竟然找不到!那估计是通过Flash实现了。前端不熟,找了半天也没找到JS实现代码,只好祭出wireshark来分析了。&br&看了顶楼的提示,在wireshark中查看端口为8601的数据包,如下图所示。&br&&img src=&/bc380df68d54c973a6e34f_b.png& data-rawwidth=&643& data-rawheight=&122& class=&origin_image zh-lightbox-thumb& width=&643& data-original=&/bc380df68d54c973a6e34f_r.png&&&br&前三个数据包就是TCP的三次握手啦,复习下;接着我们看第四个数据包,如下图所示&br&&img src=&/8b58accddb_b.png& data-rawwidth=&595& data-rawheight=&231& class=&origin_image zh-lightbox-thumb& width=&595& data-original=&/8b58accddb_r.png&&一般来说通信协议设计“内容长度”+“内容”,我们来看tcp数据包内容,前四个字节为0x59 = 5*16+9 = 89,再看整个数据包长度为93,正好符合长度+内容,差不多我们可以确定通信协议如下:&br&struct {&br& //数据包长度&br& //经抓包发现该字段一直与len字段一致&br& //不知道啥意思,发现请求都是0x2b1, 返回都是0x2b2&br&char content[0]; //消息具体内容&br&}&br&从图中的内容中可以看到:&br&1. 登录弹幕服务器: &type@=loginreq/username@%s=/password@=%s/roomid@=%d/ct@=2/&,输入自己的账号密码(经测试发现,账号密码随便填都能成功),要看的房间id,如yyf的房间id为52428&br&通过socket发送上面的内容后,你回收到这样的一条数据,格式与发送格式一样:&br&“type@=loginres/userid@=0/roomgroup@=0/pg@=0/sessionid@=0/username@=/nickname@=/live_stat@=0/is_illegal@=0/npv@=0/best_dlev@=0/cur_lev@=0/”,没发现有啥有用的数据。&br&2. 收到上面的消息后,这时候要加入一个组,格式如下:&br&&type@=joingroup/rid@=%d/gid@=%d/&,rid就是房间id,要注意的问题来了:&br&gid应该是group id,登录不同房间该id都不一样,每次我都是抓包来查看该id是多少,有知情人告诉我吗?(一楼评论中也提到这个问题)&br&发送上面的消息后,我们就可以安心的接收数据了,然后从数据中提取我们想要的就可以了,其中很多数据都不懂啥意思。&br&最后我们看下yyf房间的弹幕哈!(节奏带的飞起)&br&&img src=&/da660f6d14a49d226909d_b.png& data-rawwidth=&616& data-rawheight=&532& class=&origin_image zh-lightbox-thumb& width=&616& data-original=&/da660f6d14a49d226909d_r.png&&
在参考顶楼的回答和评论后,正确获取到了弹幕,来回报下社会,代码已经放在Github上了! 代码是C写的,本来用的python,感觉C更好用(在处理数据的时候)。比较喜欢看yyf的dota2直播,但是最近yyf经常…
&b&抓到知乎耗流量的证据了,知乎后台会上传不知道什么鬼,非常夸张,每次都要5.3M,而且间隔不定。不废话,上图。&/b&&br&&br&&img data-rawwidth=&1242& data-rawheight=&2208& src=&/51e4fc549a451f6fd454f1e4adcb9e6a_b.jpeg& class=&origin_image zh-lightbox-thumb& width=&1242& data-original=&/51e4fc549a451f6fd454f1e4adcb9e6a_r.jpeg&&&br&首先,我们使用surge进行抓包,现在已经清零,注意时间,22分,此时开始正常使用知乎,计时4min(因为听其他回答者说是2min为一个周期)&br&&img data-rawwidth=&1242& data-rawheight=&2208& src=&/6aca017abc7dca3ba7f271_b.jpeg& class=&origin_image zh-lightbox-thumb& width=&1242& data-original=&/6aca017abc7dca3ba7f271_r.jpeg&&&br&这是26min时的截图,哇塞!4分钟已经用了19M!好,那么我们来看看主要是什么东西搞得鬼。&br&&img data-rawwidth=&1242& data-rawheight=&2208& src=&/5aaefc8534_b.jpeg& class=&origin_image zh-lightbox-thumb& width=&1242& data-original=&/5aaefc8534_r.jpeg&&&img data-rawwidth=&1242& data-rawheight=&2208& src=&/3bd13cae3bf7ed5a094634_b.jpeg& class=&origin_image zh-lightbox-thumb& width=&1242& data-original=&/3bd13cae3bf7ed5a094634_r.jpeg&&&img data-rawwidth=&1242& data-rawheight=&2208& src=&/8a9e1bc24be780d5dc30ea641b7794bd_b.jpeg& class=&origin_image zh-lightbox-thumb& width=&1242& data-original=&/8a9e1bc24be780d5dc30ea641b7794bd_r.jpeg&&&br&大家注意看,分别在24min20s,以及24min21s(你妹的,就过了一秒),以及26min21s的时候想zhihu-analytics上传了5.3M的文件。这都是什么鬼?!!知乎是不是应该站出来给个说法??后台偷偷摸摸的上传什么数据?&br&&b&最后说明一下,我于52min写完答案,半个小时已经用了143M流量。。。&/b&&br&&b&还好我这次连的是wifi&/b&&br&&br&&br&&br&&br&&br&——分割线——以前的答案——&br&对对对!!亲测,新版消耗流量超快!!今天联通发短信说我4个g的流量用光的时候吓死我了!!赶紧重置了iphone流量记录,想查查谁是凶手,果不其然,知乎真是联通的好朋友啊!!不废话,上图&br&&img data-rawwidth=&1242& data-rawheight=&2208& src=&/5bf0cf7fbfffbfb15be2beecf2b4bf0c_b.jpeg& class=&origin_image zh-lightbox-thumb& width=&1242& data-original=&/5bf0cf7fbfffbfb15be2beecf2b4bf0c_r.jpeg&&&br&吃饭前重置的,吃饭的时候刷了二十分钟知乎,吃完饭一看。。。。50M就没了。。。&br&&br&&b&他喵的,老子答个题,用了几张就几百k的截图,又用了老子40M流量。。。&/b&&img data-rawwidth=&1242& data-rawheight=&2208& src=&/c5d981ee293fef7cd125bbb4_b.jpeg& class=&origin_image zh-lightbox-thumb& width=&1242& data-original=&/c5d981ee293fef7cd125bbb4_r.jpeg&&&br&&br&发完上面这张图,再一看,已经又20m没了。。。&br&&br&&b&关键是,我使用2g也能上知乎。。。什么意思?&/b&&b&给多大带宽就用多大是吗!!知乎是真正做到了4g比2g耗流量。&/b&&br&&b&看来以后联通得专门为知乎出一个包时长的套餐才行。&/b&
抓到知乎耗流量的证据了,知乎后台会上传不知道什么鬼,非常夸张,每次都要5.3M,而且间隔不定。不废话,上图。首先,我们使用surge进行抓包,现在已经清零,注意时间,22分,此时开始正常使用知乎,计时4min(因为听其他回答者说是2min为一个周期)这是26m…
知乎有个风气,一提到家里网络不好,全部都是&b&路由器买买买&/b&,说起哪家设备穿墙厉害简直都不要不要的。每次我遇到这种情况都觉得那几家公司是放了n多水军吧。&b&但是对于室内的无线网络规划,无线接入点位置的选择往往比买个贵的路由器重要得多。&/b&&br&利益相关:博士毕设题目是做多目标室内无线网络规划的&br&&b&(另,图片是我刚刚用测试平台比利时根特大学(UGENT)WiCa团队的WHIPP画的,模拟所用Path loss model基于WHIPP算法中的SIDP模型。禁止引用!!!!)&/b&&br&我们假设家大小为15米*34.5米,室内地图如下图(我随手3分钟画的,咳咳不准嫌弃不真实):&br&&img src=&/be6ec830abc9_b.jpg& data-rawwidth=&1536& data-rawheight=&705& class=&origin_image zh-lightbox-thumb& width=&1536& data-original=&/be6ec830abc9_r.jpg&&&br&灰色线代表混凝土墙,蓝色线是窗子,黄色线为门,紫色的点点就是接入点(无线路由器),紫色点里面的数字代表的是接入点的EIRP值。经过模拟计算后大块的颜色占据的位置代表的是覆盖区域,不同颜色分别代表不同的传输速率(带宽)如下图:&br&&img src=&/fa439d0dfec61_b.jpg& data-rawwidth=&168& data-rawheight=&220& class=&content_image& width=&168&&如果把接入点放置在一个房间的阳台上,就可以发现除了离得最近的房间外其他房间的无线网络质量都比较堪忧。如果你是住在左上角的小伙伴估计就会很恼火了。然后就发了下面这个帖子:&a href=&/question/& class=&internal&&家里可以装两个路由器吗!!? - 计算机网络&/a&。&br&&b&于是知乎就有一大票的人会告诉你应该换个啥路由器bla bla bla。(详情见&/b&上面问题的答案们,我没截图,主要是因为他们字太大,我怕。)那是一片叫买(卖)声此起彼伏。各位知乎的大爷都是买买买俱乐部的吧!!!!!!小女子觉得有这钱买肉吃多好啊!!!!&br&虽然对方就是抱着钱求买,但连人家家里地图没看,家里用啥墙都不知道就推荐那是相当不负责任+不厚道的。虽然这种话我每次说都没人理,哼。都欺负我无图无真相不是!这回就关门放图(gou)!&br&假设楼主买了个新路由器,穿墙可厉害了,EIRP值哄的一下变为了20dBm了(以前为16dBm),现在看看情况有多大改变:&br&&img src=&/7afcbf64d9be0fabae61c48_b.jpg& data-rawwidth=&1504& data-rawheight=&675& class=&origin_image zh-lightbox-thumb& width=&1504& data-original=&/7afcbf64d9be0fabae61c48_r.jpg&&&br&嗯,要说完全没变是不客观的,但是要说改变很大也是不客观的。只能说,如果你就换个路由器,位置天线方向啥都不变,对整体室内环境的无线网络覆盖情况是很难有大的改观的。&br&&br&要想有一个大的变化,实际上,你在原有网络布置的基础上买一根网线,然后把以前的路由器(EIRP=16dBm那个)位置挪到室内就好。我就随便扔到了室内中间,其他都没变。连优化都懒得跑,同样的模拟后如下图:&br&&img src=&/9fd55de6b9d147b467534bce2264108c_b.jpg& data-rawwidth=&1480& data-rawheight=&689& class=&origin_image zh-lightbox-thumb& width=&1480& data-original=&/9fd55de6b9d147b467534bce2264108c_r.jpg&&&br&这样是不是看上去就好很多了啊,成本也就是一根网线的钱。大部分地方也都可以用,多舒爽,多省心,多节约!剩下的钱钱又可以买肉肉吃了!&br&&b&如果你非得买两个,记得设置好信道。要不然&/b&&b&产生干扰会使得无线网络质量下降,甚至还不如就用一个呢。&/b&&br&&br&实际上关于现在人们的室内无线网络规划的槽点多得像筛子。&br&如果看得人多,我写完毕业论文再来接着回答吧。
知乎有个风气,一提到家里网络不好,全部都是路由器买买买,说起哪家设备穿墙厉害简直都不要不要的。每次我遇到这种情况都觉得那几家公司是放了n多水军吧。但是对于室内的无线网络规划,无线接入点位置的选择往往比买个贵的路由器重要得多。利益相关:博士…
以前整理过一个《从零开始学编程系列》&a class=& wrap external& href=&///?target=https%3A///justjavac/Programming-Alpha-To-Omega& target=&_blank& rel=&nofollow noreferrer&&justjavac/Programming-Alpha-To-Omega · GitHub&i class=&icon-external&&&/i&&/a&&br&里面收录了从零开始写编译器、记事本、服务器、操作系统、虚拟机、GC、数据库、……&br&&blockquote&「从零开始」系列
&ul&&li&&p&&a href=&/mosky/& class=&internal&&从零开始写个编译器吧系列&/a&
(知乎专栏)&/p&&/li&&li&&p&&a href=&///?target=http%3A///13810/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&从零开始写一个简单的操作系统&i class=&icon-external&&&/i&&/a&
(伯乐在线)&/p&&/li&&li&&p&&a href=&///?target=http%3A//.cn/minibook/770& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&从零开始写 JavaScript 框架&i class=&icon-external&&&/i&&/a&
(图灵社区)&/p&&/li&&li&&p&&a href=&///?target=http%3A///tech/web/.asp& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&从零开始写 jQuery 框架&i class=&icon-external&&&/i&&/a&
(蓝色理想 )&/p&&/li&&li&&p&&a href=&///?target=http%3A//blog.fens.me/series-nodejs/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&从零开始 nodejs 系列文章&i class=&icon-external&&&/i&&/a&
(粉丝日志)&/p&&/li&&li&&p&&a href=&///?target=https%3A///zh-cn/blogs//1/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&从零开始编写网络游戏&i class=&icon-external&&&/i&&/a& ( 英特尔(R) 开发人员专区)&/p&&/li&&li&&p&&a href=&///?target=http%3A///EmptyFS/p/3621484.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&从零开始编写自己的 C# 框架&i class=&icon-external&&&/i&&/a& (博客园)&/p&&/li&&li&&p&&a href=&/question/& class=&internal&&如何从零开始写一个 Chrome 扩展?&/a& (知乎)&/p&&/li&&li&&p&&a href=&///?target=http%3A//jayli.github.io/blog/data//writejslib.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&从零开始写框架&i class=&icon-external&&&/i&&/a& (@jayli)&/p&&/li&&/ul&
「自己动手」系列
&ul&&li&&p&&a href=&///?target=http%3A///python//one-day-write-language-in-python.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&一天时间用 Python 写门语言&i class=&icon-external&&&/i&&/a& (justjavac博客)&/p&&/li&&li&&p&&a href=&///?target=http%3A///php/405.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&利用 Composer 一步一步构建自己的 PHP 框架&i class=&icon-external&&&/i&&/a& (岁寒博客 by JohnLui)&/p&&/li&&li&&p&&a href=&///?target=http%3A///john-d/archive//1617710.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&自己动手写虚拟机&i class=&icon-external&&&/i&&/a& (博客园)&/p&&/li&&li&&p&&a href=&///?target=http%3A//blog.csdn.net/heiyeshuwu/article/details/2576915& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&自己动手写 HTTP Server&i class=&icon-external&&&/i&&/a& #C (CSDN)&/p&&/li&&li&&p&&a href=&///?target=http%3A///gc//babys-first-garbage-collector.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&自己动手写 GC&i class=&icon-external&&&/i&&/a& (Java译站)&/p&&/li&&li&&p&&a href=&///?target=http%3A///flclain/archive//2941397.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&自己动手写一个推荐系统&i class=&icon-external&&&/i&&/a& #Python (博客园)&/p&&/li&&li&&p&&a href=&///?target=http%3A///BlueSky2012/articles/huffman_zip.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&自己动手写压缩软件&i class=&icon-external&&&/i&&/a& #C++ (博客园)&/p&&/li&&li&&p&&a href=&///?target=http%3A///Ninputer/archive//2073908.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&自己动手开发编译器&i class=&icon-external&&&/i&&/a& (博客园)&/p&&/li&&li&&p&&a href=&///?target=http%3A//toigel./348& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&自己动手写俄罗斯方块&i class=&icon-external&&&/i&&/a& #C (51CTO)&/p&&/li&&li&&p&&a href=&///?target=http%3A///blog/lumia-editor-diy-yourself-editor/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&自己动手写编辑器&i class=&icon-external&&&/i&&/a& #nodejs (@phodal)&/p&&/li&&li&&p&&a href=&///?target=http%3A////simple-git-http-server/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&自己动手写 Git HTTP Server&i class=&icon-external&&&/i&&/a& #go (io-meter)&/p&&/li&&li&&p&&a href=&///?target=http%3A///use-symfony2-component-to-create-your-own-php-framework-index.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&使用 Symfony2 的组件创建自己的 PHP 框架&i class=&icon-external&&&/i&&/a& (@ruchengtang)&/p&&/li&&li&&p&&a href=&///?target=http%3A///blog/2014/07/database_implementation.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&数据库的最简单实现&i class=&icon-external&&&/i&&/a& (阮一峰)&/p&&/li&&li&&p&&a href=&///?target=http%3A///77305/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&动手写一个C语言编译器&i class=&icon-external&&&/i&&/a& (伯乐在线)&/p&&/li&&li&&p&&a href=&///?target=http%3A//blog.csdn.net/littlehedgehog/article/details/2928391& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&自己动手写 Basic 解释器&i class=&icon-external&&&/i&&/a& (CSDN)&/p&&/li&&/ul&&/blockquote&
以前整理过一个《从零开始学编程系列》里面收录了从零开始写编译器、记事本、服务器、操作系统、虚拟机、GC、数据库、……「从零开始」系列
(知乎专栏)
大神前辈的回复非常高大全,赞个。&br&&br&不过对于初入游戏行业,特别是进入屌丝创业公司开发页游&手游来说,过于复杂了。&br&&br&一般来说,首先根据游戏类型区分使用短连接还是长连接,简单地来说就是是否一个玩家的行为会实时影响到其他玩家,如果需要,那么则使用长连接。&br&&br&接下来,按照是否分服,架构上又会有些不同:&br&一般使用短连接的都是不需要分服的,因为这类游戏一般都是弱联网类型,玩家交互均为异步(即你的屏幕上看到的其他的玩家的数据如主城、阵容等均为“离线”数据,而不是实时的数据),再加上支持HTTP协议的WEB容器均提供了很成熟的cluster方案(如nginx+tomcat),因此可以比较轻松的实现大量玩家同时在线。接下来如果是cluster,那么各节点之间需要共享数据,考虑到性能和响应性的话关系型DB肯定是最次的选择,因此一般选择为可以跨进程访问的CACHE,如memcached、redis、芒果DB等。&br&&br&长连接不分服的话也是类似短连接一样多个cluster节点连接同样的CACHE数据源的情况,只是跨节点进行通信比较麻烦一点(如用户A连接到节点1,用户B连接到节点2,用户A向节点1发起TCP请求处理业务需要再通知到节点2的用户B)。一般来说有2种解决方案,1是建立场景服务器,即专门用一个socket server来保持所有玩家的连接,然后它只处理数据推送,不做业务,可以达到10-20W承载。2是采用发布订阅方式实现节点间的实时通信。对了,还有前端类似nginx一样需要有一个gateway server,负责告诉客户端你应该连接到后端的哪一个cluster节点,最简单的需要实现一致性HASH以便路由。有人可能要问为啥不用haproxy这样的进行负载均衡,因为类似nginx、haproxy这样的实现反向代理的话均需要占用服务器本机的端口,短连接无所谓,长连接的话,端口长时间占用,很快会达到6W的理论上限,因此一般都是采用直连方式。&br&&br&如果不需要分服,那么非常简单了,不论长短连接,基本上就是io线程接受请求--&根据协议拆包--&业务线程处理业务--&根据协议封包--&io线程发送响应包。99%的数据需要放在进程内的CACHE中处理维护,最后异步写入关系型DB。你问如果DOWN机导致CACHE和关系型DB数据不一致的问题?查日志尽量恢复,恢复不了的运营发补偿。而且就算你再怎么殚尽竭虑也不能阻止蓝翔挖你机房光纤是不?如果运维接受,那么可以将你的服务器进行垂直拆分成多个进程如战斗、日志、登录、交易等等。&br&&br&最后再次免责声明,以上方案仅仅适用于“进入屌丝创业公司开发页游&手游”。&br&语言选择java的话,看看mina、netty即可,选择c++之类的,去看云风大神的blog
大神前辈的回复非常高大全,赞个。不过对于初入游戏行业,特别是进入屌丝创业公司开发页游&手游来说,过于复杂了。一般来说,首先根据游戏类型区分使用短连接还是长连接,简单地来说就是是否一个玩家的行为会实时影响到其他玩家,如果需要,那么则使用长连…
谢邀,手游页游和端游的服务端本质上没区别,区别的是游戏类型。&br&&br&&b&类型1:卡牌、跑酷等弱交互服务端&/b&&br&&br&卡牌跑酷类因为交互弱,玩家和玩家之间不需要实时面对面PK,打一下对方的离线数据,计算下排行榜,买卖下道具即可,所以实现往往使用简单的 HTTP服务器:&br&&img src=&/b6e288b02b8664afd843_b.jpg& data-rawwidth=&438& data-rawheight=&186& class=&origin_image zh-lightbox-thumb& width=&438& data-original=&/b6e288b02b8664afd843_r.jpg&&登录时可以使用非对称加密(RSA, DH),服务器根据客户端uid,当前时间戳还有服务端私钥,计算哈希得到的加密 key 并发送给客户端。之后双方都用 HTTP通信,并用那个key进行RC4加密。客户端收到key和时间戳后保存在内存,用于之后通信,服务端不需要保存 key,因为每次都可以根据客户端传上来的 uid 和 时间戳 以及服务端自己的私钥计算得到。用模仿 TLS的行为,来保证多次 HTTP请求间的客户端身份,并通过时间戳保证同一人两次登录密钥不同。&br&&br&每局开始时,访问一下,请求一下关卡数据,玩完了又提交一下,验算一下是否合法,获得什么奖励,数据库用单台 MySQL或者 MongoDB即可,后端的 Redis做缓存(可选)。如果要实现通知,那么让客户端定时15秒轮询一下服务器,如果有消息就取下来,如果没消息可以逐步放长轮询时间,比如30秒;如果有消息,就缩短轮询时间到10秒,5秒,即便两人聊天,延迟也能自适应。&br&&br&此类服务器用来实现一款三国类策略或者卡牌及酷跑的游戏已经绰绰有余,这类游戏因为逻辑简单,玩家之间交互不强,使用 HTTP来开发的话,开发速度快,调试只需要一个浏览器就可以把逻辑调试清楚了。&br&&br&&b&类型2:第一代游戏服务器 1978&/b&&br&&br&1978年,英国著名的财经学校University of Essex的学生 Roy Trubshaw编写了世界上第一个MUD程序《MUD1》,在University of Essex于1980年接入 ARPANET之后加入了不少外部的玩家,甚至包括国外的玩家。《MUD1》程序的源代码在 ARPANET共享之后出现了众多的改编版本,至此MUD才在全世界广泛流行起来。不断完善的 MUD1的基础上产生了开源的 MudOS(1991),成为众多网游的鼻祖:&br&&img src=&/b647b152f0c29b29e2c9_b.jpg& data-rawwidth=&368& data-rawheight=&225& class=&content_image& width=&368&&MUDOS采用 C语言开发,因为玩家和玩家之间有比较强的交互(聊天,交易,PK),MUDOS使用单线程无阻塞套接字来服务所有玩家,所有玩家的请求都发到同一个线程去处理,主线程每隔1秒钟更新一次所有对象(网络收发,更新对象状态机,处理超时,刷新地图,刷新NPC)。&br&&br&游戏世界采用房间的形式组织起来,每个房间有东南西北四个方向可以移动到下一个房间,由于欧美最早的网游都是地牢迷宫形式的,因此场景的基本单位被成为 “房间”。MUDOS使用一门称为LPC的脚本语言来描述整个世界(包括房间拓扑,配置,NPC,以及各种剧情)。游戏里面的高级玩家(巫师),可以不断的通过修改脚本来为游戏添加房间以及增加剧情。早年 MUD1上线时只有17个房间,Roy Trubshaw毕业以后交给他的师弟 Richard Battle,在 Richard Battle手上,不断的添加各种玩法到一百多个房间,终于让 MUD发扬光大。&br&&br&用户使用 Telnet之类的客户端用 Tcp协议连接到 MUDOS上,使用纯文字进行游戏,每条指令用回车进行分割。比如 1995年国内第一款 MUD游戏《侠客行》,你敲入:&go east&,游戏就会提示你:“后花园 - 这里是归云庄的后花园,种满了花草,几个庄丁正在浇花。此地乃是含羞草生长之地。这里唯一的出口是 north。这里有:花待 阿牧(A mu),还有二位庄丁(Zhuang Ding)”,然后你继续用文字操作,查看阿牧的信息:“look a mu”,系统提示:“花待 阿牧(A mu)他是陆乘风的弟子,受命在此看管含羞草。他看起来三十多岁,生得眉清目秀,端正大方,一表人才。他的武艺看上去【不是很高】,出手似乎【极轻】”。然后你可以选择击败他获得含羞草,但是你吃了含羞草却又可能会中毒死亡。在早期网上资源贫乏的时候,这样的游戏有很强的代入感。&br&&br&用户数据保存在文件中,每个用户登录时,从文本文件里把用户的数据全部加载进来,操作全部在内存里面进行,无需马上刷回磁盘。用户退出了,或者每隔5分钟检查到数据改动了,都会保存会磁盘。这样的系统在当时每台服务器承载个4000人同时游戏,不是特别大的问题。从1991年的 MUDOS发布后,全球各地都在为他改进,扩充,退出新版本,随着 Windows图形机能的增强。1997游戏《UO》在 MUDOS的基础上为角色增加的x,y坐标,为每个房间增加了地图,并且为每个角色增加了动画,形成了第一代的图形网络游戏。&br&&br&因为游戏内容基本可以通过 LPC脚本进行定制,所以MUDOS也成为名副其实的第一款服务端引擎,引擎一次性开发出来,然后制作不同游戏内容。后续国内的《万王之王》等游戏,很多都是跟《UO》一样,直接在 MUDOS上进行二次开发,加入房间的地图还有角色的坐标等要素,该架构一直为国内的第一代 MMORPG提供了稳固的支持,直到 2003年,还有游戏基于 MUDOS开发。&br&&br&虽然后面图形化增加了很多东西,但是这些MMORPG后端的本质还是 MUDOS。随着游戏内容的越来越复杂,架构变得越来越吃不消了,各种负载问题慢慢浮上水面,于是有了我们的第二代游戏服务器。&br&&br&&b&类型3:第二代游戏服务器 2003&/b&&br&&br&2000年后,网游已经脱离最初的文字MUD,进入全面图形化年代。最先承受不住的其实是很多小文件,用户上下线,频繁的读取写入用户数据,导致负载越来越大。随着在线人数的增加和游戏数据的增加,服务器变得不抗重负。同时早期 EXT磁盘分区比较脆弱,稍微停电,容易发生大面积数据丢失。因此第一步就是拆分文件存储到数据库去。&br&&img src=&/984d43af31dcbb20bfbdf6c22cce4947_b.jpg& data-rawwidth=&439& data-rawheight=&159& class=&origin_image zh-lightbox-thumb& width=&439& data-original=&/984d43af31dcbb20bfbdf6c22cce4947_r.jpg&&&br&此时游戏服务端已经脱离陈旧的 MUDOS体系,各个公司在参考 MUDOS结构的情况下,开始自己用 C在重新开发自己的游戏服务端。并且脚本也抛弃了 LPC,采用扩展性更好的 Python或者 Lua来代替。由于主逻辑使用单线程模型,随着游戏内容的增加,传统单服务器的结构进一步成为瓶颈。于是有人开始拆分游戏世界,变为下面的模型:&br&&img src=&/68a2d231c4e2c1ba2fb37_b.jpg& data-rawwidth=&404& data-rawheight=&163& class=&content_image& width=&404&&游戏服务器压力拆分后得意缓解,但是两台游戏服务器同时访问数据库,大量重复访问,大量数据交换,使得数据库成为下一个瓶颈。于是形成了数据库前端代理(DB Proxy),游戏服务器不直接访问数据库而是访问代理,再有代理访问数据库,同时提供内存级别的cache。早年 MySQL4之前没有提供存储过程,这个前端代理一般和 MySQL跑在同一台上,它转化游戏服务器发过来的高级数据操作指令,拆分成具体的数据库操作,一定程度上代替了存储过程:&br&&img src=&/cf87922d9cff5e0a6490abc5d396c4fe_b.jpg& data-rawwidth=&466& data-rawheight=&162& class=&origin_image zh-lightbox-thumb& width=&466& data-original=&/cf87922d9cff5e0a6490abc5d396c4fe_r.jpg&&但是这样的结构并没有持续太长时间,因为玩家切换场景经常要切换连接,中间的状态容易错乱。而且游戏服务器多了以后,相互之间数据交互又会变得比较麻烦,于是人们拆分了网络功能,独立出一个网关服务 Gate(有的地方叫 Session,有的地方叫 LinkSvr之类的,名字不同而已):&br&&img src=&/6ae41d97c6bbf306d1319a_b.jpg& data-rawwidth=&486& data-rawheight=&289& class=&origin_image zh-lightbox-thumb& width=&486& data-original=&/6ae41d97c6bbf306d1319a_r.jpg&&把网络功能单独提取出来,让用户统一去连接一个网关服务器,再有网关服务器转发数据到后端游戏服务器。而游戏服务器之间数据交换也统一连接到网管进行交换。这样类型的服务器基本能稳定的为玩家提供游戏服务,一台网关服务1-2万人,后面的游戏服务器每台服务5k-1w,依游戏类型和复杂度不同而已,图中隐藏了很多不重要的服务器,如登录和管理。这是目前应用最广的一个模型,到今天任然很多新项目会才用这样的结构来搭建。&br&&br&人都是有惯性的,按照先前的经验,似乎把 MUDOS拆分的越开性能越好。于是大家继续想,网关可以拆分呀,基础服务如聊天交易,可以拆分呀,还可以提供web接口,数据库可以拆分呀,于是有了下面的模型:&br&&img src=&/e0c141eb5954dcafcbb4bc86c475da30_b.jpg& data-rawwidth=&480& data-rawheight=&266& class=&origin_image zh-lightbox-thumb& width=&480& data-original=&/e0c141eb5954dcafcbb4bc86c475da30_r.jpg&&这样的模型好用么?确实有成功游戏使用类似这样的架构,并且发挥了它的性能优势,比如一些大型 MMORPG。但是有两个挑战:每增加一级服务器,状态机复杂度可能会翻倍,导致研发和找bug的成本上升;并且对开发组挑战比较大,一旦项目时间吃紧,开发人员经验不足,很容易弄挂。&br&&br&比如我见过某上海一线游戏公司的一个 RPG上来就要上这样的架构,我看了下他们团队成员的经验,问了下他们的上线日期,劝他们用前面稍微简单一点的模型。人家自信得很,认为有成功项目是这么做的,他们也要这么做,自己很想实现一套。于是他们义无反顾的开始编码,项目做了一年多,然后,就没有然后了。&br&&br&现今在游戏成功率不高的情况下,一开始上一套比较复杂的架构需要考虑投资回报率,比如你的游戏上线半年内 PCU会去到多少?如果一个 APRG游戏,每组服务器5千人都到不了的话,那么选择一套更为贴近实际情况的结构更为经济。即使后面你的项目真的超过5千人朝着1万人目标奔的话,相信那个时候你的项目已经挣大钱了 ,你数着钱加着班去逐步迭代,一次次拆分它,相信心里也是乐开花的。&br&&br&上面这些类型基本都是从拆分 MUDOS开始,将 MUDOS中的各个部件从单机一步步拆成分布式。虽然今天任然很多新项目在用上面某一种类似的结构,或者自己又做了其他热点模块的拆分。因为他们本质上都是对 MUDOS的分解,故将他们归纳为第二代游戏服务器。&br&&br&&b&类型4:第三代游戏服务器 2007&/b&&br&&br&从魔兽世界开始无缝世界地图已经深入人心,比较以往游戏玩家走个几步还需要切换场景,每次切换就要等待 LOADING个几十秒是一件十分破坏游戏体验的事情。于是对于 2005年以后的大型 MMORPG来说,无缝地图已成为一个标准配置。比较以往按照地图来切割游戏而言,无缝世界并不存在一块地图上面的人有且只由一台服务器处理了:&br&&img src=&/c13a5acd999_b.jpg& data-rawwidth=&418& data-rawheight=&185& class=&content_image& width=&418&&&br&每台 Node服务器用来管理一块地图区域,由 NodeMaster(NM)来为他们提供总体管理。更高层次的 World则提供大陆级别的管理服务。这里省略若干细节服务器,比如传统数据库前端,登录服务器,日志和监控等,统统用 ADMIN概括。在这样的结构下,玩家从一块区域走向另外一块区域需要简单处理一下:&br&&img src=&/424cd1ceecfeb_b.jpg& data-rawwidth=&388& data-rawheight=&290& class=&content_image& width=&388&&玩家1完全由节点A控制,玩家3完全由节点B控制。而处在两个节点边缘的2号玩家,则同时由A和B提供服务。玩家2从A移动到B的过程中,会同时向A请求左边的情况,并向B请求右边的情况。但是此时玩家2还是属于A管理。直到玩家2彻底离开AB边界很远,才彻底交由B管理。按照这样的逻辑将世界地图分割为一块一块的区域,交由不同的 Node去管理。&br&&br&对于一个 Node所负责的区域,地理上没必要连接在一起,比如大陆的四周边缘部分和高山部分的区块人比较少,可以统一交给一个Node去管理,而这些区块在地理上并没有联系在一起的必要性。一个 Node到底管理哪些区块,可以根据游戏实时运行的负载情况,定时维护的时候进行更改 NodeMaster 上面的配置。&br&&br&于是碰到第一个问题是很多 Node服务器需要和玩家进行通信,需要问管理服务器特定UID为多少的玩家到底在哪台 Gate上,以前按场景切割的服务器这个问题不大,问了一次以后就可以缓存起来了,但是现在服务器种类增加不少,玩家又会飘来飘去,按UID查找玩家比较麻烦;另外一方面 GATE需要动态根据坐标计算和哪些 Node通信,导致逻辑越来越厚,于是把:“用户对象”从负责连接管理的 GATE中切割出来势在必行于是有了下面的模型:&br&&img src=&/bd2bec76b90651cfdf696da_b.jpg& data-rawwidth=&420& data-rawheight=&275& class=&content_image& width=&420&&网关服务器再次退回到精简的网络转发功能,而用户逻辑则由按照 UID划分的 OBJ服务器来承担,GATE是按照网络接入时的负载来分布,而 OBJ则是按照资源的编号(UID)来分布,这样和一个用户通信直接根据 UID计算出 OBJ服务器编号发送数据即可。而新独立出来的 OBJ则提供了更多高层次的服务:&br&&ul&&li&对象移动:管理具体玩家在不同的 Node所管辖的区域之间的移动,并同需要的 Node进行沟通。&br&&/li&&li&数据广播:Node可以给每个用户设置若干 TAG,然后通知 Object Master 按照TAG广播。&br&&/li&&li&对象消息:通用消息推送,给某个用户发送数据,直接告诉 OBJ,不需要直接和 GATE打交道。&br&&/li&&li&好友聊天:角色之间聊天直接走 OBJ/OBJ MASTER。&/li&&/ul&整个服务器主体分为三层以后,NODE专注场景,OBJ专注玩家对象,GATE专注网络。这样的模型在无缝场景服务器中得到广泛的应用。但是随着时间的推移,负载问题也越来越明显,做个活动,远来不活跃的区域变得十分活跃,靠每周维护来调整还是比较笨重的,于是有了动态负载均衡。&br&&br&动态负载均衡有两种方法,第一种是按照负载,由 Node Master 定时动态移动修改一下各个 Node的边界,而不同的玩家对象按照先前的方法从一台 Node上迁移到另外一台 Node上:&br&&img src=&/0c4dcad7e6e8a694a46df5e_b.jpg& data-rawwidth=&162& data-rawheight=&181& class=&content_image& width=&162&&
图11 动态负载均衡&br&&br&这样 Node Master定时查找地图上的热点区域,计算新的场景切割方式,然后告诉其他服务器开始调整,具体处理方式还是和上面对象跨越边界移动的方法一样。&br&&br&但是上面这种方式实现相对复杂一些,于是人们设计出了更为简单直接的一种新方法:&br&&img src=&/8e250bfe7fc15eb0a0d2925dab684ec2_b.jpg& data-rawwidth=&251& data-rawheight=&250& class=&content_image& width=&251&&
图12 基于网格的动态负载均衡&br&&br&还是将地图按照标准尺寸均匀切割成静态的网格,每个格子由一个具体的Node负责,但是根据负载情况,能够实时的迁移到其他 Node上。在迁移分为三个阶段:准备,切换,完成。三个状态由Node Master负责维护。准备阶段新的 Node开始同步老 Node上面该网格的数据,完成后告诉NM;NM确认OK后同时通知新旧 Node完成切换。完成切换后,如果 Obj服务器还在和老的 Node进行通信,老的 Node将会对它进行纠正,得到纠正的 OBJ将修正自己的状态,和新的 Node进行通信。&br&&br&很多无缝动态负载均衡的服务端宣称自己支持无限的人数,但不意味着 MMORPG游戏的人数上限真的可以无限扩充,因为这样的体系会受制于网络带宽和客户端性能。带宽决定了同一个区域最大广播上限,而客户端性能决定了同一个屏幕到底可以绘制多少个角色。&br&&br&从无缝地图引入了分布式对象模型开始,已经完全脱离 MUDOS体系,成为一种新的服务端模型。又由于动态负载均衡的引入,让无缝服务器如虎添翼,容纳着超过上一代游戏服务器数倍的人数上限,并提供了更好的游戏体验,我们称其为第三代游戏服务端架构。网游以大型多人角色扮演为开端,RPG网游在相当长的时间里一度占据90%以上,使得基于 MMORPG的服务端架构得到了蓬勃的发展,然而随着玩家对RPG的疲惫,各种非MMORPG游戏如雨后春笋般的出现在人们眼前,受到市场的欢迎。&br&&br&&b&类型5:战网游戏服务器&/b&&br&&br&经典战网服务端和 RPG游戏有两个区别:RPG是分区分服的,北京区的用户和广州区的用户老死不相往来。而战网,虽然每局游戏一般都是 8人以内,但全国只有一套服务器,所有的玩家都可以在一起游戏,而玩家和玩家之使用 P2P的方式连接在一起,组成一局游戏:&img src=&/bfda3d0c5da7_b.jpg& data-rawwidth=&493& data-rawheight=&352& class=&origin_image zh-lightbox-thumb& width=&493& data-original=&/bfda3d0c5da7_r.jpg&&玩家通过 Match Making 服务器使用:创建、加入、自动匹配、邀请 等方式组成一局游戏。服务器会选择一个人做 Host,其他人 P2P连接到做主的玩家上来。STUN是帮助玩家之间建立 P2P的牵引服务器,而由于 P2P联通情况大概只有 75%,实在联不通的玩家会通过 Forward进行转发。&br&&br&大量的连接对战,体育竞技游戏采用类似的结构。P2P有网状模型(所有玩家互相连接),和星状模型(所有玩家连接一个主玩家)。复杂的游戏状态在网状模型下难以形成一致,因此星状P2P模型经受住了历史的考验。除去游戏数据,支持语音的战网系统也会将所有人的语音数据发送到做主的那个玩家机器上,通过混音去重再编码的方式返回给所有用户。&br&&br&战网类游戏,以竞技、体育、动作等类型的游戏为主,较慢节奏的 RPG(包括ARPG)有本质上的区别,而激烈的游戏过程必然带来到较 RPG复杂的多的同步策略,这样的同步机制往往带来的是很多游戏结果由客户端直接计算得出,那在到处都是破解的今天,如何保证游戏结果的公正呢?&br&&br&主要方法就是投票法,所有客户端都会独立计算,然后传递给服务器。如果结果相同就更新记录,如果结果不一致,会采取类似投票的方式确定最终结果。同时记录本剧游戏的所有输入,在可能的情况下,找另外闲散的游戏客户端验算整局游戏是否为该结果。并且记录经常有作弊嫌疑的用户,供运营人员封号时参考。&br&&br&&b&类型7:休闲游戏服务器&/b&&br&&br&休闲游戏同战网服务器类似,都是全区架构,不同的是有房间服务器,还有具体的游戏服务器,游戏主体不再以玩家 P2P进行,而是连接到专门的游戏服务器处理:&br&&img src=&/bae1e94836cbb_b.jpg& data-rawwidth=&698& data-rawheight=&630& class=&origin_image zh-lightbox-thumb& width=&698& data-original=&/bae1e94836cbb_r.jpg&&&br&和战网一样的全区架构,用户数据不能象分区的 RPG那样一次性load到内存,然后在内存里面直接修改。全区架构下,为了应对一个用户同时玩几个游戏,用户数据需要区分基本数据和不同的游戏数据,而游戏数据又需要区分积分数据、和文档数据。胜平负之类的积分可以直接提交增量修改,而更为普遍的文档类数据则需要提供读写令牌,写令牌只有一块,读令牌有很多块。同帐号同一个游戏同时在两台电脑上玩时,最先开始的那个游戏获得写令牌,可以操作任意的用户数据。而后开始的那个游戏除了可以提交胜平负积分的增量改变外,对用户数据采用只读的方式,保证游戏能运行下去,但是会提示用户,游戏数据锁定。&br&&br&&b&类型8:现代动作类网游&/b&&br&&br&从早期的韩国动作游戏开始,传统的战网动作类游戏和 RPG游戏开始尝试融合。单纯的动作游戏玩家容易疲倦,留存也没有 RPG那么高;而单纯 RPG战斗却又慢节奏的乏味,无法满足很多玩家激烈对抗的期望,于是二者开始融合成为新一代的:动作 + 城镇 模式。玩家在城镇中聚集,然后以开副本的方式几个人出去以动作游戏的玩法来完成各种 RPG任务。本质就是一套 RPG服务端+副本服务端。由于每次副本时人物可以控制在8人以内,因此可以获得更为实时的游戏体验,让玩家玩的更加爽快。&br&&br&说了那么多的游戏服务器类型,其实也差不多了,剩下的类型大家拼凑一下其实也就是这个样子而已。游戏服务端经历了那么多结构上的变迁,内部开发模式是否依然不变?究竟是继续延续传统的开发方式?还是有了更多突破性的方法?经历那么多次架构变迁,后面是否有共通的逻辑?未来的发展还会存在哪些困难?游戏服务端开发如何达到最终的彼岸?请看下节:技术的演进。&br&&br&&b&技术的演进&/b&&br&&br&(欢迎加入“游戏服务端架构交流” QQ群 ,共同讨论相关问题)&br&&br&(待续)
谢邀,手游页游和端游的服务端本质上没区别,区别的是游戏类型。类型1:卡牌、跑酷等弱交互服务端卡牌跑酷类因为交互弱,玩家和玩家之间不需要实时面对面PK,打一下对方的离线数据,计算下排行榜,买卖下道具即可,所以实现往往使用简单的 HTTP服务器:登录…
&a href=&///?target=https%3A///chenshuo/recipes/blob/master/basic/int128.h& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&/chenshuo/rec&/span&&span class=&invisible&&ipes/blob/master/basic/int128.h&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&
说实话,我初期主要的技术观都是通过微软技术获得的,也许是比较幸运,如果上来写iOS或者Android代码很容易废掉,沦为框架型程序员,微软技术的精髓就是把一些问题想的很透,比如很多Android刚出的技术微软N年前就实现了,再比如把WCF技术理解通透了,当自己重新去写server端程序的时候会感觉很有方向感,不只是我一个人,很多同事都觉得微软技术是根。
说实话,我初期主要的技术观都是通过微软技术获得的,也许是比较幸运,如果上来写iOS或者Android代码很容易废掉,沦为框架型程序员,微软技术的精髓就是把一些问题想的很透,比如很多Android刚出的技术微软N年前就实现了,再比如把WCF技术理解通透了,当自…
当然可以,而且允许发件人自定义绝大多数的发件人特征信息,只要符合SMTP协议就可以。Linux的sendmail命令其实就可以直接发送,只不过妥妥的进垃圾箱。&br&&br&为了防止伪造邮件,现在的邮箱都有了SPF(Sender Policy Framework)机制:&br&收邮件方会根据你的SPF记录来判断连接过来的IP地址是否被包含在SPF记录里面,如果在,则认为是一封正确的邮件,否则则认为是一封伪造的邮件。&br&用nslookup(Windows)或者dig(Linux)命令就可以查看一个域名的SPF记录。&br&&p&正确设置后邮件头一般显示如下:&/p&&div class=&highlight&&&pre&&code class=&language-text&&Received-SPF: pass (: domain of wordpress@ designates 72.47.192.112 as permitted sender) client-ip=72.47.192.112;
Authentication-Results: ; spf=pass (: domain of wordpress@your_d
&/code&&/pre&&/div&&br&像Gmail还有DKIM机制,DKIM的全称是Domain Key Identified Mail,最初由Yahoo提出。&br&简单的说,就是发送邮件的服务器对邮件做签名,表示这个邮件的确是该服务器发送出去的。如果一个接收端能够验证这个签名,一定程度上表明这个邮件可能不是垃圾或者钓鱼邮件——原因是现在大多数的垃圾和钓鱼邮件都使用伪造的email地址。当然,这个技术不能单独解决问题,因为一个垃圾邮件发送者也可以自己做一个服务器来对发出的所有垃圾邮件签名。但是,由于邮件是签名的,我们就可以通过黑名单和白名单来进一步了解某个域名发出的邮件是否为垃圾邮件,甚至可以在网上维护一个域名的积分系统。&br&因为DKIM必需配合软件和加密技术,比较麻烦。目前使用的也不多。
当然可以,而且允许发件人自定义绝大多数的发件人特征信息,只要符合SMTP协议就可以。Linux的sendmail命令其实就可以直接发送,只不过妥妥的进垃圾箱。为了防止伪造邮件,现在的邮箱都有了SPF(Sender Policy Framework)机制:收邮件方会根据你的SPF记录来…
asio除了是个网络库、io库外,还是个可以玩出很多花样的异步任务分派引擎,还支持stackful和stackless两种协程。asio对于异步、相关联任务的串行化及任务处理顺序等做了非常严格的保证,基于此可以撸出一整套异步处理系统。刚基于asio开发了网游用的actor模型的引擎,打算用于公司的新手游。&br&ps:asio最近的版本调整比较大,因为它正在为进入c++17做准备,未来的某一天它很可能变成std::network&br&抱歉不熟悉wangle…
asio除了是个网络库、io库外,还是个可以玩出很多花样的异步任务分派引擎,还支持stackful和stackless两种协程。asio对于异步、相关联任务的串行化及任务处理顺序等做了非常严格的保证,基于此可以撸出一整套异步处理系统。刚基于asio开发了网游用的actor模…
既然没有高手,那我这个业余站长、业余开发者且来一答。&br&方案一:AWS 12个月 21种产品免费体验方案&br&&img src=&/22c695add2a_b.png& data-rawwidth=&883& data-rawheight=&522& class=&origin_image zh-lightbox-thumb& width=&883& data-original=&/22c695add2a_r.png&&优点:VPS、对象数据存储、NOSQL、Lambda、CodeCommit、Key Management Service、Cognito、AppStream、CloudFront、RDS、Mobile Analytics、EBS、ElastiCache、Elastic Transcoder、CloudWatch、SQS、SNS、SWF、Data Pipeline、SES、CodePipeline、API Gateway、Device Farm 全部免费用一年。&br&足够你做为学习用途,把一个站长与开发者所需的学习资源都用上。其中一些你不太理解的应用,也请多花点时间研究。&br&缺点:1.需绑定信用卡【用超了会扣款】 2.15G入站流量限制 &a href=&///?target=http%3A//3.IO& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&3.IO&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a&也有限制容易超 4.国内访问ping值100以上【推荐新加坡与东京节点】 5.因为众所周知的原因,有时要多刷新几次才能打开。6.进入付费阶段后因为价格高、容易打不开、国内没节点等原因,不适合国内开发者&br&&br&方案二、腾讯云 小额付费方案:&br&1.&a href=&///?target=http%3A///anniversary/5th/promotion/newuser.php& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&5周年庆 - 新用户专场&i class=&icon-external&&&/i&&/a& 领取使用代金券、认证送50元【自己找自己研究,还有很多优惠方式】&br&&img src=&/d7b71ffdee80_b.png& data-rawwidth=&984& data-rawheight=&545& class=&origin_image zh-lightbox-thumb& width=&984& data-original=&/d7b71ffdee80_r.png&&2.每充100送200&br&3.cdn 50g/月 免费6个月,初次付费 1t cdn 流量 100元&br&4.Redis CRS暂时免费、对象存储每月免费50g流量、50g空间(做图床什么的都很好)、还有一堆东西都用的上&br&5.云数库(mysql),6元 使用6个月(10G空间,360M内存 够你玩的)&br&6.一共享核/512M/1M带宽/Linux主机360元/年 1核/1G/1M 650元/年&br&结合以上方式,付个300元左右,一台主机用一年,cdn,云数据库,对象存储等实用的东西6个月。这时你手送还有600元左右的券,再给主机续1年,共2年,cdn、云数据库也续下费。&br&300元,用两年,而且全套你学习要用的都有了,速度还快。做个小型生产环境都够了。&br&优点:速度快、与aws类似,配套齐,除vps外,几乎所有的周边服务在轻度使用时仅需少额付费或不付费。&br&缺点:要花钱、以上优惠有时效性。&br&&br&额外的:&a href=&///?target=http%3A///& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&主机卫士 - 让服务器真正安全起来,后门扫描,网站补丁,主动防御&i class=&icon-external&&&/i&&/a& 360旗下的多款服务能够给你很多性能优化与安全建议,并提供基础的防护产品,而且是免费的。&br&&br&以上可结合使用。&br&&br&&br&&br&--------------------------------------跑题--------------------------------------&br&以上方案都是浮云,我的私人服务器是这样的:&br&电信IDC托管一台:1U 双子星系统【 6核至强 X 2路、 48G、 600G SAS硬盘 X 6】再X2 共24核48线程、96G内存、3.6T硬盘。20M带宽。 用esxi做虚拟化,双子星系统是两台完全独立的单元再做高可用,开个虚拟机专门给其他虚拟机加密后做快照与整机双备份到百度云与360云,用ikuai做网络管理与vpn,用腾讯的cdn加速,然后虚拟机想开几台有几台,想要多少性能有多少性能,一年多没关过机。&br&&br&对的,私人服务器就一个人用,真TMD爽。&br&&br&最后,你猜,这些只需要多少钱。
既然没有高手,那我这个业余站长、业余开发者且来一答。方案一:AWS 12个月 21种产品免费体验方案优点:VPS、对象数据存储、NOSQL、Lambda、CodeCommit、Key Management Service、Cognito、AppStream、CloudFront、RDS、Mobile Analytics、EBS、ElastiCache…
我来总结一下吧:&br&&ol&&li&PaaS:&/li&&ol&&li&(推荐)Redhat 的 OpenShift,可以一直免费。&/li&&li&Heroku,也可以一直免费。&/li&&li&SAE,没用过。&/li&&/ol&&li&IaaS:&/li&&ol&&li&DigitalOcean 学生赠送100刀+10刀,优点是所有规格都可以用,但要国际信用卡。&/li&&li&(推荐)AWS 的 Free Tier 中的 EC2,可以用一年最便宜的机器(两台),同时还有一大堆其他服务,也要国际信用卡。&/li&&li&阿里云似乎有新用户5块钱两个月类似的优惠。&/li&&/ol&&/ol&
我来总结一下吧:PaaS:(推荐)Redhat 的 OpenShift,可以一直免费。Heroku,也可以一直免费。SAE,没用过。IaaS:DigitalOcean 学生赠送100刀+10刀,优点是所有规格都可以用,但要国际信用卡。(推荐)AWS 的 Free Tier 中的 EC2,可以用一年最便宜的机器(…
我一直在用heroku,觉得还不错。介绍如下:&br&&br&免费帐号能创建无限个网站,支持python/ruby/php等诸多语言,你的app会被分配到独立的linux虚拟机中。使用git、GitHub或dropbox部署。&br&&br&每个网站在30分钟无人访问后便会被关闭(所有数据都会被清空,但程序不会),再有人访问就会自动重新打开。即使总有人访问,免费版网站24小时内如果运行了超过18小时也会被强行关闭。&br&&br&机房在美国和欧洲(可选),国内访问速度可以接受,不过网站启动需要几秒钟的时间,所以半小时之内的第一次访问会卡一些。&br&&br&基本上没有什么限制,不像SAE连读写文件系统都不让(反正半个小时重置一次也不怕你乱改),没有流量限制。&br&&br&heroku还提供不会被清空的数据库,免费版好像有容量限制,没用过不知道。&br&&br&===== 我是跑题的分割线&br&&br&我最近在研究让app在heroku上持续运行的技巧,原理大致如下:&br&1. 创建两个源码相同的app,分别为A和B&br&2. 启动A&br&3. A运行12小时后唤醒B,并将程序运行的阶段性成果发给B&br&4. B开始运行,30分钟后A自动关闭&br&5. B运行12小时后又唤醒A……&br&再整个过程中A和B都没触发18小时强行停机的限制
我一直在用heroku,觉得还不错。介绍如下:免费帐号能创建无限个网站,支持python/ruby/php等诸多语言,你的app会被分配到独立的linux虚拟机中。使用git、GitHub或dropbox部署。每个网站在30分钟无人访问后便会被关闭(所有数据都会被清空,但程序不会),…
我前一段时间写了几篇有关于网络编程的博客,讲述自己的网络编程开发之旅,希望能给你提供借鉴:&br&&a href=&///?target=http%3A//yaocoder./3513& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&我的网络开发之旅――TCP/IP协议分析&i class=&icon-external&&&/i&&/a&&br&&a href=&///?target=http%3A//yaocoder./6742& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&我的网络开发之旅――socket编程&i class=&icon-external&&&/i&&/a&&br&&a href=&///?target=http%3A//yaocoder./5740& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&我的网络编程之旅——P2P相关话题&i class=&icon-external&&&/i&&/a&&br&&br&接着有时间了我还会继续写自己对网络编程方面的一些浅薄之见,希望我们能持续交流。
我前一段时间写了几篇有关于网络编程的博客,讲述自己的网络编程开发之旅,希望能给你提供借鉴:接着有时间了我还会继续写自己对网络编程方面的一些浅薄…
我说几个比较常见的。&br&&br&1.三次握手,到底完成了么?常见的攻击就是不完成3次握手,导致你的backlog队列塞满,而没有任何accept发生,这会导致后续的连接被拒绝。因此第一步就是要干掉没有在规定时间内完成3次握手的连接,并且最好将该ip短时间内拉入黑名单(20秒,1分钟之类)。&br&&br&2.异常数据,异常的数据会导致逻辑不严谨的代码触发一些不确定的行为。因此在协议设计的时候,要为不符合预期的数据做好准备。常见的比如 数据包的包长度必须限制在一个规定的范围内,而不是shrot 或者 int 的长度。对于在此之上的文件传输,最好另开结点或者为此定制一个文件传输协议(即分割文件)。&br&&br&3.长期空闲,定时检查超时连接是避免不了的,除非存在挂机的现象(网游),否则对于不活跃的连接应当直接清除。&br&&br&4.数据的加密和解密,这个老生常谈了,照着方法就好。&br&&br&5.socket不正常关闭的情况,socket连接的关闭需要4次握手,但通常很难确保该握手会完成,因此应当强制清理需要关闭的socket。&br&&br&6.第三方客户端,任何未授权的应用都不能调用目标服务器上的数据,协议设计时应当考虑鉴权和确保非第三方客户端的机制。&br&&br&7.逻辑和数据服务器,绝对不应该放在整个网络的前面(即客户直连的地方),不管你是自定义协议or常用协议,用户连接到的服务器应该是你们的网关服务器,再由网关服务器转发(可以变换协议)到内部服务器上。
我说几个比较常见的。1.三次握手,到底完成了么?常见的攻击就是不完成3次握手,导致你的backlog队列塞满,而没有任何accept发生,这会导致后续的连接被拒绝。因此第一步就是要干掉没有在规定时间内完成3次握手的连接,并且最好将该ip短时间内拉入黑名单(20…
&p&&b&首先,这是个很大的命题,之前在360负责过几个对外的服务的研发,也算是有点小经验,我试着答一下:&/b&&/p&&p&在Internet环境下,安全问题我主要分为如下几类:&/p&&ol&&li&信息传输过程中被黑客窃取&/li&&li&服务器自身的安全&/li&&li&服务端数据的安全&/li&&/ol&&p&首先,如果能用https,就尽量用https,能用nginx等常见服务器,就用常见服务器,主要能避免以下问题:&/p&&ul&&li&自己实现的协议&Server端可能会有各种Bug,被缓冲区溢出攻击等&/li&&li&SSL加密体系在防监听方面已经足够成熟,值得信赖&/li&&/ul&&p&所幸,私有协议服务的攻击需要黑客分析协议,这就给一般的小服务增加了一层保护。但如果是在大公司做事,树大招风,就必须至少做到理论上没有安全漏洞。神马,xor混淆一下,C/S端写死一个对称密钥这种掩耳盗铃的事情就不要做了,不然会死的很难看。&/p&&p&如果需要自己实现Server端,实现一套合格的SSL还是很考验功底的:&/p&&ul&&li&首先要弄明白SSL加密体系密钥交换的原理&/li&&li&对各种对称、非对称加密算法要有深刻的理解&/li&&li&用非对称加密算法怎么实现一套密钥交换体系&/li&&li&如何处理ca证书,在自签名情况下怎么避免中间人攻击&/li&&/ul&&p&工程实现过程中,要考虑:&/p&&ul&&li&各种可能的缓冲区溢出攻击&/li&&li&SYN flood攻击,慢连接攻击&/li&&li&DDoS防起来有难度,但至少能防御DoS攻击&/li&&/ul&&p&业务逻辑层面,要考虑:&/p&&ul&&li&每个接口都要做好用户&权限验证&/li&&li&接口会不会被人乱用,重放攻击&/li&&li&攻击方会不会找到一个比较消耗服务端资源的接口,用很小的代价耗尽服务端资源&/li&&li&用户的用户名密码会不会被通过接口破解,参见:&a href=&///?target=http%3A//en.wikipedia.org/wiki/2014_celebrity_photo_hack& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&2014 celebrity photo hack&i class=&icon-external&&&/i&&/a&&/li&&li&你的服务会不会被黑客利用去攻击别的服务,特别是会根据用户输入抓取什么资源的服务&/li&&li&古老的SQL注入&/li&&li&无耻的仿冒服务,DNS欺诈&/li&&li&涉及HTML的,还要考虑跨站……&/li&&/ul&&p&即使你做到了天衣无缝,还要考虑队友有时会掉链子:&/p&&ul&&li&glibc、openssl这些基础的库也会爆出漏洞,参见:&a href=&///?target=http%3A//en.wikipedia.org/wiki/Heartbleed& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Heartbleed&i class=&icon-external&&&/i&&/a&&/li&&li&同一台主机上的其它服务被攻陷&/li&&/ul&&p&没有踩过很多坑,哪里知道很多事。写完之后整个人都不好了&/p&
首先,这是个很大的命题,之前在360负责过几个对外的服务的研发,也算是有点小经验,我试着答一下:在Internet环境下,安全问题我主要分为如下几类:信息传输过程中被黑客窃取服务器自身的安全服务端数据的安全首先,如果能用https,就尽量用https,能用ngi…
内容安全考虑,非对称加密交换密钥(RSA/DH),然后对称加密(RC4/RC5)进行通信。即使盘路监听了,也无法获取你的通信内容。如果嫌弃 RSA太庞大,不想上 openssl/polarssl的话,可以用 DH算法,上64位整数,实现一个64位整数的快速 PowMod,参考 Russian Peasant multiplication 和 Right-to-left binary method 来实现快速运算,大质数事先固定(免去沉重的质数生成计算),每秒钟计算上几十万次密钥交换应该不是大问题。
内容安全考虑,非对称加密交换密钥(RSA/DH),然后对称加密(RC4/RC5)进行通信。即使盘路监听了,也无法获取你的通信内容。如果嫌弃 RSA太庞大,不想上 openssl/polarssl的话,可以用 DH算法,上64位整数,实现一个64位整数的快速 PowMod,参考 Russian P…
通常来讲,就是利用 select 的空余时间,来进行时钟检查,不管是 select / poll / epoll/ kevent,以下统称 select,它有一个等待时间作为参数,即没有事件时,最多 wait 多少时间,我们把这个作为网络库的基准频率,比如 10MS,或者 20MS, 25MS, 50MS,都是常用的几个值。&br&&br&就是说网络库调用 select 等待事件时如果没有事件,那么最长等待 10MS 就返回了,这时再处理完所有网络事件后,就可以来处理时钟数据了。事件处理函数就是这样:&br&&div class=&highlight&&&pre&&code class=&language-python&&&span class=&k&&def&/span& &span class=&nf&&update_events&/span&&span class=&p&&(&/span&&span class=&n&&milisec&/span& &span class=&o&&=&/span& &span class=&mi&&10&/span&&span class=&p&&):&/span&
&span class=&n&&result&/span& &span class=&o&&=&/span& &span class=&n&&selector&/span&&span class=&o&&.&/span&&span class=&n&&select&/span&&span class=&p&&(&/span&&span class=&n&&milisec&/span&&span class=&p&&)&/span&
&span class=&k&&for&/span& &span class=&n&&fd&/span&&span class=&p&&,&/span& &span class=&n&&event&/span& &span class=&ow&&in&/span& &span class=&n&&result&/span&&span class=&p&&:&/span&
&span class=&n&&do&/span& &span class=&n&&something&/span& &span class=&k&&with&/span& &span class=&n&&socket&/span& &span class=&n&&event&/span&
&span class=&n&&current&/span& &span class=&o&&=&/span& &span class=&n&&time&/span&&span class=&o&&.&/span&&span class=&n&&time&/span&&span class=&p&&()&/span&
&span class=&n&&update_timer&/span&&span class=&p&&(&/span&&span class=&n&&current&/span&&span class=&p&&)&/span&
&span class=&k&&while&/span& &span class=&mi&&1&/span&&span class=&p&&:&/span&
&span class=&n&&WAIT_MILLISEC&/span& &span class=&o&&=&/span& &span class=&mi&&10&/span&
&span class=&n&&update_events&/span&&span class=&p&&(&/span&&span class=&n&&WAIT_MILLISEC&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&br&关键就是这个两次 select 中间 update_timer 的任务:集合中检查需要唤醒的时钟,并且调用它们的回调函数,来驱动整个服务器的时钟运行,以最简单的扫描法为例:&br&&div class=&highlight&&&pre&&code class=&language-python&&&span class=&k&&def&/span& &span class=&nf&&update_timer&/span& &span class=&p&&(&/span&&span class=&n&&current&/span&&span class=&p&&):&/span&
&span class=&k&&for&/span& &span class=&n&&timer&/span& &span class=&ow&&in&/span& &span class=&n&&available_timers&/span&&span class=&p&&:&/span&
&span class=&k&&while&/span& &span class=&n&&current&/span& &span class=&o&&&=&/span& &span class=&n&&timer&/span&&span class=&o&&.&/span&&span class=&n&&expires&/span&&span class=&p&&:&/span&
&span class=&n&&timer&/span&&span class=&o&&.&/span&&span class=&n&&callback&/span&&span class=&p&&(&/span&&span class=&n&&current&/span&&span class=&p&&)&/span&
&span class=&n&&timer&/span&&span class=&o&&.&/span&&span class=&n&&expires&/span& &span class=&o&&+=&/span& &span class=&n&&timer&/span&&span class=&o&&.&/span&&span class=&n&&period&/span&
&/code&&/pre&&/div&&br&available_timers 记录着当前可用的所有 timer 的集合,expires 是他们需要被触发的时间,如果当前时间大于等于这个 expires,认为该 timer 需要被触发到。注意 timer.expires 更新的时候是 += 周期,而不是 = current + 周期,后者会导致误差积累,长时间运行后偏差越来越大。同时这里需要 while,因为可能跨越两个以上周期,当然只运行一次的 timer 就不需要了,这里只是简化下。&br&&br&比如 libevent 里面的主循环 event_base_loop 每次 select 完毕后就调用一次 timeout_process。&br&&br&这就是 Timer 调度的基本原理。&br&&br&可能你会发现每次 select 结束都要扫描整个 available_timers 集合,是一个非常费时间的事情,那么首先想到的就是优先队列了:将 Timer 节点按照 expires 的先后顺序,将最快要发生的超时节点放在前面,每次检测队列头就可以判断是否超时了。&br&&br&比如 libevent 里面的 timerout_process 函数,就是用最小堆来存储超时事件,每次检测堆的第一个节点如果超时则删除并继续检测下一个,否则跳出循环(此时没有任何节点到期)。&br&&br&还有一种固定超时队列,就是里面的节点的超时周期都是相同的,那么每次增加都在最后,每次检测都只检测头部。比如所有链接都要检测60秒无事件超时这个事情,就可以用它,因为60秒是固定的,新增时放到队列最后,检测时只检测头部是否超时,如果有事件来到,就删除并重新加入队列末尾,这是固定超时队列。&br&&br&还有上面专门说的系统提供的 timerfd,创建后加入
select, 但是受限于 linux 系统,跨平台就用不了了,不能太依赖。&br&&br&然而这些都不算最完美的解决方案,一旦超时节点多达上万个,每个时间都不同,又考虑通用实现(非特定平台实现)的话,这几种调度方式是要吃亏的,目前最好的算法是 Linux Kernel 的时间轮算法,几乎保证不管有多少个时钟对象要处理,每次 update_timer 的时间都几乎是常数。&br&&br&具体可以看代码 kernel/timer.c ,楼上提到 skynet 里面有个时间轮的应用层实现,看了一眼,和 skynet 依赖太大了,需要自己做剥离工作,同时全局变量做 tvec_base(时钟管理器),这有点要命,你多线程每个线程一个 selector 的时候,就没法用了。更加具备简单性和可拆分性的 Linux 时间轮的应用层实现见我写的:&br&&a href=&///?target=https%3A///skywind3000/AsyncNet/blob/master/system/itimer.h& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&AsyncNet/itimer.h at master · skywind3000/AsyncNet · GitHub&i class=&icon-external&&&/i&&/a&&br&&a href=&///?target=https%3A///skywind3000/AsyncNet/blob/master/system/itimer.c& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&AsyncNet/itimer.c at master · skywind3000/AsyncNet · GitHub&i class=&icon-external&&&/i&&/a&&br&&br&两个文件,拷贝走就得了,没有任何第三个文件的依赖,更没有全局唯一的时钟管理器。&br&&br&一般来讲 “侵入式” 的网络库,都会把这个事情给管理了,因为他们接管你的主循环,比如 libevent, skynet 之类,你进入一个 event_loop 就只有程序结束才能出来了,而非侵入式的网络库不会接管你的主循环,可以让你自己主动去触发。&br&&br&比如某同事想在 libevent 上跑一套自己的时钟系统,而 event_base_dispatch 属于进去就出不来的 “侵入式” 设计。为了能在 select 前后加入自己的时钟调度,不得不把 libevent 改出一个 branch 来,所以 侵入式 是比较恶劣的设计。libevent 应该学习一下 win32,把 GetMessage, DispatchMessage 放出来,比如叫做:&br&&div class=&highlight&&&pre&&code class=&language-c&&&span class=&kt&&int&/span& &span class=&nf&&event_base_update&/span&&span class=&p&&(&/span&&span class=&k&&struct&/span& &span class=&n&&event_base&/span& &span class=&o&&*&/span&&span class=&n&&base&/span&&span class=&p&&,&/span& &span class=&kt&&int&/span& &span class=&n&&max_wait_time&/span&&span class=&p&&);&/span&
&/code&&/pre&&/div&&br&让你主动去触发它,然后灵活的在前后做点事情,还可以用 event_base_wakeup 从另外一个现成唤醒它,这样就会灵活很多了,完全取代
event_base_dispatch 这个进去出不来的死循环。&br&&br&每次 select wait 的时间一般用一个固定值,称为一个 TICK,固定值选大了,时钟基准周期就会很长,短时误差就会增大,选小了,又会占用额外 cpu,可以模拟 Linux 使用 100Hz的值,即 10ms来做,这也是通行做法。&br&&br&不嫌麻烦还可以每次从 timer 集合里面选择最先要超时的事件,计算还有多长时间就会超时,作为 select wait 的值,每次都不一样,每次都基本精确,同时不会占用多余 cpu,这叫 tickless,Linux 的 3.x以上版本也支持 tickless 的模式来驱动各种系统级时钟,号称更省电更精确,不过需要你手动打开,FreeBSD 9 以后也引入了 tickless。&br&&br&TICKLESS 模式可以说是一个新的方向,但是目前处于默认关闭的测试状态,那么你的网络库到底是用 TICK 还是 TICKLESS,看你根据具体情况来评估了。
通常来讲,就是利用 select 的空余时间,来进行时钟检查,不管是 select / poll / epoll/ kevent,以下统称 select,它有一个等待时间作为参数,即没有事件时,最多 wait 多少时间,我们把这个作为网络库的基准频率,比如 10MS,或者 20MS, 25MS, 50MS,都…
我不是开发游戏的,但是从服务器应用的角度来说,网游服务端的程序无非就是一个事件循环。可以在事件循环中处理特定的消息,通过外部计时器如Linux系统自带的cron,或者独立的计时线程向主循环定时发送消息。主循环收到消息之后再处理,也就是说我推荐方案1。从提升服务器负载能力的角度考虑,这是较优的选择。
我不是开发游戏的,但是从服务器应用的角度来说,网游服务端的程序无非就是一个事件循环。可以在事件循环中处理特定的消息,通过外部计时器如Linux系统自带的cron,或者独立的计时线程向主循环定时发送消息。主循环收到消息之后再处理,也就是说我推荐方案1…
Client 发的 FIN 丢包。
Client 发的 FIN 丢包。
我就帮大家简单算个帐&br&&br&(因为讲的是带宽,所以以下单位是 bit,而不是byte)&br&现在搞直播好歹得有
1 mbps 的码流才勉强算高清直播吧,那么100万在线就是1 TB带宽。实际上不可能只租1TB,总要有点冗余浪费,实际可能是 1.5TB。&br&&br&光有带宽是不够的,还要有服务器,一般便宜的服务器都是GB级网卡只能用1GB带宽,但是不可能跑满的,总要留点冗余,一般就是800MB,也就是说最多同时服务800个用户。&br&那么服务100万用户,就要1250台前端服务器,用户分配不可能很均匀,还要留点冗余容灾什么的,那么大约需要2000台前端。为了服务这2000台前端,需要配至少300台后端做管理存储分发等工作。服务器要折旧的,这笔钱要算上。&br&&br&为了能让所有用户都就近接入,所以要在每个主要的节点IDC都部署服务器,由于天朝特色,运营商之间不互联互通,还有很多小网段,铁通、教育网、各种奇葩小宽带运营商等,至少要部署50+个机房。&br&&br&为了管理这2500台服务器和50个机房,好歹要有个30人左右的运维团队。&br&&br&这么粗略算下来,维持一个100万并发直播的能力需要每月花2000万左右。&br&&br&我不是随便乱说的,YY拥有远不止100万并发的直播能力,YY上个季度的带宽成本是 1.3亿元(参考财报2015Q2)&br&&br&评论中以及其它答案里提CDN方案的同学们,你们再好好想想,如果CDN方案又好用又便宜 YY 为什么不用,就算我孤陋寡闻不懂,后台几百个研发的同事都不懂?高管们、董事会还有投资人都不知道?就你一眼就看出来了?你觉得可能吗?
我就帮大家简单算个帐(因为讲的是带宽,所以以下单位是 bit,而不是byte)现在搞直播好歹得有 1 mbps 的码流才勉强算高清直播吧,那么100万在线就是1 TB带宽。实际上不可能只租1TB,总要有点冗余浪费,实际可能是 1.5TB。光有带宽是不够的,还要有服务器,…
虽然我不是专业搞视频直播(录播?)技术的,我也不知道 腾讯出了什么问题, 但我可以负责任的告诉题主 还有那个 &a data-hash=&cbd9d2ae81e1ef2de233& href=&///people/cbd9d2ae81e1ef2de233& class=&member_mention& data-editable=&true& data-title=&@李航楠& data-tip=&p$b$cbd9d2ae81e1ef2de233&&@李航楠&/a&,100w在线的直播视频毫无问题,无非就是视频cdn, 现在视频cdn同步也就在1-2s内完成了,所以观众看到的是cdn的内容,有轻微延迟,如果是录播,连延迟的问题都无所谓了。&br&&br&但这里 还有弹幕的需求, qt被弹慕弹死那是另外一个问题,不属于题主问题的一部分, 也许 qt没有遇到过如此量大的弹幕,没有针对性的优化,其次即便服务器100w的弹幕搞定,客户端也不一定有带宽接受那么多弹幕,有那么多cpu资源渲染,导致卡顿?都需要特别情况下特别优化。&br&&br&但不管咋样,仅仅 视频(录播)直播,100w完全可以做到。
虽然我不是专业搞视频直播(录播?)技术的,我也不知道 腾讯出了什么问题, 但我可以负责任的告诉题主 还有那个 ,100w在线的直播视频毫无问题,无非就是视频cdn, 现在视频cdn同步也就在1-2s内完成了,所以观众看到的是cdn的内容,有轻微延迟,如…
1. 建议看protobuf io 模块下zerocopystream实现,可以参考以减少额外的数据copy动作。&br&&br&2. 不要自己写内存池,引入一些第三方库,例如tcmalloc等&br&&br&能做到以上两点,基本上就够用了。
1. 建议看protobuf io 模块下zerocopystream实现,可以参考以减少额外的数据copy动作。2. 不要自己写内存池,引入一些第三方库,例如tcmalloc等能做到以上两点,基本上就够用了。
已有帐号?
社交帐号登录
无法登录?
社交帐号登录
3543 人关注
310 个回答
2227 人关注
189 人关注
181 个回答
339 人关注
121 人关注

我要回帖

更多关于 bit.do 的文章

 

随机推荐