一、定义

PACK 模型系列组件是 PUSH 和 PULL 模型的结合体,应用程序不必处理分包(如: PUSH)与数据抓取(如: PULL), 组件保证每个 OnReceive 事件都向应用程序提供一个完整数据包。
在实际开发中,PACk模型是比较推荐使用一种。

二、原理

PACK 模型组件触发监听器对象的 OnReceive(pSender, dwConnID, pData, iLength)事件时,会保证 pData 是一个完整的数据包。 PACK 模型组件会对应用程序发送的每个数据包自动加上 4 字节(32 位) 的包头, 组件接收到数据时根据包头信息自动分包, 每个完整数据包通过 OnReceive 事件发送给应用程序。
PACK包头格式:

前 10 位 X 为包头标识位, 用于数据包校验。 有效包头标识取值范围 0 ~ 1023(0x3FF),当包头标识等于 0 时不校验包头。 后 22 位 Y 为长度位,记录包体长度。 有效数据包最大长度不能超过 4194303(0x3FFFFF) 字节,默认长度限制为: 262144(0x40000)字节。 应用程序可以通过SetPackHeaderFlag() 和 SetMaxPackSize() 分别设置包头标识与最大包长限制。
通过以上分析可知:

  1. 如果选用PACK模型,需要client和server两端都是PACK模型,并且有效包头标识需要设置一样,这样才能c/s之间相互解包成功。

三、编写PACK模型Server端

编码步骤几乎和上一篇push模型步骤一样,有问题的话可以参考上一篇《Hp-Socket高性能网络库一–tcp组件push接收模型》
只需将相应的类型换掉即可

Create_HP_TcpPackServerListener
Create_HP_TcpPackServer

main.cpp如下:

#include "../HpInclude/HPSocket4C.h"
#include <stdio.h>En_HP_HandleResult __stdcall OnPrepareListen(HP_Server pSender, SOCKET soListen)
{TCHAR szAddress[50];int iAddressLen = sizeof(szAddress) / sizeof(TCHAR);USHORT usPort;::HP_Server_GetListenAddress(pSender, szAddress, &iAddressLen, &usPort);return HR_OK;
}En_HP_HandleResult __stdcall OnAccept(HP_Server pSender, HP_CONNID dwConnID, SOCKET soClient)
{BOOL bPass = TRUE;TCHAR szAddress[50];int iAddressLen = sizeof(szAddress) / sizeof(TCHAR);USHORT usPort;::HP_Server_GetRemoteAddress(pSender, dwConnID, szAddress, &iAddressLen, &usPort);const char* msg = "hello world";::HP_Server_Send(pSender, dwConnID, (const BYTE*)msg, strlen(msg));printf("%s:%d connected...\n", szAddress, usPort);return bPass ? HR_OK : HR_ERROR;
}En_HP_HandleResult __stdcall OnSend(HP_Server pSender, HP_CONNID dwConnID, const BYTE* pData, int iLength)
{return HR_OK;
}En_HP_HandleResult __stdcall OnReceive(HP_Server pSender, HP_CONNID dwConnID, const BYTE* pData, int iLength)
{printf("receive data [connID=%d]:%s\n", dwConnID, pData);::HP_Server_Send(pSender, dwConnID, pData, iLength);return HR_OK;
}En_HP_HandleResult __stdcall OnClose(HP_Server pSender, HP_CONNID dwConnID, En_HP_SocketOperation enOperation, int iErrorCode)
{printf("[connID=%d] closed\n", dwConnID);return HR_OK;
}En_HP_HandleResult __stdcall OnShutdown(HP_Server pSender)
{return HR_OK;
}int main()
{HP_TcpServer m_pServer;HP_TcpServerListener m_pListener;// 创建监听器对象m_pListener = ::Create_HP_TcpPackServerListener();// 创建 Socket 对象m_pServer = ::Create_HP_TcpPackServer(m_pListener);// 设置 Socket 监听器回调函数::HP_Set_FN_Server_OnPrepareListen(m_pListener, OnPrepareListen);::HP_Set_FN_Server_OnAccept(m_pListener, OnAccept);::HP_Set_FN_Server_OnSend(m_pListener, OnSend);::HP_Set_FN_Server_OnReceive(m_pListener, OnReceive);::HP_Set_FN_Server_OnClose(m_pListener, OnClose);::HP_Set_FN_Server_OnShutdown(m_pListener, OnShutdown);// 设置包头标识与最大包长限制::HP_TcpPackServer_SetMaxPackSize(m_pServer, 0xFFF);::HP_TcpPackServer_SetPackHeaderFlag(m_pServer, 0x169);if (::HP_Server_Start(m_pServer, "127.0.0.1", 6000)){printf("start tcp server successfully\n");}else{printf("start tcp server failed\n");return 0;}getchar();
}

3.1.验证包头

编写好之后,我们用网口助手测试下,server给我们发送的数据,是否加了4字节包头。
运行server

启动网口助手,请求tcp连接,连接上后收到server发送的"hello world"字符串,如下
0B 00 40 5A 4字节就是组件自动加上的包头

3.2验证粘包,断包

3.2.1正常情况

用网口助手给server发送带包头的数据
“hello world”==>[0B00405A68656C6C6F20776F726C64]
服务端正常显示,接收到"hello world"字符串

3.2.2断包,粘包情况

1.利用网口助手首先发送一帧包头+"He"这样的字节流,此时服务端onReceive()没有被触发;
2.然后在发送剩下的"llo world+包头+Hello world"字节流,此时服务端onReceive()被触发两次,说明组件内部解包的时候,确实解析出两个完整的数据包,符合预期。

四、最后

通过对PACK模型的调试,可以看到Hp-socket还是很友好的帮我处理好了组包,拆包的工作,能保证每次onReceive()被触发,pData都是一个完整的数据包。
下一步,我们通过查看PACK模型的源码,看代码内部针对组包,拆包的工作是如何处理的。
完整代码已上传码云

Hp-socket高性能网络库三--tcp组件pack接收模型相关推荐

  1. Hp-socket高性能网络库二--tcp组件pull接收模型

    一.定义 PULL 模型: 组件接收到数据时会触发监听器对象的 OnReceive(pSender, dwConnID,iTotalLength) 事件,告诉应用程序当前已经接收到多少数据,应用程序检 ...

  2. 高性能网络编程(三)TCP消息的接收

    这篇文章将试图说明应用程序如何接收网络上发送过来的TCP消息流,由于篇幅所限,暂时忽略ACK报文的回复和接收窗口的滑动. 为了快速掌握本文所要表达的思想,我们可以带着以下问题阅读: 应用程序调用rea ...

  3. 【★更新★】高性能 Windows Socket 服务端与客户端组件(HP-Socket v2.0.1 源代码及测试用例下载)...

    HP-Socket 以前为某大型通信项目开发了一套通用 Windows Socket TCP 底层通信组件,组件代号为 HP-Socket.现在把 HP-Socket 的所有代码向大众公开,希望能对大 ...

  4. java socket ip_JAVA 网络编程 TCP/IP、Socket 和协议设计

    [JAVA 网络编程 TCP/IP.Socket 和协议设计] TCP/IP 协议简介 IP 首先我们看 IP(Internet Protocol)协议.IP 协议提供了主机和主机间的通信. 为了完成 ...

  5. socket第三方库 AsyncSocket(GCDAsyncSocket)

    为什么80%的码农都做不了架构师?>>>    Socket描述了一个IP.端口对.它简化了程序员的操作,知道对方的IP以及PORT就可以给对方发送消息,再由服务器端来处理发送的这些 ...

  6. socket套接字TCP API

    socket套接字TCP API socket概念 socket又称"套接字",是计算机网络中进程间通信数据通道的一个端点,或称之为句柄.IP地址+端口号就可以唯一确定一个sock ...

  7. C++socket编程(三):3.9 TCPServer移植到windows中

    如下代码: #ifdef WIN32 #include <Windows.h> #define socklen_t int #else #include <sys/types.h&g ...

  8. 高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了

    1.前言 在本系列文章的上篇中我们回顾了过云的10年里,高性能网络编程领域著名的C10K问题及其成功的解决方案(上篇请见:<高性能网络编程(二):上一个10年,著名的C10K并发连接问题> ...

  9. QT中使用C++ socket通信,socket通信原理三次握手和四次握手详解、客户端与服务端实例详解

    对TCP/IP.UDP.Socket编程这些词你不会很陌生吧?随着网络技术的发展,这些词充斥着我们的耳朵.那么我想问: 1.         什么是TCP/IP.UDP? 2.         Soc ...

  10. 网络编程基础socket 重要中:TCP/UDP/七层协议

    计算机网络的发展及基础网络概念 问题:网络到底是什么?计算机之间是如何通信的? 早期 : 联机 以太网 : 局域网与交换机 广播 主机之间"一对所有"的通讯模式,网络对其中每一台主 ...

最新文章

  1. UITabelView使用流程
  2. libpcap 源代码分析(二)
  3. 链接多个数据库的方法
  4. Android FFmpeg系列——5 音视频同步播放
  5. 现代密码学3.1--定义计算安全的两种方法
  6. Oracle中的move命令
  7. mysql数据库出现幻读,MySQL 幻读怎样处理?_数据库
  8. Python中关于文件路径的简单操作 [转]
  9. 美妆海报模板|来点创意的海报设计(立体剪纸风格)
  10. 服务器基础知识大科普
  11. 计算机桌面左上角 鼠标,鼠标一直跑到桌面左上角怎么解决
  12. 快速入门学习qt5--mian主函数代码详解
  13. 实战大数据平台开发架构讲解,免费大数据教学视频等你来拿
  14. PDF Expert for mac(专业pdf编辑器)兼容12系统兼容m1
  15. centos:/usr/bin/perl is needed by mysql-community-server
  16. 架构设计分布式数据结构与算法面试题(2020最新版)
  17. C语言基础知识:*p++与*++p;(*p)++  与 ++(*p)的理解
  18. 什么是数据库分组查询(详解)
  19. 视觉技术中的图像采集卡
  20. 【2019.07.10】python + OpenCV + adb 实现 自动 微信跳一跳

热门文章

  1. 跳频技术——学习总结(一)
  2. cdr添加节点快捷键_CDR快捷键大全(精编排).doc
  3. 解决keil中 点击setting 程序中断问题
  4. html英文期刊参考文献,英文参考文献标准格式
  5. Word:开机即启动Word程序(转)
  6. 一篇文章看懂自然语言处理——word表示技术的变迁(从bool模型到BERT)
  7. 如何在vue中使用Cesium加载shp文件、wms服务、WMTS服务
  8. Linux的安装教程 | 菜鸟教程
  9. Python 教程之再见 Excel你 Python 的spreadsheets电子表格
  10. 偏最小二乘法(R语言)