两个软件之间如何进行数据交换? (200分)

  • 主题发起人 主题发起人 jeefong
  • 开始时间 开始时间
J

jeefong

Unregistered / Unconfirmed
GUEST, unregistred user!
 现要写两个软件A和B, 软件A负责本地数据的采集,软件B负责将这些数据向网络发送, 软件B还要将网络接收到的控制信号交给软件A处理.
问题:
 有什么办法可以将软件A采集到的数据, 交给软件B,软件B又怎样实现将收到的控制数据交给软件A? 即两个软件之间的数据交换,不能做成一个软件,最好也不要用到数据库之类的文件读写操作,因为要实时发送, 要尽量免去读写文件的时间.
 数据量不大, 但是每分每秒都会发生. 
 
常用的方法有:
1、Socket通信
2、COM/DCOM组件(或其它组件形式)调用
 
用内存映射文件,或wm_copydata发送消息
 
注意: 两个软件在同一台电脑上运行

DCOM怎样做? 不太懂.
 
通过数据库啊
 
需要有接口可以调用!
 
数据量不大,处理速度够快,直接通过消息传递即可
 
各位能否提供相关例子,或详细的说明,或一小段源码(VB,Delphi,CBuilder均可).
我头昏了, 200分呀.
 
用消息wm_copydata,最方便了。
 
下面是我的思路,源于我们的一个项目中的实施方式。为什么要采用COM/DCOM方式呢?因为这样可以实现两个优点:1、程序位置透明性,A程序与B程序可以在一台机器上,也可以不在一台机器上;2、语言无关性,A程序和B程序可以用不同的编程语言来开发和调用。
此实施方法是假设与对端服务器的通信是采用Socket的,所以才有一系统关于Socket通信的代码,但代码的具体实现需要你自己来完成。
/*
在使用前需要自己定义以下数据类型,实现以下方法:
CmdStruc类型,该类型的结构用于存储要发送的指令数据
CmdResultStruc类型,该类型的结构用于存储业务处理结果
InitWinsock方法,初始化Winsock
FinlWinsock方法,关闭Winsock
SockCliConn方法,建立一个Winsock客户端连接对端服务器
SendCommand方法,发送业务处理指令
*/

//IDL定义:
//HRESULT _stdcall TransData([in] BSTR Cmd, [out] BSTR * ReturnInfo, [out, retval] int * Result );

STDMETHODIMP TGatheringIntfImpl::TransData(BSTR Cmd, BSTR* ReturnInfo,
int* Result)
//将采集到的信息传输给远端的业务处理服务器, 并获取返回值
//参数说明:Cmd:要传给远端服务器的指令;ReturnInfo:返回信息;Result:处理结果
//返回值:1:成功;-1:指令无效;-2:连接对端服务器失败;-3:业务处理失败
{
int fd, rs;
CmdStruc stCmd; //请求结构包(需要根据你的情况自己定义)
CmdResultStruc stResult; //返回结构包(需要根据你的情况自己定义)
char sFailReason[120]="";

if (WideString(Cmd).Length()==0){
*Result = -1;
return S_FALSE;
}

rs = InitWinsock(); //初始化WinSock
if (rs<0){
snprintf(sFailReason, sizeof(sFailReason),
"(PE4)初始化Socket失败: %d", rs);
*ReturnInfo = WideString(sFailReason).Detach();
*Result = -2;
}else{
//SockCliConn是连接对端Socket服务器的函数, 两个参数分别是服务器地址
//和端口号, 连接成功后返回Socket描述符
if ((fd = SockCliConn(sServerAddr, uServerPort))<0){
//连接对端服务器失败
snprintf(sFailReason, sizeof(sFailReason),
"(PE5)连接业务系统服务器失败:%d", fd);
*ReturnInfo = WideString(sFailReason).Detach();
*Result = -2;
}else{
//连接对端服务器成功, 可以跟它通信了
ZeroMemory(&amp;stCmd, sizeof(stCmd));
ZeroMemory(&amp;stResult, sizeof(stResult));
strncpy(stCmd.CmdString, AnsiString(Cmd).c_str(),
sizeof(stCmd.CmdString));
//发送指令
SendCommand(&amp;stCmd, &amp;stResult);
if (stResult.ResultFlag != 1){
//业务处理失败,在此假设业务处理失败(或未通过)时,对端服务器
//会在返回结构包里的ResultStr字段时写入失败信息
*Result = -3;
}else
*Result = 1;
//返回业务处理结果,此时,采集进程(即此组件方法的调用者)就可以根据
//Result或ReturnInfo来判断业务处理结果并作相应的后续处理
*ReturnInfo = WideString(stResult.ResultStr).Detach();
}
}
FinlWinsock(); //关闭WinSock
return S_OK;
}

在此只是抛砖引玉,用我的思路来实现这一过程,希望各位能够根据你所提的解决方法提出具体方案,给贴主多几种参考。

 
wm_copydata的例子,内存映射文件的例子delphi/demos/ipcdemo下有
/////////////发送端

procedure TForm1.Button1Click(Sender: TObject);
var i:integer;
begin
for i:=0 to 10 do begin
self.sendmsg('send msg '+inttostr(i));
end;

end;


procedure TForm1.sendmsg(s: string);
var cds:PCOPYDATASTRUCT;
begin
new(cds);
cds.dwData:=10;
cds.cbData:=length(s)+1;
GetMem(cds.lpData,cds.cbData);
StrCopy(cds.lpData,pchar(s));

if SendMessage(FindWindow(nil,'test'),wm_copyData,Handle,Integer(cds))=1 then
memo1.Lines.Add('send ok');
end;

end.

/////////////////接收端
procedure TForm1.WMCopyData(var M:TWMCopyData);
begin
memo1.Lines.Add(Pchar(m.CopyDataStruct.lpData));
m.Result:=1;
end;

///////////////////你的代码,我做了如下修改,执行正确
procedure TForm1.WMCopyData(var M:TMessage);
var
m_buf:array of byte;
bufsize:integer;
cdstemp:COPYDATASTRUCT;
begin
copymemory(@cdstemp,ptr(M.LParam),sizeof(cdstemp));
memo1.Lines.Add(pchar(cdstemp.lpdata))
end;
 
完全赞同wfzha,WM_COPYDATA所花代价最小,也最灵活。(我也是在DFW学的一招,每每有
效[:D])。
不过我认为直接广播消息寻找接收方或发送方更好一些。如果A先运行则由B发送广播消息,
A在收到后发送自己的窗口句柄,这样比FindWindow规范。如果进程间通过Mutex保证唯一
性将更好。

Sachow:完全不需要Socket参与。
龙丹:进程间只能发送最多两个长整数大小的数据,估计不够用。
 
呵呵,WM_COPYDATA也是消息哦
如果是我的话,就会使用自定义消息
 
WM_COPYDATA和一般的消息可不一样。你在进程A中申请的内存到传到进程B中,你直接写个
结构是传不过去的。自定义消息只能传递WParam/LParam两个长整数本身。
 
聪明人动嘴笨人出手:
发送端:
procedure TForm1.Button1Click(Sender: TObject);
var uimsg:uint;
tmp:pdword;
begin
uimsg:=RegisterWindowMessage('testmsg');
caption:=inttostr(uimsg);
new(tmp);
tmp^:=BSM_APPLICATIONS;
if BroadcastSystemMessage(BSF_NOHANG or BSF_POSTMESSAGE,tmp,
uimsg,
0,0)<>-1 then begin
caption:=caption+'ok'
end else
caption:='???'
end;
接受端

unit Unit2;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, AppEvnts;

type
TForm1 = class(TForm)
Button1: TButton;
ApplicationEvents1: TApplicationEvents;
procedure FormCreate(Sender: TObject);
procedure ApplicationEvents1Message(var Msg: tagMSG;
var Handled: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
uimsg:uint;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
uimsg:=RegisterWindowMessage('testmsg');
caption:=inttostr(uimsg);
end;

procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
var Handled: Boolean);
begin
if msg.message=uimsg then begin
CaptioN:='Send message ok';
end;
end;

end.
 
barton:
用共享内存嘛
 
其实共享内存也行,delphi/demos/ipcdemo中封装了一个TSharedMem类,代码如下:
TSharedMem = class(THandledObject)
private
FName: string;
FSize: Integer;
FCreated: Boolean;
FFileView: Pointer;
public
constructor Create(const Name: string; Size: Integer);
destructor Destroy; override;
property Name: string read FName;
property Size: Integer read FSize;
property Buffer: Pointer read FFileView;
property Created: Boolean read FCreated;
end;


................


{ TSharedMem }

constructor TSharedMem.Create(const Name: string; Size: Integer);
begin
try
FName := Name;
FSize := Size;
{ CreateFileMapping, when called with $FFFFFFFF for the hanlde value,
creates a region of shared memory }
FHandle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0,
Size, PChar(Name));
if FHandle = 0 then abort;
FCreated := GetLastError = 0;
{ We still need to map a pointer to the handle of the shared memory region }
FFileView := MapViewOfFile(FHandle, FILE_MAP_WRITE, 0, 0, Size);
if FFileView = nil then abort;
except
Error(Format('Error creating shared memory %s (%d)', [Name, GetLastError]));
end;
end;

destructor TSharedMem.Destroy;
begin
if FFileView <> nil then
UnmapViewOfFile(FFileView);
inherited Destroy;
end;
具体用法见该例子
 
共享内存也不是不可以。可是接收者需要一种机制去激活它,共享内存做不到这一点。你
需要在发送方写内容到共享内存时激活一个Mutex(仅有的一个内核对象)来通知接收方,
你自己想想哪一个简单?
其实DDE也是可以的,比共享内存的方案还简单一些,但是比起WM_COPYDATA来,还是太复
杂了。这个问题不用争了。OK?我因为有个项目需要找一个本地管线,各种方案都试过,
最后,最简单的就是WM_COPYDATA。这是我一年多以前的一个贴子。
http://www.delphibbs.com/delphibbs/dispq.asp?lid=860899
 
看看代码就知道了,wm_copydata最简单
 
后退
顶部