我应该跟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等等,简单写个点对点的通讯,直接用 ...
随机推荐
- hbase 程序优化 参数调整方法
hbase读数据用scan,读数据加速的配置参数为: Scan scan = new Scan(); scan.setCaching(500); // 1 is the default in Scan ...
- Linux系统编程---守护进程
守护进程是什么?就是在后台运行的进程. 那么如何创建守护进程呢? 1. 创建孤儿进程 2. setsid() 创建进程会话 3. 重定向标准输入, 标准输出 4. chdir, 改当当前进程的工作目录 ...
- Socket接收器——Acceptor
Acceptor是JIoEndpoint的内部类,主要的职责就是监听是否有客户端套接字连接并接收socket,再将socket交由任务执行者(Executor)执行.不断从系统底层读取socket,接 ...
- 安卓一键分享到qq,微信,微博,官方SDK非第三方
当我们项目中需要集成分享功能时,我们通常会采取一下几个办法: 1.调用系统自带分享 优点:简单快速,几行代码搞定,不需添加任何额外包: 缺点:系统会调出手机内部所有带分享功能的APP,且界面风格跟随系 ...
- 数据库再设计(Database Redesign)
数据库设计有三个来源:(1)可以从现有数据开始设计数据库,例如从excel表格等,这种模式下需要考虑的问题是数据的normalization,最终通常将数据转化为BCNF范式:(2)设计新的数据库,这 ...
- Linux下jetty报java.lang.OutOfMemoryError: PermGen space及Jetty内存配置调优解决方案
Linux下的jetty报java.lang.OutOfMemoryError: PermGen space及Jetty内存配置调优解决方案问题linux的jetty下发布程序后再启动jetty服务时 ...
- js对象、构造函数、命名空间、方法、属性
<script language="javascript"> var myNameSpace = new Object(); //构造一个命名 空间myCla ...
- 使用C#+socket实现用移动设备控制的虚拟手柄
近期在和同学玩死神vs火影,以怀念小时候,突然觉得用键盘玩的不够畅快,因此萌生了写一个虚拟手柄的念头. 我的思路是在移动设备(iOS.Android)上实现手柄,在电脑上监听,利用socket建立持久 ...
- UNIX环境高级编程——system V消息队列
unix早期通信机制中的信号能够传送的信息量有限,管道则只能传送无格式字节流,这远远是不够的. 消息队列(也叫报文队列)客服了这些缺点: 消息队列就是一个消息的链表. 可以把消 ...
- Chapter 2 User Authentication, Authorization, and Security(2):创建登录帐号
原文出处:http://blog.csdn.net/dba_huangzj/article/details/38705965,专题目录:http://blog.csdn.net/dba_huangzj ...