基于libuv的TCP设计(二)

一、本人设想的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----|

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

#pragma
pack(1)//将当前字节对齐值设为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;

#define
NET_PACKAGE_HEADLEN sizeof(NetPacket)//包头长度,为固定大小34字节

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

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

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

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

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

基于libuv的TCP设计(二)

时间: 2024-10-12 07:03:26

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

基于libuv的TCP设计(三)

? 基于libuv的TCP设计(一) 基于libuv的TCP设计(二) ? 一.第二版本的libuv_tcp已经基本可以使用.不会出错与崩溃现象,支持几百路客户端同时连接.可是有一缺陷就占用CPU非常高.因为IDLE阶段一直检测有无数据需要发送,所以当服务器空闲时IDLE会空转,占用CPU.如今对此流程进行了改进. ? ? 二.改进 1.去掉prepare,check,idle事件 2.prepare里的判断用户关闭tcp和发送数据由uv_async_send代替 3.重新定义客户端数据stru

基于角色的权限设计(二)

第一部分请參看:http://blog.csdn.net/snomyc520/article/details/38677861 针对这种需求,版本号一就无能为力了(当然你也能够添加几个功能:比方分类A的新闻起草和分类B的新闻起草,再把这个功能加入到对应的角色里面去,可是这个应该不是我们要得解决方式吧,只是版本号二也是基于这个思想来解决的). 事实上比新闻更好的样例是论坛板块的版主. 以下是版本号二的解决方式: 在版本号二的功能表中增加了一个ResourceType这个字段,这个字段用来表示对某个

基于linux的TCP网络聊天室设计与实现

利用Linux实现基于TCP模式的网络聊天程序 主要完成的两大组成部分为:服务器和客户端. 服务器程序主要负责监听客户端发来的消息. 客户端需要登录到服务器端才可以实现正常的聊天功能.该程序是利用进程以及共享内存来实现群发送消息的. 以下简单分析一下服务器端和客户端两个方面所要完成的任务. 服务器的主要功能如下: 在特定的端口上进行监听,等待客户端的连接. 用户可以配置服务器端的监听端口. 向连接的客户端发送登录成功信息. 向已经连接到服务器的客户端的用户发送系统消息. 使用TCP多线程并发服务

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

业务需求及设计见前文:基于 MongoDB 动态字段设计的探索 根据专业计算各科平均分 (总分.最高分.最低分) public Object avg(String major){ Aggregation aggregation = Aggregation.newAggregation( Aggregation.unwind("courseList"), Aggregation.match(Criteria.where("major").is(major)), Agg

WCF客户端配置以及代理-----基于DDD领域驱动设计的WCF+EF+WPF分层框架(4)

写在最前面:转载请注明出处 目录置顶: 关于项目--------------------基于DDD领域驱动设计的WCF+EF+WPF分层框架(1) 架构搭建--------------------基于DDD领域驱动设计的WCF+EF+WPF分层框架(2) WCF服务端具体实现---------基于DDD领域驱动设计的WCF+EF+WPF分层框架(3) WCF客户端配置以及代理-----基于DDD领域驱动设计的WCF+EF+WPF分层框架(4) Domain具体实现------------基于DD

基于消息系统架构设计

近期在弄一个业务系统,这个业务系统原本是有一个架构的,可是在后期扩展时发现问题多多.关键扩展非常不方便,并且由于业务系统安全规格较高.数据网络连接须要通过多个闸口传递才可,并且业务系统可能须要多地系统联合组网.共享业务数据,可是各地系统又必须相互独立. 用户希望改动架构,让系统可扩展性添加,同一时候要满足系统相互独立方便升级和兴许开发. 依照用户的要求我考虑使用一个基于消息传递的架构设计来满足需求. 所谓基于消息,就是通过消息中转server,中转全部系统间连接数据,同一时候管理数据路由,由消息

基于DDD领域驱动设计的WCF+EF+WPF分层框架

目录置顶: 关于项目--------------------基于DDD领域驱动设计的WCF+EF+WPF分层框架(1) 架构搭建--------------------基于DDD领域驱动设计的WCF+EF+WPF分层框架(2) WCF服务端具体实现---------基于DDD领域驱动设计的WCF+EF+WPF分层框架(3) WCF客户端配置以及代理-----基于DDD领域驱动设计的WCF+EF+WPF分层框架(4) Domain具体实现------------基于DDD领域驱动设计的WCF+EF

基于PHP实战ThinkSNS V3二次开发

基于PHP实战ThinkSNS V3二次开发(系统架构.网站定制化开发.问答系统开发) 课程分类:PHP 适合人群:中级 课时数量:25课时 服务类型:C类(普通服务类课程) 用到技术:PHP.ThinkSNS V3二次开发 涉及项目:ThinkSNS V3二次开发.问答系统 咨询QQ:1840215592 课程内容简介: 由于ThinkSNS产品提供了完整的微博及系统功能,并提供了非常友好的二次开发规范.越多越多的企业和开发人员选择使用ThinkSNS构建成熟的SNS企业网站和商业项目.本课程

分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架,附代码下载

一.分布式消息总线 在很多MIS项目之中都有这样的需求,需要一个及时.高效的的通知机制,即比如当使用者A完成了任务X,就需要立即告知使用者B任务X已经完成,在通常的情况下,开发人中都是在使用者B所使用的程序之中写数据库轮循代码,这样就会产品一个很严重的两个问题,第一个问题是延迟,轮循机制要定时执行,必须会引起延迟,第二个问题是数据库压力过大,当进行高频度的轮循会生产大量的数据库查询,并且如果有大量的使用者进行轮循,那数据库的压力就更大了. 那么在这个时间,就需要一套能支持发布-订阅模式的分布式消