【DIOCP知识库】连接上下文TIocpClientContext

【概述】

     该类管理远程连接,每一个远程连接会对应一个该类的实例,开发时可以通过继承该类,扩展属性,可以存储更多的连接信息,可以重写OnRecvBuffer方法进行数据逻辑的处理

 

【字段/属性说明】

  • property RemoteAddr: String read FRemoteAddr;

说明:远程连接IP。

 

  • property RemotePort: Integer read FRemotePort;

说明:远程连接端口。

 

  • property SocketHandle: TSocket read FSocketHandle;

说明:连接套接字.

 

【方法说明】

  • procedure DoCleanUp;virtual;

说明: 该方法从对象池中获取一个对象时(TIocpTcpServer.getClientContext)执行该方法,进行相关资源的清理,在该实例不再需要,放回到连接池时(TIocpTcpServer.releaseClientContext)也会执行该方法,该方法同时只会一个线程访问和执行。

 

  • procedure PostNextSendRequest; virutal;

说明:该方法在发送请求得到响应完成并成功(TIocpSendRequest.HandleResponse),会再次调用该方法可以进行下一个请求的发送,如果响应中发现GetLastError不为0或者服务关闭已经停止则不会执行该方法

 

  • procedure OnRecvBuffer(buf: Pointer; len: Cardinal; ErrCode: WORD); virtual;

说明:如果接收到远程数据时会触发该函数的执行,该方法在响应投递的接收数据的请求(TIocpRecvRequest.HandleResponse)中调用,如果响应中发现GetLastError不为0或者服务关闭已经停止则不会执行该方法。

 

 

==========================================

DIOCP官方社区|MyBean官方社区

http://diocp.wedelphi.com/

==========================================

【DIOCP知识库】-粘包的处理

什么是粘包:

   第一次发送  12345, 第二次发送abcde, 底层socket可能会一次性进行发送12345abcde,或者对方可能一次性进行了接收,那接收的时候,你可能想分两次接收才对,第一次接受到12345, 第二次想接收abcde,但是事与愿违,一次就接收完了,这就是粘包的问题。需要自己处理。

 

怎么样处理粘包:

  常见的方法是在包数据的前面加长度比如我先发送一个字节代表长度5 然后再发数据包12345, 这样接收的时候,先读数据包长度,然后再获取包的数据,这样就可以处理粘包问题了。

diocp3的StreamCoder,可以让你直接发送TStream对象,不需要处理粘包的问题。接收到的数据对象就是一个TStream对象

==========================================

DIOCP官方社区|MyBean官方社区

http://diocp.wedelphi.com/

==========================================

【杂谈接口】接口对象的生命周期-对象所占用的内存块清理

【概述】

相信经常使用接口的朋友们,经常碰到访问违规异常(Access violation),很多情况下无法理解,认为是编译器的Bug,然后去绕开它,不追其根源,把责任推给IDE,推给编译器(其实本人以前也经常这样想)。其实每个异常都是有原因的,碰到这种问题不要绕开,如果目前无法解决,至少要清楚的知道它出现的起因,不放过每一次追根到底的机会。这才是做程序员的应有的心态。(好像有点扯远了…)

 

【问题描述】

今天公司外包模块中,外包人员反应出现一个很奇怪的问题,说模块中无故出现了AV异常。调试果然如此,而且每次都能出现,每次都能出现的异常就好解决,

最初的代码如下:

一个点击按钮事件中包含如下一段代码:

 

begin
  ....
  (TmBeanFrameVars.GetBean('ef_pcy_frmTree'as INormalSelector).executeSelect(lvPass);
  ....
end;

这样程序在退出函数的时候引发了一个AV异常(end;运行之后),这时候一般对接口不了解的都无从下手。也无从下手进行调试。

 

【问题分析】

首先上面这句简单的访问其实会出现接口的临时变量,而这个变量在函数退出的时候会执行清理,因为executeSelect函数中释放了插件的实例,然后清理临时接口变量时会触发接口对象的__release方法。这个时候引发的一个异常。

我改造一下代码,让错误在函数退出之前出现,完整代码如下。

I`VNO]}GF`0}M_PHZR9C2{U

我用两个局部变量,这样改造后,在执行lvIntf := nil的时候就会出现AV错误。

image

我顺便把executeSelect代码贴一下,可以看到这个插件是一个窗体对象实例。在执行这个函数里面会把窗体显示,然后进行了释放,然后退出了函数。

 

大概的原因明白后,我们调整下代码,代码如下:

PFRPD@W3BOX1E[R2B~V[~K9

注意红色部分,选取完后(释放实例后),然后马上清理接口变量,这个时候,其实内存块应该还是完整的(个人推测),所以清理时不会出现访问违规异常。

 

下面我来做个调试证明我的推测

R7$@CSJ6K@)E74)1XGHER@V

看红色框出来部分,两个接口变量在释放完后,和之前的指向的内存块中值是一样的(我只获取了一个值,其实可以进行完整对比),然继续执行。

{8FA%_B][VZU%_SCWT7%V@U

在看看红色部分,这个时候(其实执行玩cdsOrgan.Append就出现了),lvIntf指向的内存块已经被清理了,因为有新的内存申请。所以后面在清理lvIntf := nil的时候出现访问违规错误。

 

好了到了这个时候,我们应该发现引发异常的真正原因了:在清理接口变量时,访问了一块不可预知的内存块,所以导致了访问违规错误。所以请大家在使用接口过程中注意接口的清理工作。

 

*认真阅读会收获更多。

 

==========================================

DIOCP官方社区|MyBean官方社区

http://diocp.wedelphi.com/

==========================================

【杂谈指针】- 指针的移动

刚刚在群里看到一个这样的问题

MonoPixel: PByte;

Inc(Integer(MonoPixel));这个在32位下没问题,为啥64位不能编译呢?

 

咋一看,以为是把里面的值进行累加,后来一想应该是移动一下指针。

对于这种移动指针的做法有两个错误:

第一个是用了Integer,来转换指针如果在32位下面显然是没有问题的,但是如果是64位,指针是64位,显然再用Integer是错误的。

第二个转换成Ineger后加一,那就相当于整数值 + 1,在PByte时没有问题,因为Byte也是一个字节。但是如果是PInteger指针就会出现错误。

 

我们来看下代码:

如果是PInteger下面应该怎么样做:

var
  p, d:PInteger;
  x : array [0..10] of Integer;
begin
  x[5] := 120;
  p := @x;
  d := p;
  Inc(d, 5);

 

 

首先所有的指针都是一个整数值

image

可以看到如果用inc移动指针,并且会按照指针的类型进行累加,上面PInteger类型Inc后是增加的SizeOf(Integer)。指向数组的下一个元素。

如果单纯的转换成整数来 + 1会 指针的值就是$12EA75显然不是指向下一个元素。当然你取到的值也是错误的。如下面的图

image

显然d^不是我们想要的数据。

除了用inc,也可以这样做,下面的做法也是正确的。

image

请操作指针的朋友们注意啦。

*以上代码在XE6下面测试运行

 

*注意没有IntPtr类型的可以自己定义下类型

type

   IntPtr = cardinal

 

==========================================

DIOCP官方社区|MyBean官方社区

http://diocp.wedelphi.com/

VirtualBox与VMWare网络冲突

VirtualBox安装一个XP后,发现老是上不到网,怎么折腾都不行,

后来发现设备管理器中 vmware accelerated amd pcnet adapter #2显示黄色感叹号

不对呀,这是VirtualBox怎么是vmware的东西,后来百度后,发现禁用vmware网卡,

image

也把VirutalBox 的网卡去掉了vmware bridage Protocol ,重启N次,里面还是那个vm的网卡,

后来百度这个词(vmware accelerated amd pcnet adapter)发现了这篇文章

http://vbox.blogcn.com/6

 

前几日分享了Virtualbox快照备份恢复系统的方法,但是发现从备份中恢复的系统似乎有很多问题,比如经常出现.DLL错误,出现mysql无法启动等问题,搞来搞去,真的很麻烦~~~

搞的都无语了~~

因为网速不给力,所以就在晚上重新下载了个XP ISO,还是雨林木风的~~今天安装好了之后发现,又出现vmware accelerated amd pcnet adapter显示黄色感叹号,真的是没有一件顺利的事情~~NND.

找了好多驱动没弄好,最后一不小心被我发现了解决的办法~~

在更新网卡驱动的地方右键--然后选择更新驱动,然后选择不搜索,自己安装,然后选择AMD的那个网卡即可,这样就能正常上网了,有浪费了我半个多小时,哎,我就想好好用下虚拟机,有这么困难么~~~真的搞的没办法~~~

终于搞定了

虚拟机的网络设定

image

关于SimpleMsgPack中swap引发的问题大端法和小端法研究笔记

今天diocp裙中[珠海]-芒果反应了一个关于SimpleMsgPack的问题

msgPack.AsFloat = 2.507182;

经过编码再解码后,会直接触发异常。

 

因为msgPack的标准,在打包的数据是大端法IEEE 754

下面是msgPack的标准说明

Float format family stores a floating point number in 5 bytes or 9 bytes.
float 32 stores a floating point number in IEEE 754 single precision floating point number format:
+--------+--------+--------+--------+--------+
|  0xca  |XXXXXXXX|XXXXXXXX|XXXXXXXX|XXXXXXXX
+--------+--------+--------+--------+--------+

float 64 stores a floating point number in IEEE 754 double precision floating point number format:
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|  0xcb  |YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
where
* XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX is a big-endian IEEE 754 single precision floating point number
* YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY is a big-endian
  IEEE 754 double precision floating point number

 

小端法变大端法把自己顺序调整下就好了

在SimpleMsgPack中有一个这样的函数,可以对Double类型的数据进行交换字节数。

procedure swap64Ex(const v; out outVal);
begin
  // 7F F5 B8 6F B5 0E 04 40

  // 40 04 0E B5 6F B8 F5 7F
  PByte(@outVal)^ := PByte(IntPtr(@v) + 7)^;
  PByte(IntPtr(@outVal) + 1)^ := PByte(IntPtr(@v) + 6)^;
  PByte(IntPtr(@outVal) + 2)^ := PByte(IntPtr(@v) + 5)^;
  PByte(IntPtr(@outVal) + 3)^ := PByte(IntPtr(@v) + 4)^;
  PByte(IntPtr(@outVal) + 4)^ := PByte(IntPtr(@v) + 3)^;
  PByte(IntPtr(@outVal) + 5)^ := PByte(IntPtr(@v) + 2)^;
  PByte(IntPtr(@outVal) + 6)^ := PByte(IntPtr(@v) + 1)^;
  PByte(IntPtr(@outVal) + 7)^ := PByte(@v)^;
end;

然后我重载了一些函数 这个函数对传入的Double进行交换字节然后返回Double类型

function swap(v:Double): Double; overload;
begin
  swap64Ex(v, Result);
end;

 

上面这个浮点数据 2.507182,经过交换后 如果仍然用Double类型来存放会是一个NaN, 会触发一个无效的浮点型数据的异常。因为不符合小端法的IEEE规则。

经过稍微修改后正常

function swap(v:Double): Int64; overload;
begin
  swap64Ex(v, Result);
end;

返回的值用Int64来存放这样就好了。

 

注意不要把一个不是Double类型的数据直接强制转换成Double类型,因为Double是有标准字节格式的,当然Single一样。

 

感谢,qdac-swish, 小白一起帮忙验证推理。

【MyBean调试笔记】关于单元的释放顺序

【概述】

DEMO提交人:惠商软件  2508696439

问题描述:MDIConsole, DEMO如果Forms单元引用顺序放在mybean.console.pas文件之后如下图所示时:

image

创建同一EXE内的MDI子插件并显示,在不关闭MDI子窗体的情况下,关闭主EXE时,会造成关闭时产生访问违规错误。

image

【调试过程】

看了问题,能重现,能重新的问题就不算什么问题了,一定可以找到原因的,开启debug dcus后,发现错误停留产生时,停留在Screen.FSaveFocusedXXX这一句。调试发现果然Screen为nil了。

(PEV87O}1LU$O[ESGWQ_R_K

 

【问题分析】

mybean在创建插件TComponent子插件时会传入beanFactory.VclOwners, 这样在程序关闭时,清理类工厂时,会释放他,并清理他的子组件,达到自动清理的插件的目的,因为getBean的插件没有手动关闭,是等待清理beanFactory时进行清理的,清理的时候,Screen已经被清理,所以产生了该错误。

我们看看工程文件的引用顺序

program MDIConsole;

uses
  FastMM4,
  FastMM4Messages,

  mybean.console,
  mybean.core.beanFactory,

  Forms,

上面代码来看是会先清理Forms,然后再清理mybean.console,和mybean.core.beanFactory单元,但是因为mybean.core.beanFactory里面引用了Forms单元,所以清理顺序变成了

1.mybean.core.beanFactory,

2.Forms,

3.mybean.console,

 

mybean.console单元中管理了所由的类工厂插件接口,因为类工厂是通过接口来决定生命周期的,所以在清理mybean.console单元的时候,才会释放最后一个工厂接口的引用,也就是释放vclOwners和他的子插件,这个时候application和screen实例都已经被释放了。所以procedure TCustomForm.BeforeDestruction;中访问Screen才会引发异常。

现在来优化下mybean的核心类。

mybean.core.beanFactory和mybean.console单元中都引用Forms单元,这样不管你顺序怎么调整,都让Forms单元成为在这两个单元后面。然后在mybean.core.beanFactory被清理时,清理工厂接口资源。

使顺序变成这样

1.mybean.core.beanFactory,

2.mybean.console,

3.Forms。

【MyBean调试笔记】接口的使用和清理

【DEMO信息】

有问题的DEMO, 由芒果提交

【问题描述】

双击Tab页面关闭页面和插件的时候出现AV异常

image

【问题调试】

我们在调试的时候出现这个错误时断点停在这里

image

可以看到停留在这个位置@IntfClear,指针清理的位置

image

好我们来调试下这个过程,跟一下是什么时候出现的, 在end 处下个断点后切换到cpu页,我们看到在ret之前调用了一过程,这个地址应该是做一些清理工作后然后返回到调用者地址,

`TDZCGURW[(RGU7B72)5CNY

跟进去后,一会就跳到错误的界面,可以说明在清理时出现的,这个时候我们来看看这段代码

复制代码

procedure TfrmMain.pgcMainMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  Index: Integer;
  lvPluginForm: IPluginForm;
  lvTabShtEx:TTabShtEx;
begin
  // 左键点击并且双击
  if (Button = mbLeft) and (ssDouble in Shift) then
  begin
    Index := pgcMain.IndexOfTabAt(X, Y);
    if Index >= 0 then
    begin
      lvTabShtEx := TTabShtEx(pgcMain.Pages[Index]);
      lvPluginForm := lvTabShtEx.PluginForm;
      if Application.MessageBox('确认要关闭画面吗?', '询问', MB_OKCANCEL + MB_ICONQUESTION) = IDCANCEL then
        Exit;
      lvPluginForm.freeObject;
      pgcMain.Pages[Index].Free;
    end;
  end;
end;

复制代码

这段代码中有一个lvPluginForm为接口IPluginForm变量, 过程在退出时会执行lvPluginForm := nil和其他一些资源的清理工作,清理的时候会触发对象的__release方法,但是我们看到这个对象已经释放掉了,然后在进行清理的时候出现了上面看到的访问违规的错误。

【问题解决】

找到出现问题的根本,解决起来就很快了,尽量不要等到过程清理时在去清理你的资源,特别是可能访问不存在的资源。在end;之前 加一句lvPluginForm := nil;这样就好了

分类: [MyBean说明书]

radxa-折腾系统ubuntu

想想今天从公司带了个键盘回来,继续折腾了下radxa板子,先折腾上ssh,听波哥的先折腾ssh。接上键盘,鼠标。

 

进入系统,rock用户,用b2andriod切换到了一次andriod挺正常,又切换回ubuntu,把无线连上去了, 百度下什么是ssh…

 

ssh,总的来说ssh是安全的可以让你远程做很多事情,好吧原来是这样,怎么装ssh?

sudo apt-get install openssh-server

啥意思?在哪里输入?

百度一下

ctrl + alt + t,进入命令模式

输入上面命令

开始安装了

装完后, 然后确认sshserver是否启动了:(或用“netstat -tlp”命令)

ps -e | grep ssh

http://www.cnblogs.com/chen1987lei/archive/2010/12/02/1894768.html

 

启动好后,然后在笔记本上面弄个ssh客户端

下载了一个MobaXterm_v7.3 可以通过ssh连接上ubuntu了。发现不能用root登陆ssh,要百度下

修改root 的密码

sudo passwd root

修改成功后,ssh还是不能登陆,波哥说要加入ssh配置

百度

http://blog.sina.com.cn/s/blog_7e64a87b0100rn8w.html

 

$ sudo vi /etc/ssh/sshd_config

找到PermitRootLogin no一行,改为PermitRootLogin yes

各种不适用来了,反人类的vi编辑器(问了别人才知道vi是编辑器)

上面是说用vi 编辑sshd_config文件

幸好有猫叔和洞主指导…

输入上面命令后i进入编辑模式,然后找到

开始是

PermitRootLogin without-password

改成

PermitRootLogin yes

shift + “:”

输入wq!;保存退出

重启ssh,搞定

root可以登陆了,试一下reboot,可以重启

 

x!也是保存退出

q!是不保存退出

….听说vi是最优秀的编辑器。。。 以后我能适用么….

radxa-折腾第一步-刷机

 

我的电脑环境是:win64位,

板子回来是andriod的系统。

首先的装驱动, 下载固件

可以点击查看这篇文章

http://www.qdac.cc/?p=949

 

我是下载的这个固件radxa_rock_pro_dual_boot_20141022_update.zip

 

解压后里面有新的刷机工具

 

安装驱动

如果你已经安装好了USB驱动,请跳过此步骤。

使用RK Driver Assistant tools安装

在此安装过程中不需要连接Rockchip设备,只需要下载并解压RKDriverAssistant.zip,然后在RKDriverAssistant目录下的DriveInstall.exe上双击运行即可。 如果你之前为其他Rockchip设备安装过Rockchip USB驱动,确保首先点击”Uninstall Driver”。

RK Driver Assistant Install Uninstall.jpg

 

这是板子的图

 

 

官方的进入刷机模式帖子

http://wiki.radxa.com/Rock/Loader_mode/zh_cn

我折腾很久没折腾好,后来还是在群里问了。

 

第一个是在开机状态下<OTG线接电脑,打开刷机软件>

recovery key<长安> –>reset key<关掉后就可以松开> –>然后按Power。这个时候就进入了刷机状态。

 

第二种方法,关电源

按住recovery key 然后插线<OTG连接电脑> 就进入刷机状态。

 

好了可以用刷机工具写入固件了

 

密码是rock<没键盘…还没测试>