IOCP数据中间件

每包最大8K(8192字节),超过8187字节的数据要分包传输

首包有5个字节的包头:4字节数据长度(告诉对方,此次总共将传输几字节数据) + 1字节命令字(告诉对方,此次请求的何种命令)

命令分类
1)请求查询数据,应答查询数据
2)请求提交数据,应答提交数据
3)请求上传文件,应答上传文件
4)请求下载文件,应答下载文件
5)请求发送字符串消息,应答发送字符串消息

unit uFun;
// 应用协议
// cxg 2016-9-23

interface

uses
SysUtils, Classes, PeachCtrl.Net.IocpTcpServer, System.Generics.Collections
;

const // 包长
pack_len = 8192;

const // 命令分类
cmd_qry_req = 1;
cmd_qry_res = 2;
cmd_post_req = 3;
cmd_post_res = 4;
cmd_up_file_req = 5;
cmd_up_file_res = 6;
cmd_down_file_req = 7;
cmd_down_file_res = 8;
cmd_data = 9;

type
THead = packed record // 包头
cmd: Byte;
len: Integer;
packNo: Integer;
packQty: Integer;
ver: Byte;
end;

type
TTask = record // 一次任务
context: Integer;
body: TBytes;
end;

PTTask = ^TTask;

var
g_TaskList: TList<PTTask>; // 任务队列

function ValidHead(AHead: THead): Boolean;
function GetTask(AContext: TCustomIocpTcpServer.TPerHandleData): PTTask;
procedure ProcessRecved(AContext: TCustomIocpTcpServer.TPerHandleData);

implementation

function ValidHead(AHead: THead): Boolean;
begin
Result := (AHead.cmd >= 1) and (AHead.len > SizeOf(THead)) and (AHead.packNo >= 1) and (AHead.packQty >= 1);
end;

function GetTask(AContext: TCustomIocpTcpServer.TPerHandleData): PTTask;
var
i: Integer;
begin
Result := nil;
if (AContext = nil) or (g_TaskList.Count = 0) then
Exit;
System.TMonitor.Enter(g_TaskList);
try
for i := 0 to g_TaskList.Count - 1 do
begin
if g_TaskList.Items[i].context = Integer(AContext) then
begin
Result := g_TaskList.Items[i];
Exit;
end;
end;
finally
System.TMonitor.Exit(g_TaskList);
end;
end;

procedure ProcessRecved(AContext: TCustomIocpTcpServer.TPerHandleData);
var
pTask: PTTask;
buf: TBytes;
head: THead;
bodyLen: Integer;
headLen: Integer;
begin
headLen := SizeOf(THead); // 包头长
if AContext.RingBuffer.NoProcessBufLen < headLen then
Exit;
AContext.RingBuffer.Peep(head, headLen); // 取包头
if not uFun.ValidHead(head) then // 校验包头
Exit;

if head.packQty = 1 then // 一批次只有一个包
begin
if AContext.RingBuffer.NoProcessBufLen < head.len then
Exit;
New(pTask);
pTask.context := Integer(AContext);
bodyLen := head.len - headLen;
SetLength(pTask.body, bodyLen);
SetLength(buf, head.len);
AContext.RingBuffer.Pop(buf[0], head.len);
Move(buf[headLen], pTask.body[0], bodyLen);
g_TaskList.Add(pTask); // 提交任务队列
end
else if head.packQty > 1 then // 一批次有多个包
begin
if head.packNo = 1 then // 首包
begin
if AContext.RingBuffer.NoProcessBufLen < pack_len then
Exit;
New(pTask);
pTask.context := Integer(AContext);
SetLength(pTask.body, head.len - head.packQty * headLen); // 一次分好缓存
SetLength(buf, pack_len);
AContext.RingBuffer.Pop(buf[0], pack_len);
bodyLen := pack_len - headLen;
Move(buf[headLen], pTask.body[0], bodyLen);
end
else
if head.packNo > 1 then // 非首包
begin
if AContext.RingBuffer.NoProcessBufLen < head.len then
Exit;
pTask := GetTask(AContext);
if pTask = nil then
Exit;
SetLength(buf, head.len);
AContext.RingBuffer.Pop(buf[0], head.len);
bodyLen := head.len - headLen;
Move(buf[headLen], pTask.body[(head.packNo - 1) * bodyLen], bodyLen);
if head.packNo = head.packQty then // 包都收齐
g_TaskList.Add(pTask); // 提交任务队列
end;
end;
end;

end.

IOCP数据中间件的更多相关文章

  1. 咏南IOCP REST中间件

    咏南IOCP REST中间件 让DELPHI7也能编写REST服务. 使用IOCP通信+UNIDAC数据库引擎. 客户端跨开发语言调用.

  2. mycat数据中间件、nginx

      MyCat & Nginx  课程目标 目标1:理解MyCat分片,能够配置MyCat分片 目标2:掌握Nginx的安装与静态网站部署 目标3:掌握Nginx的静态网站部署 目标4:理解N ...

  3. java 中间件

    先说中间件:非底层操作系统软件.非业务应用软件,不是直接给最终用户使用的,不能直接给客户带来价值的软件,统称中间件.常见的有如下几种:服务中间件.集成中间件.数据中间件.消息中间件.安全中间件. 其中 ...

  4. [NewLife.XCode]数据初始化

    NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netstandard,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量结合示 ...

  5. [NewLife.XCode]脏数据

    NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netstandard,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量结合示 ...

  6. [NewLife.XCode]数据层缓存(网站性能翻10倍)

    NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netcore,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量结合示例代码和 ...

  7. node的express框架,核心第三方模块body-parser 获取我们所有post请求传过来数据

    - 安装 body-parser模块- npm install body-parser -S - 调用- let bodyParser=require('body-parser'); - 设置中间件- ...

  8. [NewLife.XCode]分表分库(百亿级大数据存储)

    NewLife.XCode是一个有15年历史的开源数据中间件,支持netcore/net45/net40,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量 ...

  9. koa2中间件

    在我看来,前端框架的中间件的思想来源于传统后端的切面编程(AOP)思想,比如我们常见的身份校验(JWT). axios的拦截器也是基于这种程序设计模式的. 在koa中,实际上是由一个数组对象来保存所有 ...

随机推荐

  1. HttpClient 接口调用

    String url = "http://127.0.0.1:8080/api"; //然后根据表名获取公司信息 HttpPost httppost = new HttpPost( ...

  2. Android(java)学习笔记171:服务(service)之绑定服务调用服务里面的方法

    1.绑定服务调用服务里面的方法,图解: 步骤: (1)在Activity代码里面绑定 bindService(),以bind的方式开启服务 :                     bindServ ...

  3. Error:Failed to resolve: com.afollestad:material-dialogs:

    http://www.chenruixuan.com/archives/1068.html 背景: 同事把Android项目直接考给了我...我在Android Studio上运行,然后提示: Err ...

  4. 路由器wan口ip地址显示0.0.0.0怎么办

    http://m.xuexila.com/luyouqi/671049.html 这个网络时代里面我们最常用来连接网络的设备就是路由器了,现在的社会不管是工作还是生活几乎都离不开网络了,同时我们也要学 ...

  5. spring注解开发-声明式事务(源码)

    1. 环境搭建与测试 1)导入相关依赖 数据源.数据库驱动.Spring-jdbc模块 <dependency> <groupId>org.springframework< ...

  6. 使用Eclipse中的反编译插件jadClipse查看Class源码

    功安装完插件jadClipse 之后便可以查看源码class文件了 但是对于自己代码的class文件,直接复制过来却看不到,需要以下操作. 将此文件以及文件夹直接拷贝到Eclipse中发现 右击项目- ...

  7. Python3使用PyMySQL操作数据库

    1. 安装PyMySQL pip install PyMySQL 关于PyMySQL的详细内容可以查看官方文档  Github 2. 创建表 在某个数据库内,使用以下指令建表 CREATE TABLE ...

  8. 在Windows上安装和配置Jenkins

    一.windows上安装Jenkins 1.官网下载Jenkins安装包Jenkins.msi ,进入安装模式,选择默认配置,安装完成之后,就会默认打开浏览器 http://localhost:808 ...

  9. (2) OpenSSL命令

    openssl命令的格式是"openssl command command-options args",command部分有很多种命令,这些命令需要依赖于openssl命令才能执行 ...

  10. CentOS7安装Tomcat9并配置

    划重点:安装tomcat之前必须先安装jdk  安装教程 1.下载 Tomcat 9 CentOS 7 下创建目录并下载文件:// 链接已更新 cd /usr/local/ mkdir tomcat ...