我应该跟libuv说声对不起,我错怪了libuv(转)
一开始,我得向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封装类的代码见《基于libuv封装的TCP通信类-服务端类源代码》。在这个文章里,你可以找到其他相关的代码。
然而好景不长,在后续的测试中发现了一个问题:客户端发送一个数据到服务器后,服务器单次回复一次数据,一切正常。但是收到一个数据,连续回复两次数据时,不管是间隔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包装类,你还是可以使用的,只是不要对一个请求回复多个命令。一对一的回复,这个包装类是可以用的。后面我再想办法改进,修复这个问题。所以分享的那个代码是可以用,只是要注意这个问题。
我应该跟libuv说声对不起,我错怪了libuv(转)的更多相关文章
- 从今天起,正式步入cnblogs,向曾经的脚印说声对不起!
步入这个行业也好多年了,从来没有定居过一个地方. 看过很多前辈们留下的资料,对后者门(其中还有我)留下很多珍贵的东西. 所以,我要向前辈学习,壮大自己,在学习的同时,不要忘记帮助别人. 对曾经我留下的 ...
- linux下libuv库安装教程
下载并编译libuv libuv需要自己手动下载源码,并手动编译. 当前目录为:/home/xlz/test/github,在后面,会用$PATH来代替,我的系统的Debian8,64bit. $gi ...
- 网络开发库从libuv说到epoll
引言 这篇博文可能有点水,主要将自己libuv的学习过程和理解. 简单谈方法. 有点杂. 那我们开始吧. 首先介绍 githup . 这个工具特别好用. 代码托管. 如果不FQ可能有点卡. 但是应该试 ...
- Microsoft Visual Studio 2017 编译最新版 libuv 1.x
步骤很简单 1 下载最新版的 libuv(地址:https://github.com/libuv 2 安装Git,Python 2.7 ,cmake(这里使用的是 3.11.0-win64-x64 版 ...
- 简单对比 Libevent、libev、libuv
Libevent.libev.libuv三个网络库,都是c语言实现的异步事件库Asynchronousevent library). 异步事件库本质上是提供异步事件通知(Asynchronous Ev ...
- 报错libtest: error while loading shared libraries: libuv.so.1: cannot open shared object file: No such file or directory
使用g++编译.运行libuv的demo错误解决 我们通过例子来讲述监视器的使用. 例子中空转监视器回调函数被不断地重复调用, 通过例子我们也可以了解到: 由于设置了监视器, 所以调用 uv_run ...
- 浅析libuv源码-编译启动
面试的间隙回头复习了一下node,感觉node就像一个胶带,把V8和libuv粘在了一起. V8毫无疑问,负责解析执行JavaScript,相当于语言层面的桥梁:而libuv则是负责操作系统底层功能的 ...
- libuv 简单使用
libuv 简单使用 来源:https://zhuanlan.zhihu.com/p/50497450 前序:说说为啥要研究libuv,其实在很久之前(大概2年前吧)玩nodejs的时候就对这个核心库 ...
- libuv之介绍
本人是在研究linux下socket TCP/IP通讯时,用到了一些linux下的API,比如socket, connect, bind,listen, accept等等,简单写个点对点的通讯,直接用 ...
随机推荐
- UNIX网络编程——TCP带外数据小结
带外数据概念实际上时向接收端传送三个不同的信息:(1)发送端进入紧急模式这个事实.接收进程得以通知这个事实的手段不外乎SIGURG信号或select调用.本通知在发送进程发送带外字节后由发送端TCP立 ...
- linux内核cfs浅析
linux调度器的一般原理请参阅<linux进程调度浅析>.之前的调度器cfs之前的linux调度器一般使用用户设定的静态优先级,加上对于进程交互性的判断来生成动态优先级,再根据动态优先级 ...
- Docker教程:docker machine的配置和命令
http://blog.csdn.net/pipisorry/article/details/50921335 安装virtualbox 如果要使用virtualbox,首先要安装virtualbox ...
- Request中Attribute 和 Parameter 的区别
Attribute 和 Parameter 的区别 (1)HttpServletRequest类有setAttribute()方法,而没有setParameter()方法 (2)当两个Web组件之间为 ...
- ROS_Kinetic_21 使用Qt Creator Plug in即ros_qtc_plugin
更为详细版本请参考: http://blog.csdn.net/zhangrelay/article/details/52214411 结合看更为具体. 首先,先上原版参考: 1 http://wik ...
- hashmap简单实例(个人使用经验)
一.HashMap<int,String>是错误的:因为int是基本类型,而key和value要求是对象,所以要用Integer而不是int.HashMap<String,Objec ...
- 【嵌入式开发】 Bootloader 详解 ( 代码环境 | ARM 启动流程 | uboot 工作流程 | 架构设计)
作者 : 韩曙亮 博客地址 : http://blog.csdn.net/shulianghan/article/details/42462795 转载请著名出处 相关资源下载 : -- u-boo ...
- (六十五)iOS的socket实现(GCDAsyncSocket)
本文介绍使用GCDAsyncSocket来实现iOS端的socket,有关简易服务端的代码已经在上一篇文章中提到,这里不再赘述,将直接介绍如何实现客户端. 首先下载CocoaAsyncSocket框架 ...
- SQL Server扫盲系列——镜像篇
为方便查看,并以专题形式展示,所以我会把一些文章整合起来.本部分为SQL Server镜像系列: 本文出处:http://blog.csdn.net/dba_huangzj/article/detai ...
- 【Unity Shaders】Reflecting Your World —— Unity3D中简单的Cubemap反射
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...