一开始,我得向Libuv库和Libuv库开发者以及相关粉丝们道一个歉,对不起,我错怪你们了。深深感到自己的无知,是多么羞愧的事情!!
事情的经过是这样的。 原先按照公司要求,我在开发Windows版的TCP服务器时,使用了Libuv库。正是因为Libuv库的强大,才让我们老大推荐使用。我们老大学识渊博,阅历丰富,他的推荐自然也是很值得使用的。所以我快速学习了一下Libuv库的使用。然后再学习的过程中,稍有了解。同时发现了一个网友phata写的对于Libuv库的包装,让代码写起来更加方便。当然,他是针对Windows版的包装。我用了之后,也就大大加快了开发的速度。对此,我非常感谢网友phata。也正是这些网友的无私,将一些宝贵的代码分享出来,才促进了开发的发展,让学习开发变得容易。所以我一直坚持分享的习惯,也正是更多是受益于各路网友的分享,我学有所成,我也希望将我的经验和成果分享给更多人。互联网的共享互助精神大概如此吧。C++技术网就是我分享我所有经验的平台,希望更多人能够参与进来吧。 Windows版的服务器做好之后,后来又需要Linux版的服务器。所以,直接将libuv使用在了Linux的Centos发行版上了。phata编写的Windows版本libuv封装类,我进行了精简整理,发布在C++技术网。然后我再将这个精简后的版本,改成了Linux版本,并应用在了Linux版的服务器上。Linux版的Libuv封装类的代码见《》。在这个文章里,你可以找到其他相关的代码。 然而好景不长,在后续的测试中发现了一个问题:客户端发送一个数据到服务器后,服务器单次回复一次数据,一切正常。但是收到一个数据,连续回复两次数据时,不管是间隔1秒还是10秒,都会造成线程死循环。这个问题持续了很久,而且只在Linux中表现出来。 迟迟没有直接解决问题,所以后来就想到一个办法,就是将多个数据合并到一个数据,然后将多次发送做成了一次发送,这样就避开了问题。然而再后来出现的需求,让合并数据成为了不可能。两次发送数据,是两个线程完成的。但是有时候可能合并得到一起,有时候无法合并到一起,因为我还是想利用之前避开问题的方法来实现,结果效果很不理想。 所以,在最开始出现连续两次发送数据造成死循环的时候,我将我上层的业务代码全部干掉,直接写测试代码,结果发现一样会出现死循环。这样之后,我就认定是Libuv的坑了。所以后来就只有饶坑了,心情很是不爽。 按照其他同事的说法,Libuv是nodejs使用的,应该不会出现这么低级的问题吧。其实我也觉得不应该出现这么低级的问题,然而这个问题就在这,我都不知道为什么。只能先将锅甩给了libuv。 当后面的需求,无法绕过去的时候,还是要直接面对这个坑的问题。怎么办呢?那就只能学习和深入研究源码了。最要命的是,Libuv的资料太少了,就有那么一本英文书,网络有人正在翻译为中文,还没有翻译完。而且这个书也不是那么全面,至少我读了之后,还是没有完全明白的意思,懵懵懂懂的。除了这个,基本上没有比较深入的资料了。要么是一点学习笔记,写了一个demo,无关痛痒。 正是因为Libuv文档太少了,让学习Libuv变得困难,出现问题都无从查询资料。而源码,也不是谁都能够看懂的。我也不愿意去钻研源码,如果能够解决问题,绝不研究源码。如果是对源码本身感兴趣,那也是闲暇的时候研究,而工作比较紧张,没有那么多时间。 事情已经进行到了必须面对问题的时候,所以我就开始再从仅有的少数资料里和代码里研究问题。然后也加了一个QQ群,群也就3个。对于示例代码的一个简单的问题,一个群友竟然说要500RMB才肯解答,说他研究了2年了。哎~ 我自己继续研究好了。然后不断的调试代码,分析代码的流程,这次是直接使用libuv的测试代码研究,通过熟悉代码,测试,然后竟然成功的实现了连续两次服务器回复命令。2017年6月3日上午,实现了一个版本。然后晚上,又实现了另外一个版本。第一个版本比较凑合,第二个版本最接近于我使用的版本,也就是前面提到的改成Linux下的libuv包装类,其实和示例代码差不多。在这个示例测试中,直接连续两次发送数据,和项目中的问题一样。然后通过不懈的努力,然后成功实现了连续两次发送数据,依然正常运行。
到现在为止,我才真正明白我之前的问题所在了。问题不在libuv,也不在于网友phata的Windows版的libuv包装类,而是在于我改成linux版的libuv包装类。我忽略的一点就是,libuv在Windows上使用的是完成端口,而在linux上使用的是异步事件epoll。两者是不一样的,所以在改成linux版libuv包装类的时候,我没有做好处理,只是简单的改了一下,忽略了底层实现的差异,才出现了这个问题。所以在Windows上没有问题,在Linux有问题。我竟然直接根据这个判定libuv有这样一个低级的坑!可见我是多么无知。
所以我总结一句话:完全相信权威,那是迷信;而不深入调查,仅根据表明现象就直接否定权威,那是无知!! 我们经常听说不要完全相信权威,要敢于质疑权威,但是很多时候,我们却不知道,质疑权威应该如何质疑。正确的质疑是用实践去证明,用合理的证据证明权威是错的。而我这个行为,是没有经过深入的调查研究的,所以是无知的表现。还好,有这机会让我直接面对问题,让我查出问题的原因,让我反省,让我矫正自己的态度。写下这篇文章,记录一下此时我的无知,在今后的研究路上,多一份谦逊,多一份研究,少一点无知,也用以警告我自己,不要随意下定论。
注:Linux版本的libuv包装类,你还是可以使用的,只是不要对一个请求回复多个命令。一对一的回复,这个包装类是可以用的。后面我再想办法改进,修复这个问题。所以分享的那个代码是可以用,只是要注意这个问题。