RBL开发笔记三

  2014-08-26 20:06:24

  今天就是在开发这个EPOLL来处理网络事件 封装较为健壮的EPOLL模型来处理基本的网络IO

  1) 超时这个主题先没有弄

  在开发EPOLL包括select/poll类型io复用时,编程技术技巧分为几点:【下面都是针对与TCP协议 如果在以后开发中需要UDP会扩展这个编程技术】

1     要处理的文件描述符种类

  a)    listenfd=socket(); 这个listenfd 就是监听的listenfd  我们暂且把他作为一个总IO文件 其实这个listenfd就是一个数组索引。利用EPOLL监听的这个listenfd  READBLE状态,那么这里肯定需要放一个TCPAcceptHandler的函数来做相应的操作  因为监听到相应的核心东东就是一系列raw的客户端传来的信息:

其中有 ip  fd  port    作为一个功能完善的程序   ip  fd  port 这些作为raw信息 外加一系列RBL服务端所要控制的信息 构造了RBLClient的这个重量级数据结构,这样网络层和RBL服务层能够通过这个数据结构进行结合了。TCPAcceptHandler在目前看来就是做这个事情。

  b) 在a阶段构造了RBLClient 但是这个只是做了TCP的raw的ACCPET操作,但是需要引入真正的逻辑操作,也就是RBLServer接受到的所有的无论是自身的还是客户端的数据通信。 这里要利用typedef  void   FileProc(EpollEventLoop* ep,void *data,int fd) 给每一个来处理的文件的描述符注册一个通用的函数指针。这点内存消耗是必须的。这点暂时也不考虑了 这个阶段就是完成了注册事件。其实在这里需要处理可读和可写个事件 1) 可读是通过这层 交付给其他服务部分,2) 可写其他组建【自身】交给网络终端。

2   做成一个可以可随时插入的事件处理模型

  在实现上要像REDIS一样,随时可以插入事件  比如建立一个EPOLLLOOP对象之后,在后面的N个步骤之后 咱们插入一个listenfd到EPOLLLOOP对象里。

在或者 我处理完一个客户端命令我需要告诉他该怎么做 也是通过回调事件来完成。 同时由于客户端随时挂掉或者主动离开  需要做DEL功能。 这些看起来是显而易见 但是需要仔细封装好。【在REDIS中是注入了readQueryFromClient/  sendReplyToClient这2个事件函数】所以呢 嘿嘿 面对这么优秀的REDIS设计  我还是利用的模式  不过在哪里潜入这2个函数呢? 需要仔细的体会体会哦

另外定义一个什么样的协议呢? 兼容REDIS 我采用同样的协议模式。

简单的类定义如下:

class EpollEventLoop
{
public:
	EpollEventLoop(int maxclient_):maxclient(maxclient_),maxepollevent(maxclient_),maxfd(-1)
	{
		epollfd=epoll_create(2048);
		if(epollfd==-1)
			std::cout<<"epoll create failed!"<<std::endl;
	}
	void CreatFileEvent(int fd,FileEvent* prere_event); //这里其实是注册事件
	void DeleteFileEvent(int fd,int mask); //这里是删除事件
	void ProcessEvents(int flag);//flag代表是那种类型的事件 在这里就是读写事件
	~EpollEventLoop()
	{
	}
private:
	int maxfd; //当前注册最大文件数目 eventloop初始化为-1
	std::vector<FileEvent> fileevent; //文件事件  用std::vector存储
	int epollfd; //epollfd文件描述符
	std::vector<struct epoll_event> maxepollevent;
	int maxclient;
};

  REDIS协议实现起来比较繁琐的是批处理操作:

  

  *<参数数量> CR LF
  $<参数 1 的字节数量> CR LF
  <参数 1 的数据> CR LF
  ...
  $<参数 N 的字节数量> CR LF
  <参数 N 的数据> CR LF这样看来:传入上面总结的3个function(readQueryFromClient/  sendReplyToClient/TCPAcceptHandler)上都是以RBLClient做为主参数,解码或者加码都是在readQueryFromClient/  sendReplyToClient函数完成。实现上还有一个难点:就是加码或者解码时这边传入的数据缓冲区不够怎么办?不能一下子放到结构化数据中,那就在实现时 做一个标记位,分多次读完 这样确实麻烦  这样在RBLClient就要多加几个结构来控制这些量了。 快哭了  网络协议部分http://www.redisdoc.com/en/latest/topic/protocol.html 就参考这个了  简化它 毕竟没有REDIS命令那么多 

接下来是一个头痛的问题:上面的实现版本是单线程模式:  接下来该怎么实现一个多线程呢?  EPOLL线程:加入任务队列WorkQueue中, 是把什么加入到这个WorkQueue中呢? 其实就是把一个个RBLClient副本到WorkQueue中,而消费线程也就是调用TakeQueue() 形式化:
LOCK1()
TakeQUEUE()
UNLOCK1()
……
……
LOCK2()
CommandExecute()
UNLOCK2()

 对于LOCK1部分的实现  用无锁队列

 对于LOCK2 这里实现有一个CommandExecute() 这里就是控制一个部分bit数组 所以对我来讲 这个地方如果采用spin_lock() 加锁会不会好一一些呢? 这个需要评估

另外而言: 对于一致性而言,这样的操作模式 对于单客户可能不会马上得到想要的结果  这是一种必须的 是需要一个时间窗口  并非强一致性  我这里是牺牲了强一致性的 但是如果WorkQueue一直非常小的话 这个时间窗口肯定就非常小了 对应用程序造不成很大的影响。

明天的实现部分估计就是这个最难熬的线程控制部分了 这个部分计划用2到3天完成。明天把EventLoop代码实现的部分和协议实现部分先贴出来 然后串讲下思路先这样了 bye
				
时间: 2024-10-11 18:38:05

RBL开发笔记三的相关文章

PHP微信公众开发笔记(三)

PHP微信公众开发笔记系列 日期:2014.9.2 今天主要的任务是昨天提到的那个处理缓存信息的问题,我需要保存一些消息用来做二次判断. 首先,记录一些PHP语法知识吧. 1.PHP中字符串的连接语法: 在lua中,两个字符串的连接很简单,加入有两个字符串 "aaa";"bbb"; 需要将这两个字符串连接起来,只需要用两个句点 .. 便可以了:"aaa" .. "bbb"; 这里要注意,字符串与句点直接需要有空格,没有空格会报

RBL开发笔记一

从这个系列开始  陆续记录整个RBL开发的过程   废话不多说   直入主题 10:54:53   2014-08-25 今天开发任务: RBL.h  的框架搭建出来   包括RBLServer RBLClient   和命令窗口 网络层: 因为我开发的目的就是linux 所有非linux系统的api 我都不会考虑. 在IO复用中我就选择了EPOLL模型  其他的实现 包括freeBSD等 主要原因是我没有精力去写

RBL开发笔记二

 17:13:55 2014-08-25 有以下几个点:  第一 :怎么在预处理阶段能够做到识别某个宏是否给定义了  这里就定义了一个SystemConfig.h 专门做这个事情  当然是需要makefile来配合的 http://blog.csdn.net/chaoqunz/article/details/6033663  这篇博文已经提到相应的方法  在makefile里加一个-D 参数  这相当于就是Makefile一个补充参数吧. 第2: 因为我的计划写这个RBL的时候  可以通过配置文

服务端开发笔记三:pemelo开发过程中遇到的问题

一 登录顶号 问题: 首先需要弄明白的是,一个客户端只有一个pomelo实例. 当用户登录之后,不退出,重启客户端. 服务器检测到玩家已经登录,会将之前的登录踢下线,客户端会触发disconnect事件,在disconnect中断开pomelo链接. 这样导致当前的链接也被断掉了. 解决方案: 目前处理方式是在disconnect中不断开链接.但这样处理有个问题,当服务器链接不上时,会有一个报错. 原因目前还在查找,找到了再来更新,有路过的小伙伴儿有其他的解决方案也欢迎留言讨论. 二 数据库触发

Vue-cli开发笔记三----------引入外部插件

(一)绝对路径直接引入: (1)主入口页面index.html中头部script标签引入: 1 <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=n0S34gQ0FW73Vj7X13A4y75q"></script> (2)build/webpack.base.conf.js 中配置: externals 1 let webpackCon

CriminalIntent项目开发笔记(三)----ListFragment的使用

本节主要学习ListFragment的用法. 1.更新模型层,创建一个 CrimeLab 类用于存储多个Crime对象 CrimeLab采用单例模式,以便数据的集中存储 package com.criminalintent; import android.content.Context; import java.util.ArrayList; import java.util.List; import java.util.UUID; public class CrimeLab { private

android studio开发笔记三

1.ToggleButton:有两种状态:选中和未被选中状态,并且需要为不同的状态设置不同的显示文本2.ToggleButton属性:android:checked="true" android:textOff="关" android:textOn="开"activity_main:<?xml version="1.0" encoding="utf-8"?><RelativeLayout

Android开发笔记(一百零三)地图与定位SDK

集成地图SDK 国内常用的地图SDK就是百度和高德了,二者的用法大同小异,可按照官网上的开发指南一步步来.下面是我在集成地图SDK时遇到的问题说明: 1.点击基本地图功能选项,不能打开地图,弹出"key验证出错!请在AndroidManifest.xml文件中检查key设置的"的红色字提示.查看日志提示"galaxy lib host missing meta-data,make sure you know the right way to integrate galaxy&

微信订阅号开发笔记(三)

1.接收语音识别结果 if($msgType=="voice"){ //收到语音消息 //MediaId 语音消息媒体id,可以调用多媒体文件下载接口拉取数据. //Format 语音格式,如amr,speex等 $format = $postObj->Format; $mediaId = $postObj->MediaId; //开通语音识别功能,用户每次发送语音给公众号时,微信会在推送的语音消息XML数据包中,增加一个Recongnition字段. //注:由于客户端缓