您的位置:首页 > 编程语言

浅谈通信编程(二)--如何分离通信物理接口和应用程序

2009-09-24 16:11 274 查看
如何分离通信物理接口和应用程序
上一篇,简单讲了如何理解通信,以及应用层通信编程的框架和简单范例代码。今天,我们来谈一下,如何使应用程序和不同的物理接口无关,也就是说,如果程序原使用串口,需要换用TCP/IP, 只需要换一个传输的控件而不需要对应用程序大量修改。
一、 [/b]我们在使用通信控件时,为什么需要隔离物理传输和应用程序?[/b]
我们常用的数据控件如:串口,TCP/IP,UDP等,封装了Windows API去处理不同的传输特性,例如:不同的属性,不同的错误,不同的发送和接收数据流程,如果我们在应用程序中,直接使用此类控件,就会造成应用程序依赖于这些物理特性,而导致我们要换用不同的物理传输时(例如:从串口换到TCP/IP),应用程序进行大量修改。所以,为了避免这种情况,我们需要找到一种办法,去隔离物理传输对应用程序的影响。

二、 [/b]我们如何来实现隔离物理传输对应用程序的影响[/b]
2.1[/b]设计思路[/b]
实现我们看一下,应用程序关心什么?它关心收到数据和发送数据,以及各种状态(例如:发送前,发送后,记录Log和错误信息等。
所以,我们的设计思路是,提供一个通用的中间类,来隔离物理传输和应用程序。


应用程序Application
中间类TwyqDataLink
物理传输控件
(Serial,TCP/IP,UDP等)
中间类的后代


例如:对TCP/IP我们定义类TwyqTCPServer:TwyqDataLink和TwyqTCPClient:TwyqDataLink,对串口,我们使用TwyqSerial:TwyqDataLink,在应用程序中,不管我们使用串口或TCP/IP,我们使用MyDataLink:TwyqDataLink; 如果使用串口,则MyDataLink=TwyqSerial的实例,如果使用TCP/IP,则MyDataLink=TwyqTCPSevrer的实例或MyDataLink=TwyqTCPClient的实例。这样,应用程序中,使用MyDataLink的代码,就不会被具体的物理控件所影响。

2.2 [/b]具体实现[/b]
2.2.1[/b]我们可以定义如下的abstract[/b]的数据链路类:[/b]
<code>
TLinkEvent = procedure (Sender: TObject;MSG:String) of object;
TwyqDataLink = class (TComponent)
private
FONAfterSend: TLinkEvent;
FONBeforeSend: TLinkEvent;
FONConnect: TNotifyEvent;
FONError: TLinkEvent;
FONLog: TLinkEvent;
FONReceive: TLinkEvent;
FONSyncReceive: TLinkEvent;
protected
function GetActive: Boolean; virtual; abstract;
procedure SetActive(Value: Boolean); virtual; abstract;
public
function Close: Boolean; virtual; abstract;
function Open: Boolean; virtual; abstract;
function Read(Var Text:String;Count:cardinal;var rCount:cardinal): Boolean;
virtual; abstract;
function Send(CMD:String;Var rCount:cardinal): Boolean; virtual; abstract;
property Active: Boolean read GetActive write SetActive;
published
property ONAfterSend: TLinkEvent read FONAfterSend write FONAfterSend;
property ONBeforeSend: TLinkEvent read FONBeforeSend write FONBeforeSend;
property ONConnect: TNotifyEvent read FONConnect write FONConnect;
property ONError: TLinkEvent read FONError write FONError;
property ONLog: TLinkEvent read FONLog write FONLog;
property ONReceive: TLinkEvent read FONReceive write FONReceive;
property ONSyncReceive: TLinkEvent read FONSyncReceive write FONSyncReceive;
end;
</code>

2.2.2 [/b]我们再来看一下实现TCPClient[/b]的类定义[/b]
TBufferKind=(skNormal,skBufferIsOne,skNoBuffer);
TwyqClientSocket = class (TwyqDataLink)
private
FPort: TClientSocket;
FWaitOpenTimer:integer;
FOnConnecting:TSocketNotifyEvent;
FOnError:TSocketErrorEvent;
FAsyncConnect:Boolean;
FBufferKind:TBufferKind;
FIsThreadMode:Boolean;
FBuf:TSyncBuf;
FThread:TwyqMsgToThread;
procedure FSetPort(Value: TClientSocket);
protected
function GetActive: Boolean; override;
procedure impONRead(Sender:TObject;Socket: TCustomWinSocket);
procedure SetActive(Value: Boolean); override;
procedure csError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
Procedure csConnecting(Sender:TObject;Socket:TCustomWinSocket);
public
property WaitOpenTimer:Integer read FWaitOpenTimer write FWaitOpenTimer;
function Close: Boolean; override;
function Open: Boolean; override;
function Read(Var Text:String;Count:cardinal;var rCount:cardinal): Boolean;
override;
function Send(CMD:String;Var rCount:cardinal): Boolean; override;
constructor Create(owner:TComponent);Override;
destructor Destroy;override;
published
Property BufferKind:TBufferKind read FBufferKind write FBufferKind;
property Socket: TClientSocket read FPort write FSetPort;
Property IsThreadMode:Boolean read FIsThreadMode write FIsThreadMode;
end;

2.2.3 [/b]上面代码中,我们看到两个新类TSyncBuf[/b]和TwyqMessgaeToThread[/b]和一个IsThreadMode[/b]的属性,下面解释一下,它们用于什么:[/b]

a) 如果IsThreadMode=True,那么,我们将会在创建的TwyqMessgaeToThread线程中,去调用ONReceive事件,否则,直接调用ONReceive事件。

b) TSyncBuf是为了实现一个线程安全的先进先出的String队列,它的定义如下:
<code>
TSyncBuf = class (TPersistent)
private
FCriticalSection: TRTLCriticalSection;
FStringList: TStringList;
protected
procedure lock;
procedure unlock;
public
constructor Create;
destructor Destroy; override;
procedure Inbuf(Const S:string);
Procedure InMultiBuf(Consts:Array of String);
function OutBuf: string;
Function IsNotEmpty:Boolean;
end;
</code>

c) TwyqMessgaeToThread的定义如下:
<code>
TwyqMsgToThread=class(TThread)
Private
FBuf:TSyncBuf;
FReceiver:TwyqDataLink;
protected
procedure Execute;override;
public
Constructor Create(Receiver:TwyqDataLink;buf:TsyncBuf);
end;
</code>

三、 通过上述的设计,我们就可以做到分离物理传输和应用程序,具体实现大家可以尝试去做,如果有任何困难或需要,请在评论中留言,或发e-mail:TigerII@vip.sina.com.cn。
希望此篇文章,可以帮助大家设计出一个具有良好结构,分离物理传输和应用程序的通信程序。本文出自 “NothingImpossible” 博客,请务必保留此出处http://tigerii.blog.51cto.com/934085/204812
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: