定时器(timer)与时间轮(timewheel)

1 定时器(timer) 1.1 定时器使用场景 通常,定时是系统一个比较常用的事件。定时器要解决的问题是,隔一定时间(short-one)或者每隔一段时间(repeated)触发一个定时事件。 无论是系统还是应用,都会用到定时功能,例如, 系统层面: 屏幕刷新,TCP等 应用层面: 网络库实现的定时功能比如libuv 1.2 应用层定时器 应用层的定时通常有几种方式: 可以在某个循环(比如Windows GetMessage, DispatchMessage后面)判断时间,通常循环里可能会sleep一下,或者有类似poll,wait之类的超时设置; 借助操作系统提供的timer函数(POSIX timer函数或者windows timer消息),或者系统提供的定时任务如crond; 利用poll相关函数,借助timerfd等(linux); 数据结构方面,可以使用链表或者堆。 1.3 系统层定时器 系统定时器有低分辨率定时器,也有高分辨率定时器。 低分辨率定时器一般为毫秒级,典型分辨率为4毫秒。通常采用timer wheel实现。 高分辨率定时器可以达到纳秒级。通常采用红黑树实现。 底层使用时钟硬件(如HPET)提供的时钟中断来提供tick。 2 时间轮(timewheel) timewheel思想十分简单。想象我们的时钟,分辨率为秒,能实现从1秒到43200(12*60*60)秒的定时。然而定时轮并不需要12*60*60大小的数组,只需要用到12+60+60=132个大小的数组。 3 参考 《Professional Linux Kernel Architechure》

基于java nio的server设计

最近由于业务需要,写了一个 java server用来与我们的游戏服务器实现交互。 server只实现了最基本的功能: 维护多个长连接,发送与接收消息;连接建立及断开(主动与被动)。 在实现的过程中,最有意思的是java nio里的buffer,但我认为这是一个失败的设计。 java nio buffer三个主要的属性,position, limit, capacity. 通常来讲,传统的ringbuffer都会有一个read index和write index, 但buffer nio将两者统一为postion,然后弄出了读写模式切换的概念。 当从buffer里取出数据,即buffer.getXXX或者channel.write(buffer), 当往buffer里放入数据,即buffer.putXX或者channel.read(buffer), 的前后,经常要考虑模式的切换,比如调用flip,这样的设计增加了复杂性,对库的使用者带来困难(笔者才疏学浅,一直疑惑他们为什么这么设计,求高人指教),这本质上是因为position属性既要当作readindex来使用,又要当作writeindex来使用。 另外一点就是由于postion的大小不能超过limit和capacity, 导致使用的过程中经常需要compact, 每次compact会导致额外的内存拷贝;传统的ringbuffer会在writeindex < readindex在的时候才可能涉及到额外内存的拷贝。 也难怪,netty里抛弃了这种设计。

关于shadowsocks

平时其实很少使用VPN,多是Mac上SSH+Socks代理,Windows上就myentunnel+Socks代理。近来工作原因,手机上需要VPN才用的较为频繁,然而最近经常不好使了,  换了几个,一直都不太稳定,原因嘛你懂的。 于是在自己国外的VPS上搭建了一个VPN,用的是shadowsocks搭建的服务器. 客户端的话Mac,  Android , Windows应该都有免费的,iPhone上现在要花16元。 搭建好,用的是443端口。一天之后,发现不行了,然后换了个端口,现在已经流畅运行好几天了,很开心:) 一般的翻墙,通过设置浏览器http代理或者socks (5)代理就可以了。shadowsocks显然做的更多。 出于习惯,想了想这个自己弄应该怎么实现。去看了下代码,服务端用的python,几千行代码挺简洁的; 客户端需要解决的问题复杂些, 涉及到TCP/IP协议栈。

CURLOPT_POSTFIELDSIZE Post

最近用libcurl向某商web服务器作登录校验踩了一坑。 事情的表象是这样的,在windows上没有问题,linux上投递过去的数据乱码。但是如果将curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data)中的data写死,即写成字符串常量,也是没有问题的。 开始以为一些参数和环境的问题,查了半天问题依旧,才怀疑到变量生存周期的问题,将data生命期拉长,就好了。

水坑装水问题

题目在这里: 原文:http://qandwhat.apps.runkite.com/i-failed-a-twitter-interview/ 译文:http://blog.jobbole.com/50705 起初也是想到先求Max,这需要一次遍历;然后从左边到Max,同时右边到Max,这次遍历一共包含两个子遍历。因此一共是两次遍历。 历史总是惊人的相似,一次遍历的方法我也是早上躺在床上完成的:比较左指针和右指针指向的值,选取大的做为Max, 同时不停的移动指针,如果碰到更大的Max,调整基准即可。 这道题目没有什么高深的算法,但思维的过程还是挺有趣的。