原文链接:https://my.oschina.net/chrisforbt/blog/1669746

一、应用背景

去年公司成立了个项目——《智慧用电安全隐患监管服务平台》,计划是开发一款设备,能够安装在电箱里面,用于实时监控电线的温度、漏电、电流、烟雾等信息。如果检测到有问题,那么就马上发送推送到手机和PC web,同时也有短信通知和电话语音通知。当时听到这个项目,笔者是觉得十分有意义的,毕竟没有比人命更珍贵的东西了。如果能够做出这样一个系统,让人们不用再担心生活中的火灾威胁,那绝对是功德无量。

二、架构设计

仔细分析了这个系统之后,服务器需要实现的功能如下:

1、接收前端设备发送过来的数据;

2、解析采集数据,根据数据状态做不同的处理(如存储、报警、推送等等);

3、提供APP和WEB PC 相应的数据API;

4、接受APP和WEB PC端的控制指令,往相应的设备发送指令。

由于设备采集和业务逻辑两部分需要的硬件条件不一样:采集端的业务简单,不需要耗那么多内存和CPU,但会比较耗端口号;业务逻辑需要耗内存和CPU,端口号问题可以通过负载均衡解决。所以避免互相干扰,就决定把这两部分分开来。

基于第4点,需要APP和PC WEB实时控制设备。用UDP协议的话可能会丢包,而且需要设备时不时唤醒一下,更新下状态,避免IP变了控制不到。那么要用UDP来保证控制的实时性,可能比较高难度。于是便选用TCP。

那么架构设计目前就是:TCP服务器接收前端采集数据,通过内网发送给业务逻辑服务器处理。APP和PC WEB发送控制指令给业务逻辑服务器,先找到对应的设备TCP连接,然后通知TCP服务器将控制指令下发给设备。

二、选择框架

由于市面上有很多现成框架,所以笔者也不打算重复造轮子(之前造过,性能不怎么高,凑合能用)。基于前期一直从事C/C++开发,脚本语言也只会lua、shell。所以这次选择框架,首先就从C/C++入手。那么为什么会选择HP-Socket呢?当时Google出来是一堆的,唯独HP-Socket是被贴上了“国产优秀网络通信框架”和“国内最火的开源项目”,接着便去研究了下。经过一个星期的实验,发现实在是非常强大,便决定用HP-Socket来做TCP服务器了。

三、开发环境

硬件环境:双核2.36GHz CPU/4G内存/50G硬盘/4M带宽 PC机

软件环境:64位Windows Server2012R2、VS2017、HP-Socket 4.3.1

四、技术细节

1、数据解析

前端采集数据将数据打包为C结构体,然后通过2G网络发送给服务器。TCP接收数据的时候,无可避免的一个问题便是粘包。网络传输过程中,数据包超过某长度会MTU分片(具体可参考:https://blog.csdn.net/singular2611/article/details/52513406)。那么服务器接收到的一个包,可能是一个完整包、半个包或者一个半包,还好贴心HP-Socket作者已经帮我们考虑好,有3种接收模型可选:PACK、PULL和PUSH模型(全自动、半自动和手工解决粘包问题)。笔者的通信数据结构有多种,于是便选择了PULL(半自动)模型。每次先 PEEK,如果够一个完整包便提取出来,不够则等待下次OnReceive触发。

2、数据处理

基本上所有业务逻辑都靠OnReceive这个事件触发,所以OnReceive里面如果有耗时操作,那么将会严重影响整个系统的性能。笔者之前曾经在OnReceive发起了Http请求,当并发量到200时,直接就不能用了。

所以这里推荐业务逻辑尽量另外开线程处理,也尽量不要在OnReceive中使用公共变量(锁会降低效率)。因为HP-Socket给每个连接分配了个extraData,利用这个特性可以解决很多问题了。业务线程的触发,笔者用的是无锁队列。OnReceive负责生产数据,然后往无锁队列中填充,业务线程读取无锁队列时,如果没数据则阻塞,有数据则一次性取出(最好也限制下大小,那样CPU不会忽高忽低)。

从无锁队列取出的数据就可以处理后发送给业务逻辑服务器了。

3、数据发送

数据发送部分,笔者刚开始是使用http协议,直接把数据POST给业务逻辑服务器。HP-Socket框架自带的http协议接口,当时笔者没有使用对,导致很多问题,尤其是内网连接不上,于是便换成libcurl了(http client的杠把子,十分给力)。但这样会造成一个问题,便是每次http请求都是短链接,系统不可避免地产生了很多TIME_WAIT。当TIME_WAIT个数达到16384时,整个系统就瘫痪了,得要等2ML后才恢复(随后又堵)。所以这个方案只能撑一时,不能撑一世。

由于笔者的业务逻辑服务器是Linux系统,刚刚好HP-Socket的Linux版面世,马上拿来写了个数据接收服务器,作为采集端和业务逻辑端的缓冲层。采集服务器的数据直接通过TCP发送给缓冲层,那么TIME_WAIT问题就不复存在了。缓冲层将数据存储在内存数据库中,并通知业务逻辑服务器去处理,稳稳的幸福。

五、困难与解决过程

1、HP-Socket入门问题

估计这个问题是大多数人都会遇到的,文档比较粗糙,群里面的大牛面对新手们无限重复的简单问题也懒得回答,怪兽大大喜欢发吴莫愁,Demo只有MFC版本,编译不过去等等问题。笔者当时也花了几天时间才编译过去,毕竟之前一直用vim,都是用gcc和makefile,VS2017不熟悉,所以会出现这样那样的问题。

文档虽然粗糙,但是确实还是挺有用的,尤其是最后的QA,笔者看了6遍后才成功把自己想要的信息提取出来,相信HP-Socket的普及面广了之后会出份详细文档。

新手们提问题时建议把问题捋好,如“HP-Socket怎么编译”之类的问题就不要问了,不是大牛不回答,是很难回答,大家都要工作生活,时间真的不多。

除了文档,Demo代码也是很有参考价值,笔者没有开发过MFC,有的Demo也没编译过去,但是要相信作者们发布出来肯定是正确的(出了问题肯定是自己没用对),看思路就好。

2、服务器性能问题

HP-Socket的性能是毋庸置疑的了,如果服务器性能不高,建议从以下几点入手:

a)、OnReceive里面是否有阻塞操作;

b)、HP-Socket是IOCP服务器,所以一般CPU的使用率都很低,跑简单逻辑估计就3~5%的使用率。如果CPU使用率很高,就要看看代码复杂部分是否有bug;

c)、如果服务器有HTTP client的逻辑,要看看TIME_WAIT的数量(Windows指令:netstat -ano | findstr "TIME_WAIT" | find /C "端口号"),一般系统TIME_WAIT到达16384个就满了,没有多余的端口能够往该端口号发送数据;

d)、如果内存涨得比较快,而且不降,那么就要考虑内存泄露问题了,但良好的编程习惯一般不会导致内存泄露问题。这时候要检查代码中的慢I/O操作(也就是耗时操作),慢I/O操作处理不善,容易导致生产速度大于消费速度,那么内存就会一直堆上去了。

六、总结

使用HP-Socket这半年多时间,除了刚刚开头入门的难度高,后面给笔者带来的是无尽的惊喜,其效率与稳定性完全适合物联网之类的项目。比如说在今年春节,公司尚未招到运营,那么维护服务器的工作就落在笔者身上,而作为一名热爱生活的开发者,春节肯定选择去嗨。晾了服务器一个月,怀着忐忑不安的心理看了下服务器监控,只能用“稳如狗”来形容了。CPU一直在10%~15%间波动,内存维持在1500Mb,内网传输曲线与外网如带宽的一致,如下图所示:

图1 7天CPU监控图

图2  7天内存监控图

图3 7天内网带宽监控图                                      图4 7天外网带宽监控图

笔者没有发布各种服务器性能测试之类的报告,因为这些一般人都很难懂,不利于服务器推广,只能用最简单的言语表达下笔者对HP-Socket的喜爱,如有不妥之处,求轻拍。

——蔡剑彬(caijianbin668943@163.com)    热爱生活的架构师

浅谈HP-Socket在物联网的应用的更多相关文章

  1. 浅谈C#Socket

    好不容易把socket通信搞懂一点,比较喜欢做笔记,嘿嘿~ 希望共同学习,共同进步! socket通信是C#中非常基础的一个知识点,我这里用到的是基于Tcp协议的socket通信.Tcp会有三次握手连 ...

  2. 浅谈tcp socket的backlog参数

    最近看netty源码碰到ChannelOption.SO_BACKLOG参数,通过跟踪代码发现其实是用于设置底层tcp socket的backlog参数,由于不了解这个参数,有必要彻底的理解一下. 底 ...

  3. 浅谈android Socket 通信及自建ServerSocket服务端常见问题

    摘  要:TCP/IP通信协议是可靠的面向连接的网络协议,它在通信两端各建立一个Socket,从而在两端形成网络虚拟链路,进而应用程序可通过可以通过虚拟链路进行通信.Java对于基于TCP协议的网络通 ...

  4. [转]浅谈Flash Socket通信安全沙箱

    用过Flash socket的同学都知道,Flash socket通讯有安全沙箱问题.就是在Flash Player发起socket通信时,会向服务端获取安全策略,如果得不到服务端响应,flash将无 ...

  5. 浅谈Socket编程

    浅谈Socket编程 说到Socket,想必大家会觉得陌生又熟悉.许多同学听说过Socket,但仅仅知道它翻译成中文叫做套接字,除此之外似乎并没有太多的了解了.那么今天我就来抛砖引玉地聊一聊Socke ...

  6. 浅谈IM软件怎样建立安全socket连接、登录

    ----------------------------------------------------欢迎查看IM软件业务知识<专栏>-------------------------- ...

  7. 浅谈JAVA中如何利用socket进行网络编程(二)

    转自:http://developer.51cto.com/art/201106/268386.htm Socket是网络上运行的两个程序间双向通讯的一端,它既可以接受请求,也可以发送请求,利用它可以 ...

  8. [nRF51822] 14、浅谈蓝牙低功耗(BLE)的几种常见的应用场景及架构(科普类干货)

    蓝牙在短距离无线通信领域占据举足轻重的地位—— 从手机.平板.PC到车载设备, 到耳机.游戏手柄.音响.电视, 再到手环.电子秤.智能医疗器械(血糖仪.数字血压计.血气计.数字脉搏/心率监视器.数字体 ...

  9. TODO:浅谈pm2基本工作原理

    TODO:浅谈pm2基本工作原理 要谈Node.js pm2的工作原理,需要先来了解撒旦(Satan)和上帝(God)的关系. 撒旦(Satan),主要指<圣经>中的堕天使(也称堕天使撒旦 ...

  10. 【转】Android Canvas的save(),saveLayer()和restore()浅谈

    Android Canvas的save(),saveLayer()和restore()浅谈 时间:2014-12-04 19:35:22      阅读:1445      评论:0      收藏: ...

随机推荐

  1. 架构师技能树skill-map

    # 架构师技能树 ## 系统架构能力 ### 基本理论- 扩展性设计- 可用性设计- 可靠性设计- 一致性设计- 负载均衡设计- 过载保护设计 ### 协议设计- 二进制协议- 文本协议 ### 接入 ...

  2. Sublime 代码段设置

    # Sublime 代码段 > 依次找到:Tools -> Developer -> New Snippet,默认代码段配置文件如下: <snippet><cont ...

  3. PAT甲级——A1143 LowestCommonAncestor【30】

    The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U ...

  4. PHP中global与$GLOBALS的区别

    单一个global是一个关键字,通常附加在变量前,用于将变量声明至全局作用域: $GLOBALS是预定义的超全局变量,把变量扔到里边的话一样可以带到全局去. $GLOBALS 是一个关联数组,每一个变 ...

  5. Cocos2d-x的Android配置以及相关参考文档

    关于Win7下配置Coco2d-x的Android开发环境,可以参考子龙山人的博客:Setting Up Cocos2d-x Android Development on Win7,这篇文章写得很详细 ...

  6. sass揭秘之@mixin,%,@function scss基本使用及操作函数

    sass揭秘之@mixin,%,@function: 地址:https://www.w3cplus.com/preprocessor/sass-mixins-function-placeholder. ...

  7. Spring Cloud动态刷新配置信息

    有时候在配置中心有些参数是需要修改的,这时候如何不重启而达到实时生效的效果呢? 添加依赖 <dependencies> ... <dependency> <groupId ...

  8. PHP正则表达式中的反斜线

    PHP反斜线再正则表达式中的使用 <?php $str = 'hello\world'; $pattern = '/hello\\\\world/'; preg_match($pattern,$ ...

  9. mongo import excle

    mongoimport --host 192.*******.** --db **  --collection **  --type csv --headerline --file /*****.cs ...

  10. Java技术专区-虚拟机系列-虚拟机参数(常用)

    基础参数系类(内存分配) -server:一定要作为第一个参数,在多个CPU时性能佳 -Xmn:young generation的heap大小,一般设置为Xmx的3.4分之一-Xms:初始Heap大小 ...