一开始,我得向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(转)的更多相关文章

  1. 从今天起,正式步入cnblogs,向曾经的脚印说声对不起!

    步入这个行业也好多年了,从来没有定居过一个地方. 看过很多前辈们留下的资料,对后者门(其中还有我)留下很多珍贵的东西. 所以,我要向前辈学习,壮大自己,在学习的同时,不要忘记帮助别人. 对曾经我留下的 ...

  2. linux下libuv库安装教程

    下载并编译libuv libuv需要自己手动下载源码,并手动编译. 当前目录为:/home/xlz/test/github,在后面,会用$PATH来代替,我的系统的Debian8,64bit. $gi ...

  3. 网络开发库从libuv说到epoll

    引言 这篇博文可能有点水,主要将自己libuv的学习过程和理解. 简单谈方法. 有点杂. 那我们开始吧. 首先介绍 githup . 这个工具特别好用. 代码托管. 如果不FQ可能有点卡. 但是应该试 ...

  4. Microsoft Visual Studio 2017 编译最新版 libuv 1.x

    步骤很简单 1 下载最新版的 libuv(地址:https://github.com/libuv 2 安装Git,Python 2.7 ,cmake(这里使用的是 3.11.0-win64-x64 版 ...

  5. 简单对比 Libevent、libev、libuv

    Libevent.libev.libuv三个网络库,都是c语言实现的异步事件库Asynchronousevent library). 异步事件库本质上是提供异步事件通知(Asynchronous Ev ...

  6. 报错libtest: error while loading shared libraries: libuv.so.1: cannot open shared object file: No such file or directory

    使用g++编译.运行libuv的demo错误解决 我们通过例子来讲述监视器的使用. 例子中空转监视器回调函数被不断地重复调用,  通过例子我们也可以了解到: 由于设置了监视器, 所以调用 uv_run ...

  7. 浅析libuv源码-编译启动

    面试的间隙回头复习了一下node,感觉node就像一个胶带,把V8和libuv粘在了一起. V8毫无疑问,负责解析执行JavaScript,相当于语言层面的桥梁:而libuv则是负责操作系统底层功能的 ...

  8. libuv 简单使用

    libuv 简单使用 来源:https://zhuanlan.zhihu.com/p/50497450 前序:说说为啥要研究libuv,其实在很久之前(大概2年前吧)玩nodejs的时候就对这个核心库 ...

  9. libuv之介绍

    本人是在研究linux下socket TCP/IP通讯时,用到了一些linux下的API,比如socket, connect, bind,listen, accept等等,简单写个点对点的通讯,直接用 ...

随机推荐

  1. 【移动开发】startForeground()让服务保持前台级别

    最近在使用android 4.1系统的时候,发现在手机休眠一段时间后(1-2小时),后台运行的服务被强行kill掉,有可能是系统回收内存的一种机制,要想避免这种情况可以通过startForegroun ...

  2. Runtime系列(一)-- 基础知识

    众所周知,Objective-C 是一种运行时语言.运行时怎么来体现的呢?比如一个对象的类型确定,或者对象的方法实现的绑定都是推迟到软件的运行时才能确定的.而运行时的诸多特性都是由Runtime 来实 ...

  3. 剑指Offer——动态规划算法

    剑指Offer--动态规划算法 什么是动态规划? 和分治法一样,动态规划(dynamic programming)是通过组合子问题而解决整个问题的解. 分治法是将问题划分成一些独立的子问题,递归地求解 ...

  4. JAVA之旅(三十一)——JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件

    JAVA之旅(三十一)--JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件 有段时间没有更新JAVA了,我们今天来说一下JAVA中的图形化界面,也就是GUI ...

  5. iOS中 Swift初级入门学习(一)

    / // Copyright (c) 2015年 韩俊强. All rights reserved. // import Foundation // Swift当中的输出函数 // println S ...

  6. 并发编程(二):分析Boost对 互斥量和条件变量的封装及实现生产者消费者问题

    请阅读上篇文章<并发编程实战: POSIX 使用互斥量和条件变量实现生产者/消费者问题>.当然不阅读亦不影响本篇文章的阅读. Boost的互斥量,条件变量做了很好的封装,因此比" ...

  7. 【一天一道LeetCode】#101. Symmetric Tree

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...

  8. iOS中 读取相册,调用系统相机 技术分享

    技术内容:分别读取相册以及调取相机,将图片显示到imageView上 布局: 1.创建imageView 和 button 并为button一个关联pickerImage的事件 <div sty ...

  9. pig的grunt中shell命令不稳定,能不用尽量不用

    shell命令:mv a b   将文件a改名为b, 可如果b已经存在,比如/test文件下有a和b两个文件,执行mv a b后,b被覆盖的了.也就是/test文件下只有a. 但是mv命令在pig的g ...

  10. Css技术入门笔记01

    在学习html的时候,html中的标签都具备了特定功能,或者含义,以及相应的样式效果.可是在有些时候我们可能仅仅希望使用 html标签把要显示的数据封装起来,而不需要任何的样式效果.这时就需要单独的标 ...