一、本人设想的TCP服务器有如下特性:

1.启动服务,一直监听端口。

2.有新连接(客户端)就通知用户。并把连接接收到的数据回调给用户。

3.客户端连接上后用户可在任意时间发送数据给它。

4.客户端断开时关闭或用户可手动关掉。

以上操作都可以不同线程在完成。

二、使用libuv遇到的问题

由于对libuv不熟悉+其文档,调用其函数时吃了不少苦头。

1.libuv的特性

libuv是基于event驱动的,当调用uv_run后就会一直启动event循环,阻塞其线程(event loop thread)直到没有事件了uv_run返回。除了uv_async_send函数外,其他函数都是非线程安全的。即其他函数只能在event loop thread里调用,在其他线程调用libuv不保证其正确性。

libuv处处回调,多数有回调的函数都是直到回调函数被触发时才算调用完成,而非该函数返回就算调用完成。

2.遇到的问题

libuv的这点特性对于我想通过多线程调用tcp sever中的不同操作是一大麻烦事。

2.1.我在另一线程里调用了uv_write发送数据,结果总提示Assertion failed: handle->write_queue_size >= req->queued_bytes, file src/win/tcp.c

最后在google group( https://groups.google.com/forum/#!msg/libuv/iHzv3x-VOr4/KzhJymI6lRkJ )中找到方法:

内部开辟一线程用于发送数据。用户调用发送函数时把数据压入队列,发送线程从队列中循环取数据,然后调用uv_async_send触发真正的发送数据函数。数据参数可以通过uv_handle_t.data传输。可用uv_sem_wait/ uv_sem_post来控制数据发送先后。

2.2.对于想要关闭一个客户端,可使用uv_close关闭其所关联的uv_handle_t,然后把客户端参数从客户端队列中删除。

但是libuv这种处处回调的函数,调用uv_close返回后并不意味着真正close成功了,此时若把客户端删除,则会调用客户端的析构函数,客户端的所有变量地址都是未知的了。因为uv_close后对客户端继续操作,所以访问这些未知变量地址会出错。真正close成功是在uv_close_cb被触发时。

所以想要delete掉一个客户端,得调用uv_close,然后在uv_close_cb等待并判断是哪个客户端,再把客户端删除。

2.3 同uv_close, uv_tcp_connect也一样,不能uv_tcp_connect就想发送数据,得等其回调函数触发后才能进行发送数据操作。uv_write也一样。

总结:libuv好不好,会用才好,不会用坑一大堆。

三、传输规则定义

网络传输中不能只接受裸流,必须对数据进行卦包与拆包,一来可防止数据被篡改与丢失,二来方便数据解析。

CSDN上对网络数据如何定义有讨论过:http://bbs.csdn.net/topics/380167545

本人定义的包结构如下:

// 一个数据包的内存结构

//增加包头与包尾数据,用于检测包的完整性。检验值用于检测包的完全性。

//|-----head----|--------------------------pack header-------------------|--------------------pack data------------|-----tail----|

字节--|--[version][head][tail][check][type][datalen][reserve]--|--datalen长度的内存数据(根据type去解析)--|--包尾1字节--|

#define NET_PACKAGE_VERSION 0x01

typedef struct _NetPacket{//传输自定义数据包头结构

int32_t version; //封包的版本号,不同版本包的定义可能不同 :0-3

unsigned char header; //包头-可自定义,例如0x02 :4

unsigned char tail; //包尾-可自定义,例如0x03 :5

unsigned char check[16];//pack data校验值-16字节的md5二进制数据 :6-21

int32_t type; //包数据的类型 :22-25

int32_t datalen; //包数据的内容长度-不包括此包结构和包头尾 :26-29

int32_t reserve; //包数据保留字段-暂时不使用 :30-33

}NetPacket;

字节

同时进行了封包与折包工作,详见packet.h

——————————————————————————————————————————————————————————————————————

代码已上传到git: https://github.com/wqvbjhc/libuv_tcp

客户端的测试例子有缺陷,但服务器完全正常。

服务器可以接收上百路连接。

基于libuv的TCP设计(二)的更多相关文章

  1. 基于libuv的TCP设计(三)

      基于libuv的TCP设计(一) 基于libuv的TCP设计(二)   一.第二版本的libuv_tcp已经基本可以使用.不会出错与崩溃现象,支持几百路客户端同时连接.可是有一缺陷就占用CPU非常 ...

  2. 基于libuv的TCP设计(一)

    本人一直在寻找一个跨平台的网络库,boost与ACE比较庞大,不考虑.对比了libevent,libev,libuv后,最终选择了libuv.可libuv文档少,例子也简单,对于tcp只有个echo- ...

  3. 38.基于FPGA的FIR设计二

    利用fdatool工具生成的滤波器系数与用代码生成的系数不一致,在网上查询得知,fdatool生成的滤波器系数是有符号小数,而且是浮点型,而代码生成的滤波器系数是定点型有符号数,故不一样. 浮点型数据 ...

  4. 基于ZedBoard的Webcam设计(一):USB摄像头(V4L2接口)的图片采集【转】

    转自:http://www.cnblogs.com/surpassal/archive/2012/12/19/zed_webcam_lab1.html 一直想把USB摄像头接到Zedboard上,搭建 ...

  5. 基于WPF系统框架设计(5)-Ribbon整合Avalondock 2.0实现多文档界面设计(二)

    AvalonDock 是一个.NET库,用于在停靠模式布局(docking)中排列一系列WPF/WinForm控件.最新发布的版本原生支持MVVM框架.Aero Snap特效并具有更好的性能. Ava ...

  6. 基于 MongoDB 动态字段设计的探索 (二) 聚合操作

    业务需求及设计见前文:基于 MongoDB 动态字段设计的探索 根据专业计算各科平均分 (总分.最高分.最低分) public Object avg(String major){ Aggregatio ...

  7. 分布式消息总线,基于.NET Socket Tcp的发布-订阅框架之离线支持,附代码下载

    一.分布式消息总线以及基于Socket的实现 在前面的分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架,附代码下载一文之中给大家分享和介绍了一个极其简单也非常容易上的基于.N ...

  8. GPS部标平台的架构设计(二) 可扩展性设计

    在设计的前夕,设计人员喜欢把领导对未来业务的期望带入到设计目标当中,比如当前业务也不过是接入几千辆车,未来业务增长也不过几万台,但领导很多激情,强势要求二期平台的接入能力要达到20万台,这个要求带入到 ...

  9. 基于.NET Socket Tcp的发布-订阅框架

    基于.NET Socket Tcp的发布-订阅框架 一.分布式消息总线 在很多MIS项目之中都有这样的需求,需要一个及时.高效的的通知机制,即比如当使用者A完成了任务X,就需要立即告知使用者B任务X已 ...

随机推荐

  1. WSAStartup() - 使用方法

    当一个应用程序调用WSAStartup函数时, 操作系统根据请求的Socket版本来搜索相应的Socket库,然后绑定找到的Socket库到该应用程序中. 以后应用程序就可以调用所请求的Socket库 ...

  2. 那些被Oracle优化的程序员

    甲骨文(中国)是一家很有趣的公司,势头强劲,却被公认为养老公司(俗称西二旗养老院).风光无限,却也走上了裁员之路. 据甲骨文员工透漏,前一天晚上还在加班改bug,第二天就通知被裁了,甚至要求被裁员工在 ...

  3. Matlab与数学建模

    一.学习目标. (1)了解Matlab与数学建模竞赛的关系. (2)掌握Matlab数学建模的第一个小实例—评估股票价值与风险. (3)掌握Matlab数学建模的回归算法. 二.实例演练. 1.谈谈你 ...

  4. C++概念分析之 重载、重写(覆盖)和隐藏的区别

    一.基本概念区别: 重载:是指同一可访问区内被声明的几个具有不同参数列(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,重载不关心函数返回类型. 隐藏:是指派生类的函数屏蔽了与其 ...

  5. 利用JDK方式和GuavaAPI方式实现观察者模式

    1.JDK方法实现案例需求: 去餐厅吃饭有时候需要排队,进行排队叫号.假如所有等待的人都是观察者,叫号系统就是一个被监听的主题对象.当叫号系统发出叫号通知后,所有等待的人,都会收到通知,然后检查自己的 ...

  6. go语言中type的几种使用

    type是go语法里的重要而且常用的关键字,type绝不只是对应于C/C++中的typedef.搞清楚type的使用,就容易理解go语言中的核心概念struct.interface.函数等的使用.以下 ...

  7. mysql innodb与myisam存储文件的区别

    myisam: .frm: 存储表定义 .myd(MYData):存储数据 .MYI(MYindex):存储引擎 innodb: .frm:存储表定义 .idb:存储数据和索引,在同一个文件中

  8. PHP课程环境安装总结文档

    phpStudy的安装 1.找一个硬盘根目录,比如这里我使用E盘,在E盘根目录创建一个php的文件夹,进入php文件夹,如下图所示 2.在步骤1的php文件夹下再建立一个文件夹php_dev,如下图所 ...

  9. 5+app uni-app flutter

    5+app uni-app flutter三者区别是什么? - 知乎 https://www.zhihu.com/question/295107584/answer/525442299 崔红保 DCl ...

  10. Java static静态关键字 有啥用

    #static有啥用 在Java语言中,static表示“静态”的意思,使用场景可以用来修饰成员变量和成员方法,当然也可以是静态代码块.static的主要作用在于创建独立于具体对象的域变量或者方法. ...