Connection

libtnet只支持IPv4 TCP Connection,之所以这么做都是为了使得实现尽可能的简单。我们主要在Connection类中封装了对tcp连接的操作。

Connection继承自std::enable_shared_from_this,也就意味着外部我们会操作其shared_ptr,libtnet几乎所有的对象都采用智能指针的方式来进行内存管理。

当Connection创建成功之后,会通过IOLoop的addHandler接口,将其绑定到ioloop上面:

ConnectionPtr_t conn = shared_from_this();
m_loop->addHandler(m_fd, TNET_READ, std::bind(&Connection::onHandler, conn, _1, _2));

因为我们直接在std::bind里面使用了shared_ptr,所以ioloop自然引用了该Connection,外部不需要在存储Connection,以防内存泄露。

对于一个connection而言,它只可能有几种状态,

  • Connecting,表明正在尝试连接,发生在connect返回EINPROGRESS。
  • Connected,连接已经建立成功,发生在connect成功或者accept成功。
  • Disconnecting,表明连接正在断开,发生在用户主动调用shutDown之后。
  • Disconnected,连接已经断开,这时候对应的socket也会被close掉。

Event Callback

在Connection中,我们使用一个event callback来绑定相应事件的回调。主要有如下connection event:

  • Conn_EstablishedEvent, 当server accept成功,创建了Connection对象之后,触发。
  • Conn_ConnectEvent,当client connect成功,触发。
  • Conn_ConnectingEvent,当client connect返回EINPROGRESS,触发。
  • Conn_ReadEvent,当连接可读,触发。
  • Conn_WriteCompleteEvent,当发送的数据都发送完毕,触发。
  • Conn_ErrorEvent,当连接有错误发生,触发。
  • Conn_CloseEvent,当连接主动或者被动关闭,触发。

event callback原型如下:

typedef shared_ptr<Connection> ConnectionPtr_t;
typedef std::function<void (const ConnectionPtr_t&, ConnEvent, const void* context)> ConnEventCallback_t;

对应不同的事件,触发的时候context的内容不同。现阶段,只有ReadEvent的时候context为StackBuffer,原型如下:

class StackBuffer
{
public:
StackBuffer(const char* buf, size_t c) : buffer(buf), count(c) {} const char* buffer;
size_t count;
};

当连接可读的时候,Connection会将数据读取到栈上面,并用StackBuffer来指代,这样当外部处理ReadEvent的时候就能通过将context转换成StackBuffer获取到读取的数据。

下面简单说明一下一些设计上面的取舍:

  • 为什么只提供一个event callback,而不提供read callback,write complete callback,close callback多个回调接口?

    libtnet的所有callback都采用的是std::function实现,而该对象占用32字节,如果每个event都提供一个对应的callback,那么内存的开销会有点大,同时大部分时候很多callback我们是不感兴趣的。

    还有一个重要的原因在于只提供一个event callback,外部的一些对象就可以通过该callback跟Connection绑定,也就是将其自身的生命周期与Connection绑定在了一起,当Connection删除的时候该对象也自行删除。libtnet中,HttpConnection,WsConnection都是采用该方法,因为对于一个Http连接来说,如果底层的Tcp连接都断开无效了,基于Tcp的Http连接自然就无效了。

  • Connection为什么不缓存读取的数据,而是交由外部callback去处理?

    Connection作为一个底层的类,对于读取的数据,并不知道具体需要如何处理,所以还不如将数据直接发到外层,供上层实际的应用逻辑处理。但是如果后续Connection考虑支持ssl,那么就需要进行缓存数据了。

Write

Connection建立之后,默认只会在ioloop中设置TNET_READ事件,因为epoll采用的水平触发模式,如果直接设置TNET_WRITE事件,那么epoll会一直通知socket可写,但实际上并没有可以发送的数据。

所以,libtnet采用如下的方式进行数据发送:

  • 直接调用writev函数进行数据发送
  • 如果数据未发送完毕,则向ioloop注册TNET_WRITE事件,下次触发可写的时候继续发送,直至发送成功,清除TNET_WRITE事件。

另外,在发送的时候,我们还需要考虑signal pipe的情况,所以需要忽略该singal。使用如下方式:

class IgnoreSigPipe
{
public:
IgnoreSigPipe()
{
signal(SIGPIPE, SIG_IGN);
}
}; static IgnoreSigPipe initObj;

当libtnet启动的时候,就忽略了signal pipe信号。虽然这样做稍微有一点副作用,但大部分时候我们并不需要关注SIGPIPE信号。

Kick Off Connection

通常,为了处理不活跃连接,程序都会将每个connection设置一个timer,如果timer到了该连接仍然没有交互,则会删除该连接,否则则继续更新timer。另一种做法就是提供一个time wheel,将connection放置在该wheel中,如果有交互,则在wheel中移动。

libtnet采用了一种更简单,但是精度比较差的做法。

当server成功创建一个connection之后,将会添加到一个ConnChecker中,checker保存的是该connection的weak_ptr。每隔一段时间,checker检查一批connection:

  • 如果connection weak_ptr无法lock提升至shared_ptr,证明该连接已经删除,checker直接移除。
  • 如果connection处于connecting状态,并且超过了设置的最大连接超时时间,shutDown该connection。
  • 如果connection处于connected状态,并且在一段时间内没有任何交互,shutDown。

ConnChecker的检查间隔以及每次检查步数都可以通过外部设置。使用ConnChecker虽然简单,但是在连接数过大的情况下面,一些过期的connection不能立刻被清理掉。对于这个问题,我觉得可以接受,一个连接一秒之后被关闭还是两秒之后被关闭,差别真的不大。如果我们真的需要对一些connection做精确的时间控制,那直接可以对其使用timer。

libtnet的地址https://github.com/siddontang/libtnet,欢迎围观。

高性能C++网络库libtnet实现:Connection的更多相关文章

  1. 高性能C++网络库libtnet实现:http

    HTTP libtnet提供了简单的http支持,使用也很简单. 一个简单的http server: void onHandler(const HttpConnectionPtr_t& con ...

  2. 高性能C++网络库libtnet实现:IOLoop

    IOLoop libtnet采用的是prefork + event loop的架构方式,prefork就是server在启动的时候预先fork多个子进程同时工作,而event loop则是基于epol ...

  3. 高性能C++网络库libtnet实践:comet单机百万连接挂载测试

    最近在用go语言做一个挂载大量长连接的推送服务器,虽然已经完成,但是内存占用情况让我不怎么满意,于是考虑使用libtnet来重新实现一个.后续我会使用comet来表明推送服务器. 对于comet来说, ...

  4. 发布一个参考tornado的高性能c++网络库:libtnet

    libtnet是一个用c++编写的高性能网络库,它在设计上面主要参考tornado,为服务端网络编程提供简洁而高效的接口,非常易于使用. Echo Server void onConnEvent(co ...

  5. 专注于HTTP的高性能高易用性网络库:Fslib.network库

    博客列表页:http://blog.fishlee.net/tag/fslib-network/ 原创FSLib.Network库(目前专注于HTTP的高性能高易用性网络库) FSLib.Networ ...

  6. [开源] gnet: 一个轻量级且高性能的 Golang 网络库

    Github 主页 https://github.com/panjf2000/gnet 欢迎大家围观~~,目前还在持续更新,感兴趣的话可以 star 一下暗中观察哦. 简介 gnet 是一个基于 Ev ...

  7. boost.ASIO-可能是下一代C++标准的网络库

    曾几何时,Boost中有一个Socket库,但后来没有了下文,C++社区一直在翘首盼望一个标准网络库的出现,网络上开源的网络库也有不少,例如Apache Portable Runtime就是比较著名的 ...

  8. Cowboy 开源 WebSocket 网络库

    Cowboy.WebSockets 是一个托管在 GitHub 上的基于 .NET/C# 实现的开源 WebSocket 网络库,其完整的实现了 RFC 6455 (The WebSocket Pro ...

  9. 网络库crash以及boost asio strand dispath分析

    最近在做服务器的稳定性的相关测试,服务器的网络底层使用的是boost asio,然后自己做的二次封装以更好的满足需求. 服务器昨天晚上发现crash了一次,之前测试了将近半个多月,有一次是莫名的退出了 ...

随机推荐

  1. VirtualBox中的Ubuntu没有权限访问共享文件夹/media/sf_bak

    之前已经搞定可以自动共享文件夹了,但是现在发现无法去访问,非root用户下,使用“ls /media/sf_bak”提示没有权限,当然如果切换到root,是可以的. [解决过程]1.把普通用户名加入到 ...

  2. jquery 单击li防止重复加载的实现代码

    因为加载内容比较慢,所以用户可能在li上不经意点击了两次,那么就会请求两次,这是我们不想看到的. 今天在javascript-jquery群上一筒子发了两个demo给我,他的方法是先将单击的li节点拷 ...

  3. 转:Bootstrap研究 精巧的网格布局系统

    本网格布局系统属于Scaffolding(框架,布局)部分.在Scaffolding里面有(固定)网格布局(Grid System)和流式网格布局(Fluid Grid System).本文讨论第一种 ...

  4. 基于visual Studio2013解决C语言竞赛题之0413同构数

       题目 解决代码及点评 该题目与水仙花数类似,只是条件不同,循环还是一样的 /***************************************************** ...

  5. Office 2010 垃圾邮件过滤设置

    垃圾邮件过滤设置 有同事反馈给我,某些时候应该收到的邮件,却到了垃圾邮件里,给工作带来了不便,下面简单介绍一下outlook 2010 有关垃圾邮件的过滤设置. 1: 找到相关的邮件,点右键,在”垃圾 ...

  6. 文件打包bundle

    做项目时,经常会有一些资源拷来拷去会很麻烦,打包这些文件到项目里会方便很多! 首先把文件放到一个文件夹里                然后重命名文件夹为iToast.bundle 拖到项目里 如何访 ...

  7. c语言string.h和memory.h某些函数重复问题

    在C语言中,为了使用memset()函数,你是选择#include <string.h>还是<memory.h>?两个都可以,如何选择? <string.h>,标准 ...

  8. UIView详解1

    一个UIView的实例就是一个视图,表示的是屏幕上的一块矩形区域,负责这块矩形区域的描绘以及和用户的交互. 第一.UIView的可视化属性 1. backgroundColor  背景属性 2. hi ...

  9. Java的位运算符具体解释实例——与(&amp;)、非(~)、或(|)、异或(^)

    位运算符主要针对二进制,它包含了:“与”.“非”.“或”.“异或”.从表面上看似乎有点像逻辑运算符,但逻辑运算符是针对两个关系运算符来进行逻辑运算,而位运算符主要针对两个二进制数的位进行逻辑运算.以下 ...

  10. cocos2dx-lua捕获用户touch事件的几种方式

    这里仅仅针对lua 1.为每一个关心的事件注冊回调函数 详细分为下面几种 1>单点触摸 注冊函数为 cc.Handler.EVENT_TOUCH_BEGAN      = 40 cc.Handl ...