一个包的libevent流程
//一个发包的流程
第一个包就是客户端的心跳包,现在加了版本的包
再来看看这个发包打包过程,过程坚持,但理解费劲
void NGP::OnliveTimer()//客户端心跳,5s发一次
{
SendCmd(c2s_on_live, NULL, );
}
bool NGP::SendCmd(int nCmd, void* pData, int nLen)
{
//std::wstring msg = L"发送命令:";
//msg += boost::lexical_cast<std::wstring>(cmd);
//m_share->log(msg.c_str());
//发送获取游戏列表请求
Protocol rpt = {};
rpt.cmd_type = nCmd;
rpt.content = pData;
rpt.size = nLen;
std::vector<char> buffer;
buffer.resize(nLen + sizeof(Protocol));//这个长度个人感觉可以-sizeof(void*),这个位置其实是被覆盖的
int send_len = rpt.to_buffer(&buffer[], buffer.size()); for (;;)
{
bool b = m_spTcpLink->Send(&buffer[], send_len); if (b)
break;
std::this_thread::sleep_for(std::chrono::milliseconds());
} return true;
}
//包的格式(这个就是初始包发送的格式)
-(一个字节的协议)----(四个字节的长度表示后面内容的大小)-----------------(包发的内容)
struct Protocol
{
unsigned char cmd_type;
int size;//content的长度, 不包含本协议头
void* content; int to_buffer(void* buffer, int buffer_len)//挺难理解的
{
if(!buffer)
return -;
int total_size = size + sizeof(Protocol) - sizeof(void*);//- sizeof(void*)是因为到时就是从这个指针的位置开始复制的
if(buffer_len < total_size)//buffer_len是提供的内存大小,total_size是打包后的总大小
return -; Protocol* p = (Protocol*)buffer;//把内存模型看成Protocol模型
p->cmd_type = this->cmd_type;
p->size = this->size;
if (content)
{
memcpy(&p->content, content, size);//从指针开始位置复制内容
}
return total_size;
}
}
//此包在libevent又进行了一次打包过程
----(4个字节,表示后面包的总长度)-(一个字节的协议)----(四个字节的长度表示后面内容的大小)-----------------(包发的内容)
所以对于心跳包的长度是9个字节 //服务端接受到这个包的流程
线程的读事件被调用
/* 读数据流 */
void Channel::read_datastream(struct bufferevent* bev)
{
//bufferevent_read每次会将输入缓冲中的数据读出来,好像最多读4096个字节,那这么大的数据有可能是多个包,还有可能一个包都不到,这是个问题
size_t len = bufferevent_read(bev, m_buf, sizeof(m_buf));
/**
* [测试]:先解锁再加锁,防止此线程在分配内存失败的时候死循环等待时,main_thread的send_data陷入阻塞。
*/
evbuffer_unlock(bev->output); //auto& in = bev->input; lock一样
//auto& out = bev->output;
m_readStream.Push(m_buf, len);//datastream相当于一个缓冲的作用,这个过程看懂废我好大劲,最后还是在同时的帮助下才了解
read_pack(); evbuffer_lock(bev->output);
} void Push(const void * pBuf, int nLen)
{
char* pBuf2 = (char*)pBuf; m_StreamBuffer.insert(m_StreamBuffer.end(), pBuf2, pBuf2 + nLen);//每次将包插入最后一个位置的地方
} /* 读包 */
void Channel::read_pack()
{
if(m_readStream.Size() < )//如果其大小小于4就表示读完了,不可能存在小于4个字节的包,有可能是不完整的包
return; size_t len = *(size_t*)m_readStream.Peek();//获取前四个字节,表示包内容的长度
if( m_readStream.Size() < + len)//表示包不符合规则,应该>=,当然也有可能是因为这个包是不完整的包,等下次再解析
return; m_event->on_receive_data(m_id, m_readStream.Peek() + , len); //对包进行处理
m_readStream.Pop( + len);//每个包逃过下次读取位置 read_pack();//一直读到完为止
}
void Pop(int nLen)
{
m_head_size += nLen;//将头标记移动
if(m_head_size > m_buff_len)
{
//可以将这个数组当成循环队列进行使用,循环队列还有种方式就是两个游标
m_StreamBuffer.erase(m_StreamBuffer.begin(), m_StreamBuffer.begin() + m_head_size);//删掉重新预留,个人理解有可能是防止读取错误,具体不是太清楚
m_head_size = ;
m_StreamBuffer.reserve(m_buff_len);
}
}
关于这个最终到达GS还有很多东西要做,暂时分析到这。
一个包的libevent流程的更多相关文章
- 一个包的TcpServer流程
上次说到对于那种有内容的包 bool TCPServer::on_receive_data(int channel_id, void* data, int len) { packet pkt; { p ...
- 一个包的net到gs流程
再来看看一个包走共享内存的流程 先来看看net进程这块如何处理的 {//用shareData这种类型封装刚才从无锁队列中取到的包 shareData sd; sd.channel_id = pkt.c ...
- 【Star CCM+实例】开发一个简单的计算流程.md
流程开发在CAE过程中处于非常重要的地位. 主要的作用可能包括: 将一些经过验证的模型隐藏在流程中,提高仿真的可靠性 将流程封装成更友好的界面,降低软件的学习周期 流程开发实际上需要做非常多的工作,尤 ...
- npm 包的 发布 流程
npm 包的发布流程 本文主要是针对 还未曾发布过自己的 npm 的同学,阐述一下 npm 的发布流程 熟悉的同学,可以绕道了. 首先你得有一个 自己的 npmjs.com 的账号 (没有的话,就到 ...
- Springboot 整合Activiti流程设计器 完成一个简单的请假流程
目录 1.前言 2.准备 3.下载解压 4.开始整合 mysql + activiti + thymeleaf 2.配置文件 3.复制文件 4.加入控制器 5.修改配置文件 6.剔除启动类里面的安全校 ...
- 面试题常考&必考之--http访问一个页面的全流程(Tcp/IP协议)
分析:-http访问一个页面的全流程,也就好比我们在地址栏输入地址,然后点击回车进行访问 该面试题的主要考点是:计算机网络的TCP/IP协议栈 描述图片:首先应用层提交http请求,传到传输层后由,T ...
- pip:带你认识一个 Python 开发工作流程中的重要工具
摘要:许多Python项目使用pip包管理器来管理它们的依赖项.它包含在Python安装程序中,是Python中依赖项管理的重要工具. 本文分享自华为云社区<使用Python的pip管理项目的依 ...
- 判断一个Activity 判断一个包 是否存在于系统中 的方法
判断一个包是否存在于系统中(来自网络),经过测试,好用: public boolean checkBrowser(String packageName) { if (packageName == nu ...
- python高级编程 编写一个包1
#目的是:编写,发行python包可重复过程"""1:是缩短开始真正工作之前所需要的设置时间,也就是提供模板2:提供编写包的标准化方法3:简化测试驱动开发方法的使用4:为 ...
随机推荐
- scala实现kmeans算法
算法的概念不做过都解释,google一下一大把.直接贴上代码,有比较详细的注释了. 主程序: import scala.io.Source import scala.util.Random /** * ...
- OJ推荐【转】
来自:http://blog.csdn.net/zdp072/article/details/16207111 一. Online Judge简介: Online Judge系统(简称OJ)是一个在线 ...
- Python脚本控制的WebDriver 常用操作 <六> 打印当前页面的title及url
下面将使用WebDriver来答应浏览器页面的title和访问的地址信息 测试用例场景 测试中,访问1个页面然后判断其title是否符合预期是很常见的1个用例: 假设1个页面的title应该是'hel ...
- 《Prism 5.0源码走读》Bootstrapper
Prism框架需要在应用程序启动的时候进行一些初始化的工作,Bootstrapper就是来做这些的,是其切入点. Bootstrapper主要要做的事有:创建和配置module catalog,创建D ...
- 包(package) 与 导入(import) 语句剖析
A) 包(package):用于将完成不同功能的类分门别类,放在不同的目录下. B)命名规则:将公司域名翻转作为包名.例如www.vmaxtam.com域名,那么包名就是com.vmaxtam 每个字 ...
- 函数调用和inline作用
函数调用的开销: 函数被调用时,要有函数调用和返回.要保存当前程序上下文信息,以便函数调用完毕后返回原来的地方,继续执行程序.将函数的参数进行压栈.出栈,执行函数,函数调用完毕后释放内部变量占用的内存 ...
- poj 3625 Building Roads
题目连接 http://poj.org/problem?id=3625 Building Roads Description Farmer John had just acquired several ...
- ubuntu 修改主机名
sudo gedit /etc/hostname sudo gedit /etc/hosts
- Log4j的常见用法
对于log4j,一般常用的只要保存如下的内容为属性文件即可: #log4j.rootLogger=DEBUG,A1,R log4j.rootLogger=INFO,A1,R log4j.appende ...
- .net sql 防注入 httpmodule
1 新建一个类,实现IHttpModule接口 using System; using System.Collections.Generic; using System.Linq; using Sys ...