上一次我们讲过了GPRSServer那个模块,这结我们讲ClientIn这个模块。上一节我留下一个东西没有讲,就是CutReceiveData这个函数,这个函数其实很大,涉及到的内容也很多,当然也涉及到一些商业机密。你们只要知道它是用来解包的就可以了,当然也可以把CutReceiveData做成一个类,但我没有这样做,速度和编程规范两者要我选择的话,我一般会选择速度,虽然我这段时间一直在写模式设计这个体系的东西,但我编程一般的原则是,能用结构绝不用类,能用函数决不用结构,能用指针决不用高级方法,关键方法的编写用汇编而不用函数,尽量避免用接口,能用GOTO的决不用Break,尽量将所有的程序做到一个模块中,当然还有能用别人的代码的就用别人代码。这样做可以最大限度的保证高速度。因为我觉得评价一个程序的好坏的指标就是:运行速度,稳定性,可扩展性,外延深度。代码好不好看是次要的。别人用的是你的程序而不是看你的语法。
        下面我们看看ClientIn是如何工作的。
我们先来看看这个模块总的结构:

 1unit UnitClientIn;
 2
 3interface
 4
 5uses
 6  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 7  Dialogs,unitmain,unit1message,UnitProtocal,UnitMatch, ScktComp,IniFiles,
 8  StdCtrls, ComCtrls, ToolWin, Menus,DateUtils,ComObj, ExtCtrls;
 9
10type
11  TFormClientIn = class(TForm)
12    ToolBar1: TToolBar;
13    ToolButton1: TToolButton;
14    ToolButton2: TToolButton;
15    ToolButton3: TToolButton;
16    ToolButton4: TToolButton;
17    Memo1: TMemo;
18    ToolButton5: TToolButton;
19    SaveDialog1: TSaveDialog;
20    PopupMenu1: TPopupMenu;
21    SaveInfo1: TMenuItem;
22    ServerJava: TServerSocket;
23    TimerSend: TTimer;
24    TimerSendJ: TTimer;
25    Timer54: TTimer;
26    procedure FormCreate(Sender: TObject);
27    procedure ToolButton1Click(Sender: TObject);
28    procedure ToolButton2Click(Sender: TObject);
29    procedure ToolButton3Click(Sender: TObject);
30    procedure ToolButton4Click(Sender: TObject);
31    procedure ToolButton5Click(Sender: TObject);
32    procedure SaveInfo1Click(Sender: TObject);
33    procedure FormDestroy(Sender: TObject);
34    procedure ServerJavaClientError(Sender: TObject;
35      Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
36      var ErrorCode: Integer);
37    procedure ServerJavaClientRead(Sender: TObject;
38      Socket: TCustomWinSocket);
39    procedure ServerJavaClientConnect(Sender: TObject;
40      Socket: TCustomWinSocket);
41    procedure ServerJavaClientDisconnect(Sender: TObject;
42      Socket: TCustomWinSocket);
43    procedure TimerSendTimer(Sender: TObject);
44    procedure TimerSendJTimer(Sender: TObject);
45    procedure Timer54Timer(Sender: TObject);
46
47  private
48    procedure WMCopyData(var M:TMessage);Message WM_COPYDATA;
49    Procedure ReMessage(Var Msg:TMessage);Message ServerSendToClientIn;
50    procedure ClientTimerSend(var Msg:TMessage);message ClientTimer;
51    Procedure JEndFlgMessage(Var Msg:TMessage);Message JEndFlgM;
52    Procedure JPacketIDFlgMessage(Var Msg:TMessage);Message JPacketIDM;
53    procedure AddErrorToLine(Var Msg:TMessage); Message SendToClientInError;
54  public
55    procedure Set_SocketInfo(S:String);
56    procedure SendMessageTo(hwndSend: HWND; s: String;
57  Mg:DWord;Wparam: Word; Flg: boolean);
58  procedure AppException(Sender: TObject; E: Exception);
59   function Change(B:byte):byte;
60   end;

总体上来说这个模块里的函数并不多,为什么很少呢?因为这个模块的功能主要是将我们上章讲的GPRSServer模块处理好的数据包转发给Java后台,同时将Java后台发送过来的数据包分析后转发给GPRSServer模块,让GPRSServer模块发给下位机。所以数据解析的大部分工作都让GPRSServer里的CutReceiveData给做掉了。我们来看看他的第一个任务是如何完成的。

   第一个任务:转发GPRSServer送过来的数据,因为GPRSServer已经将下位机传送上来的数据解析成了电量电压电流等等数据了,所以我们的ClientIN只要做:收到——〉确认——〉发给Java后台就OK了。

看看转发的代码:(我真的受不了了,才写好的文章,被博客网一停止响应给毁了,还要重写)

 1procedure TFormClientIn.WMCopyData(var M: TMessage);
 2var
 3Count,i,l:integer;
 4PP:Pchar;
 5S,SS,sss,GPRSIDSTR,SSS_Old:string;//测试用
 6hwndReceiver:HWND;
 7label H1;
 8begin
 9if (PcopyDataStruct(M.LParam)^.dwData=ServerSendToClientInInfo) then
10   begin
11      S:=Pchar(PCopyDataStruct(M.LParam)^.lpData);
12      Count:=ServerJava.Socket.ActiveConnections;
13    for i:=0 to Count-1 do
14       begin
15      ServerJava.Socket.Connections[i].SendText(S);
16       end;
17     if G_ShowInfo then
18       Memo1.Lines.Add(S);
19   end;
20     if  (PcopyDataStruct(M.LParam)^.dwData=ServerInSendToClientInInfo) then
21      begin
22     S:=Pchar(PCopyDataStruct(M.LParam)^.lpData);
23     memo1.Lines.Add('ClientIn<--ServerIn:收到数据!'+S+#13+#10);
24     sss:=S;
25     SSS_Old:=S;
26      SS:='';
27      GPRSIDSTR:='';
28      ////////////////////////////////
29      ///
30      /// 假如为GPRS数据包则先进行拆包,对内部数据包进行打包后再进行合包,发送到TFormServer后再进行具体发送
31      /// 包格式为:%%%%|13851823257|####|后面格式不变
32      /////////////////////////////////
33      if copy(sss,1,5)='%%%%|' then
34          begin
35             GPRSIDSTR:=copy(sss,1,17);
36             sss:=copy(sss,18,1024);
37          end;
38      ///////////////////////////////////////////////////////////////////////////////
39      //
40      //对9520H,J进行打包
41      ///////////////////////////////////////////////////////////////////////////////
42      if  copy(sss,1,5)='####|' then
43            begin
44                     Goble_S:='';
45                    SS:=IPro.BulidSendData(sss);
46                    if SS='' then
47                      goto H1;
48
49                    if copy(SSS_Old,1,5)='%%%%|' then
50                       begin
51                        SS:=GPRSIDSTR+SS;
52                        hwndReceiver:=findwindow('TFormGPRSServer',nil); //向GPRS服务器发送数据
53                           if  hwndReceiver<>0 then
54                         SendMessageTo(hwndReceiver,SS,ClientInSendToGPRSServer,0,true);
55                        end else
56                        begin
57                         hwndReceiver:=findwindow('TFormServer',nil);//向无线电服务器发送数据
58                           if  hwndReceiver<>0 then
59                         SendMessageTo(hwndReceiver,SS,ClientInSendToServerInfo,0,true);
60
61                        end;
62                    H1:
63  end;
64      end;
65end;

其实这个消息函数中涉及到ClientIn转发功能的也只有9~19行,上面的15行就是将GPRSServer发送过来的数据包通过Socket转发给JSP后台。我们从上面的代码中可以看出ClientIn模块并没有对这些数据包做容错处理,因为我们在GPRSServer模块中已经做过容错处理了,就是在我上面讲的CutReceiveData中。当然我们还会在Java后台中再作一次容错处理,但是在Java后台中作的容错操作要比在CutReceiveData中做的容错要简单得多了。
     当然我们在GPRSServer模块和Java后台的通讯上也作了很多的约定,比如说数据包如何转换,数据包的格式之类的东西,有很多,我写了大概有一本书之多。为什么要有这些约定呢?你们可能要问,直接将Java后台发送的数据包传送给底层模块不就行了吗。还需要这么麻烦用GPRSServer和ClientIN来转发吗。这个里面涉及到一些语言之间的差别,我们下一章再说。

第二个任务:ClientIN 将Java后台发送过来的数据包解析之后发送给GPRSServer模块。

 我们来看看转发代码:

 1procedure TFormClientIn.ServerJavaClientRead(Sender: TObject;
 2  Socket: TCustomWinSocket);
 3var
 4Count,i,j:integer//测试用
 5S,SS,sss,GPRSIDSTR,SSS_Old:string;//测试用
 6hwndReceiver:HWND;
 7label H1;
 8  begin
 9 try
10while socket.ReceiveLength>0 do
11  begin
12     Goble_S:='';
13     Goble_S:=socket.ReceiveText;
14     memo1.Lines.Add('ClientIn<--JavaServer:收到数据!'+Goble_S+#13+#10);
15     sss:=Goble_S;
16     SSS_Old:=Goble_S;
17      SS:='';
18      GPRSIDSTR:='';
19      ////////////////////////////////
20      ///
21      /// 假如为GPRS数据包则先进行拆包,对内部数据包进行打包后再进行合包,发送到TFormServer后再进行具体发送
22      /// 包格式为:%%%%|13851823257|####|后面格式不变
23      /////////////////////////////////
24      if copy(sss,1,5)='%%%%|' then
25          begin
26             GPRSIDSTR:=copy(sss,1,17);
27             sss:=copy(sss,18,1024);
28          end;
29      ///////////////////////////////////////////////////////////////////////////////
30      //
31      //对9520H,J进行打包
32      ///////////////////////////////////////////////////////////////////////////////
33      if  copy(sss,1,5)='####|' then
34            begin
35                     Goble_S:='';
36                    SS:=IPro.BulidSendData(sss);
37                    if SS='' then
38                      goto H1;
39
40                    if copy(SSS_Old,1,5)='%%%%|' then
41                       begin
42                        SS:=GPRSIDSTR+SS;
43                        hwndReceiver:=findwindow('TFormGPRSServer',nil); //向GPRS服务器发送数据
44                           if  hwndReceiver<>0 then
45                         SendMessageTo(hwndReceiver,SS,ClientInSendToGPRSServer,0,true);
46                        end else
47                        begin
48                         hwndReceiver:=findwindow('TFormServer',nil);//向无线电服务器发送数据
49                           if  hwndReceiver<>0 then
50                         SendMessageTo(hwndReceiver,SS,ClientInSendToServerInfo,0,true);
51
52                        end;
53                    H1:
54         if G_ShowInfo then
55                 begin
56                       S:='';
57                       for j:=1 to length(SS) do
58                          begin
59                            S:=S+inttohex(ord(SS[j]),2)+' ';
60                           end;
61                          memo1.Lines.Add('通讯服务器<--后台:收到数据!'+S+#13+#10);
62                  end;
63            end;
64  end;
65   except
66     on EConvertError do begin Goble_S:='';abort; end;
67   end;
68end;

这个里面的36行就是将Java后台发送的数据包解析成GPRSServer模块能够识别的数据包的函数,其实36行是一个接口:IProtocal,我将这个接口设计成了Singleton模式。我将这类解析过程全部封装到了这个接口中。你们只要知道它的作用就可以了,因为里面涉及到商业机密。
   上面的45行和50行就是将已经解析好的数据包按照约定发送给GPRSServer和Server(无线电)模块。
   总体来说整个框架还是比较简单的。
    ClientIn里面一些很“变态”的程序我就不讲了,以免你们对主体程序产生混淆。我在毕业设计文章的时候总是在想,要是再让我写一次这么变态的程序,我还会不会去写。下一章我将会告诉你们为什么我们需要用到转换。
posted on 2006-05-05 13:56  coffeeliu  阅读(791)  评论(2编辑  收藏  举报