//一个发包的流程
第一个包就是客户端的心跳包,现在加了版本的包
再来看看这个发包打包过程,过程坚持,但理解费劲
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流程的更多相关文章

  1. 一个包的TcpServer流程

    上次说到对于那种有内容的包 bool TCPServer::on_receive_data(int channel_id, void* data, int len) { packet pkt; { p ...

  2. 一个包的net到gs流程

    再来看看一个包走共享内存的流程 先来看看net进程这块如何处理的 {//用shareData这种类型封装刚才从无锁队列中取到的包 shareData sd; sd.channel_id = pkt.c ...

  3. 【Star CCM+实例】开发一个简单的计算流程.md

    流程开发在CAE过程中处于非常重要的地位. 主要的作用可能包括: 将一些经过验证的模型隐藏在流程中,提高仿真的可靠性 将流程封装成更友好的界面,降低软件的学习周期 流程开发实际上需要做非常多的工作,尤 ...

  4. npm 包的 发布 流程

    npm 包的发布流程 本文主要是针对 还未曾发布过自己的 npm 的同学,阐述一下 npm 的发布流程 熟悉的同学,可以绕道了. 首先你得有一个 自己的 npmjs.com 的账号 (没有的话,就到 ...

  5. Springboot 整合Activiti流程设计器 完成一个简单的请假流程

    目录 1.前言 2.准备 3.下载解压 4.开始整合 mysql + activiti + thymeleaf 2.配置文件 3.复制文件 4.加入控制器 5.修改配置文件 6.剔除启动类里面的安全校 ...

  6. 面试题常考&必考之--http访问一个页面的全流程(Tcp/IP协议)

    分析:-http访问一个页面的全流程,也就好比我们在地址栏输入地址,然后点击回车进行访问 该面试题的主要考点是:计算机网络的TCP/IP协议栈 描述图片:首先应用层提交http请求,传到传输层后由,T ...

  7. pip:带你认识一个 Python 开发工作流程中的重要工具

    摘要:许多Python项目使用pip包管理器来管理它们的依赖项.它包含在Python安装程序中,是Python中依赖项管理的重要工具. 本文分享自华为云社区<使用Python的pip管理项目的依 ...

  8. 判断一个Activity 判断一个包 是否存在于系统中 的方法

    判断一个包是否存在于系统中(来自网络),经过测试,好用: public boolean checkBrowser(String packageName) { if (packageName == nu ...

  9. python高级编程 编写一个包1

    #目的是:编写,发行python包可重复过程"""1:是缩短开始真正工作之前所需要的设置时间,也就是提供模板2:提供编写包的标准化方法3:简化测试驱动开发方法的使用4:为 ...

随机推荐

  1. .ascx.g.cs文件不能生成 The name ‘InitializeControl’ does not exist in the current context - Visual Web part Sharepoint

    InitializeControl doesn't exsit When using visual studio 2012 for developing SharePoint 2013 Visual ...

  2. adb 修改system文件

    1. $ adb push SecureSetting.apk /sdcard/  // 上传要安装的文件,为安装做准备.     2. $ adb shell     3. $ su // 切换到  ...

  3. LinkedList存储一副扑克牌,实现洗牌功能。

    package cd.itcast.runble; import java.util.LinkedList; import java.util.Random; /** * LinkedList存储一副 ...

  4. delphi构造&析构调用顺序

    _ClassCreate ->Create ->AfterConstruction(->DoCreate / OnCreate) BeforeDestruction(->DoD ...

  5. 利用FMX控件的MakeScreenshot过程实现WAIT效果

    原理: 1.新建一个waitform,添加控件: 背景图片BACKPIC:Timage控件: 再叠加一个WAIT图标(TAniIndicato控件). 2.在要实现wait效果的form上添加一个控件 ...

  6. Python之mongodb操作

    1.安装驱动pymongo 输入命令:pip install pymongo 2.直接使用驱动 #encoding=utf-8 from pymongo import MongoClient clie ...

  7. WPF Event 在 Command 中的应用初级篇,支持所有Event 展示松耦合设计的全部代码 - 解决TextBoxBase.TextChanged或者TextBox.TextChanged等类似事件绑定问题。

    做过WPF开发的人,都知道做MVVM架构,最麻烦的是Event的绑定,因为Event是不能被绑定的,同时现有的条件下,命令是无法替代Event.而在开发过程中无法避免Event事件,这样MVVM的架构 ...

  8. C# 自定义集合

    自定义类型 public class Product { public int Id { get; set; } // 自增ID public string Name { get; set; } // ...

  9. mq消息队列

    rabbitmq学习9:使用spring-amqp发送消息及同步接收消息 通过对spring-amqp看重要类的认识,下面来通过spring-amqp的发送消息及同步接收消息是如何实现的.有兴趣的朋友 ...

  10. EMVTag系列17《9F66 终端交易属性》

    字节:1 8    1 – 支持非接触磁条 (MSD) 0– 不支持非接触磁条 (MSD) 7    1 – 支持非接触PBOC 0– 不支持非接触PBOC 6    1 – 支持非接触qPBOC 0 ...