顺极科技闸机、客户端连接服务器将使用新的中间件DLL,本中间件DLL为TCP传输方式,可以传送命令,如开门、关门、文字显示等,也可以传输文件,如图片数据,我公司闸机的指纹数据和图片使用DLL动态库传输,数据是按实际大小传输的,传输性能高,中间件的传输是内存流的传输,是底层传输中间件,与语言的编码无关。目前调用已经翻译成delphi工程,并做了相关DEMO,我们将择时公开本DEMO源码,以供大家二次开发参考。
//DLL相关代码,DLL为VC制作
unit importf;
interface
const sjdllname='sj_transdata_tp.dll';
const __SHUN_JI_WWW='www.HeroGod.com\0';
function sj_sendto(Data:PChar;len:Integer;RemIp:PChar;iplen:Integer=0;
nRemotePort:Integer=0):Integer; cdecl;
function sj_startrev(confirms:PChar;maxBufSize:Integer=1024*40;{*如果为0,则为40Kb,如果只是传命令,无图片传输,只需1k*/} nPort:Integer=0{/*监听的端口,0为默认的5101*/}):Integer cdecl;//开始接收
function sj_havedata(timeout:Integer=500):Integer;cdecl;//询问是否有数据来到,不停的询问
function sj_readdata(Data:PChar;dataLen:PInteger;ip:PChar;iplen:PInteger):Integer;cdecl;//如果有数据,则接收数据,得到数据的长度和IP地址
function sj_stoprev():Integer;cdecl;//停止接收数据
implementation
function sj_sendto;cdecl;external sjdllname;
function sj_startrev;cdecl; external sjdllname;
function sj_stoprev;cdecl;external sjdllname;
function sj_havedata;cdecl;external sjdllname;
function sj_readdata;cdecl;external sjdllname;
end.
{#define __SHUN_JI_WWW "www.HeroGod.com\0"
/************************************************************************/
/*顺极科技TCP传送中间件,本中间件内部为多线程,接收和发送都是按实际字节传输
DLL为unicode环境,但函数只关心字节本身,不涉及编码问题
接收时,最多允许1000个客户端,这时要注意传输量和客户的总流量
本中间件可传输任意大小的数据包,默认为40KB
*/
/************************************************************************/
/* 开始接收数据,本函数只用于接收的开始,实际上启动TCP监听
confirms:确认字符
必须为www.HeroGod.com,否则会失败
maxBufSize:缓存大小
缓存大小在开始后不能改变,应比实际传输的最大值大
nPort:默认端口
TCP监听的端口,无特殊情况,应使用默认值
*/
int sj_startrev(char* confirms=__SHUN_JI_WWW,int maxBufSize=1024*40,/*如果为0,则为40Kb,如果只是传命令,无图片传输,只需1k*/int nPort=0/*监听的端口,0为默认的5101*/);//开始接收
/*
停止接收数据,在开始后用于停止
注意,顺序不能错
*/
int sj_stoprev();//停止接收数据
/*
询问内部是否有数据
应在开始接收后,不停的询问是否有数据到来,调用为阻塞式
timeout:如果没有数据,等待的超时时间
超时只在数据没有到来时起作用,数据到来时,立即返回,因此设置较长时间不会影响数据接收
如果在多线程中调用,可以将超时设置长一些,以节省资源
询问到一次数据后,必须读取,否则再次询问将返回0
如果有数据,返回的是数据的长度
*/
int sj_havedata(int timeout=500);//询问是否有数据来到,不停的询问
/*
读取数据
在sj_havedata返回有数据后,应立即调用此函数读取数据,否则数据可能会被新来的数据覆盖
Data:接收到的原始数据,该数据应先分配好,接收频繁的话,应事先分配传输时的最大值的内存,最好是全局变量,以节省资源
datalen:接收到的数据长度
ip:数据来源的IP地址,也应事先分配好ip的最大值,比如24字节的数组
iplen:ip地址的字符串的总长度.
*/
int sj_readdata(char *Data,int& dataLen,char *ip,int& iplen);//如果有数据,则接收数据,得到数据的长度和IP地址
/*
发送数据,该函数是独立的,如果只是发送数据,可以不调用以上函数而直接发送数据
Data:要发送的数据缓存
len:要发送的长度
RemIp:目标IP地址,要在IP地址的有效字符串之后加'\0'
iplen:目标地址长度,为RemIp带'\0'的总长度,如果是0,则RemIp必须为'\0'结束
程序内部会执行:RemIp[iplen]='\0';
nRemotePort:远程端口,可以使用0作为默认端口,默认为5101
*/
int sj_sendto(char* Data,int len,char* RemIp,int iplen=0,int nRemotePort=0/*要发送的远程的端口,0为默认的5101端口*/);//发送数据
}
//接收数据的线程,收到数据后,通过消息发送到主窗体
unit ReadThread;
interface
uses
Windows,Classes,Messages;
const USRMSG_RECVDATA= WM_USER+101;
const USRMSG_CLOSETHD=WM_USER+102;
type TRevDataSUT=record
mData:array[0..1024*40] of Char;
nDatalen:Integer;
cIp:array[0..23] of Char;
nIpLen:Integer;
end;
type TPRevDataSUT=^TRevDataSUT;
type
TReadThd = class(TThread)
private
{ Private declarations }
m_hWnd:HWND;
protected
procedure Execute; override;
public
bRunning:Boolean;
constructor Create(hwnd:HWND);
end;
implementation
uses importf;
constructor TReadThd.Create(hwnd:HWND);
begin
bRunning:=True;
FreeOnTerminate:=True;
m_hWnd:=hwnd;
inherited Create(False);
end;
procedure TReadThd.Execute;
var bHav:Boolean;
vRevDataStu:TRevDataSUT;
begin
{ Place thread code here }
while bRunning do
begin
bHav:= sj_havedata(500)=1;
if bHav then
begin
bHav:= sj_readdata(vRevDataStu.mData,@vRevDataStu.nDataLen,vRevDataStu.cIp,@vRevDataStu.nIpLen)=1;
PostMessage(m_hWnd,USRMSG_RECVDATA,Integer(@vRevDataStu),0);
end;
end;
PostMessage(m_hWnd,USRMSG_CLOSETHD,0,0);
end;
end.
主窗口,比较简单,应该能看懂吧
unit mainf;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Spin,ReadThread;
type
TFrmMain = class(TForm)
grp1: TGroupBox;
lbl1: TLabel;
se_lsnport: TSpinEdit;
btn_start: TButton;
btn_stop: TButton;
mmo_recv: TMemo;
lbl2: TLabel;
grp2: TGroupBox;
lbl3: TLabel;
se_rm_port: TSpinEdit;
lbl4: TLabel;
edt_rm_ip: TEdit;
mmo_send: TMemo;
btn_send: TButton;
procedure FormCreate(Sender: TObject);
procedure btn_sendClick(Sender: TObject);
procedure btn_startClick(Sender: TObject);
procedure btn_stopClick(Sender: TObject);
private
{ Private declarations }
vReadThd:TReadThd;
procedure RevDataFun(var mmsg:TMessage);message USRMSG_RECVDATA;
procedure RevStopFun(var mmsg:TMessage);message USRMSG_CLOSETHD;
public
{ Public declarations }
end;
var
FrmMain: TFrmMain;
implementation
{$R *.dfm}
uses importf;
procedure TFrmMain.btn_sendClick(Sender: TObject);
var nRet:Integer;
sendstr:string;
sendlen:Integer;
ipstr:string;
iplen:Integer;
begin
sendstr:= mmo_send.Text;
sendlen:= Length(sendstr);
ipstr:=edt_rm_ip.Text;
iplen:=Length(ipstr);
nRet:= sj_sendto(@sendstr[1],sendlen,@ipstr[1],iplen,se_rm_port.Value);
if nRet<>1 then
begin
ShowMessage('发送出错');
Exit;
end;
mmo_send.Clear;
end;
procedure TFrmMain.btn_startClick(Sender: TObject);
var rRet:Integer;
begin
rRet:=sj_startrev(__SHUN_JI_WWW,1024*40,0) ;
if rRet=0 then
begin
ShowMessage('开始出错');
Exit;
end;
//开线程
vReadThd:=TReadThd.Create(Handle);
btn_start.Enabled:=False;
btn_stop.Enabled:=True;
end;
procedure TFrmMain.btn_stopClick(Sender: TObject);
begin
vReadThd.bRunning:=False;
WaitForSingleObject(vReadThd.Handle,INFINITE);
sj_stoprev();
btn_start.Enabled:=True;
btn_stop.Enabled:=False;
end;
procedure TFrmMain.FormCreate(Sender: TObject);
begin
edt_rm_ip.Text:='127.0.0.1';
se_rm_port.Value:=5101;
se_lsnport.Value:=5101;
btn_stop.Enabled:=False;
mmo_recv.Clear;
mmo_send.Clear;
end;
procedure TFrmMain.RevDataFun(var mmsg: TMessage);
var pData:TPRevDataSUT;
str1,str2:string;
begin
pData:=TPRevDataSUT( mmsg.WParam);
str1:=StringOfChar(Chr(0),pData.nDatalen);
CopyMemory(@str1[1],@pData.mData,pData.nDatalen);
str2:=StringOfChar(Chr(0),pData.nIpLen);
CopyMemory(@str2[1],@pData.cIp,pData.nIpLen);
mmo_recv.Lines.Insert(0,Format('来自:%s'#13#10' 数据为:%s'#13#10#13#10,[str2,str1]));
str1:='';
str2:='';
end;
procedure TFrmMain.RevStopFun(var mmsg: TMessage);
begin
mmo_recv.Lines.Insert(0,'已经停止'#13#10);
end;
end.