上一节我们留下了一个小尾巴,就是为什么需要转发。首先看看我们的下层硬件的驱动程序是用什么语言编的,我们的下层硬件是DSP,用的是C语言,而我们的后台用的是Java,这个里面就出现了问题。
      Java里面的Byte类型的取值范围是-128~127,而我们用C语言编出的程序每个字节储存的值可是0~255。要知道Java可没有Unsigned类型的数据。这个怎么解决?只能通过第三方来转发。
      由于Java数据类型的取值范围的平台无关性,这导致了我们在16位的DSP芯片里编的程序所输出的数据传输到Java后台时会不会发生溢出这也是一个问题。这个怎么解决?只能通过第三方来转发。
      而且由于Java是在虚拟机上运行的,它是解释型的,让Java SDK去处理CPU敏感任务,即不停的处理毫秒,微妙级的任务,呵呵,我没有这个勇气去冒这个险。 
       用Java RMI还是用基于com的Active控件来做网页的实时显示?从客户体验方面来说首选Active控件。如果用Java来做呵呵,后果不可想象。就目前为止,Java还没有找到能够改善客户体验的一种有效的方式。 
       以上就是为什么要用转发机制的动机,下面我们来看看ServerIn这个模块的功能。ServerIn这个模块是用来管理Active控件的,也就是说当用户打开实时监控页面运行Active控件时,Active如何建立?如何运行?这些要靠ServerIn模块来管理。其实ServerIn模块的功能和ClientIn模块的功能很象。只不过ClientIn是转发GPRSServer模块和Java后台之间的数据而ServerIn是转发GPRSServer和Active之间的数据。

      我们来看看ServerIn两个主要的功能:

第一个功能:将GPRSServer模块的数据转发给Active。

 1procedure TFormServerIn.WMCopyData(var M: TMessage);
 2var
 3count,i,l:integer;
 4SS,S:String;
 5PP:Pchar;
 6SocketT:Tcustomwinsocket;
 7SocketID:integer;
 8begin
 9if PcopyDataStruct(M.LParam)^.dwData=ServerSendToServerInInfo then
10   begin
11       Count:=ServerInS.Socket.ActiveConnections;
12       PP:=PCopyDataStruct(M.LParam)^.lpData;
13       l:=PCopyDataStruct(M.LParam)^.cbData;
14       S:='';
15        for i:=0 to l-1 do
16          begin
17              if (PP+i)^=chr($7F) then
18                  S:=S+chr(0)
19                  else
20                  S:=S+(PP+i)^;
21          end;
22        for i:=0 to  G_ActiveNo-1 do
23            begin
24          SocketID:=FindActiveSocketArr(ActiveSocketArr.InnerActiveSocketArr[i],S);
25     if  SocketID<>0 then
26        begin
27        SocketT:=Tcustomwinsocket.Create(SocketID);
28        SocketT.SendText(S);
29        end;
30              end;
31      if G_ShowInfo then
32        begin
33        SS:='';
34         for i:=0 to l-1 do
35         SS:=SS+inttohex(ord(S[i+1]),2)+' ';
36         memo1.Lines.Add(SS);
37        end
38     end;
39end;
40

    

          这个消息函数还是比较简单的,基本上和上一节列出的消息函数差不多。不过我们要注意的是24行,这行作用是找到相应的SocketID,SocketID是什么?当很多个Active控件连接到ServerIn模块的时候,每个Active控件在ServerIn模块中都会留下唯一的标识。这个标识就是SocketID,其实就像是数据库中一张表中的关键字一样。找到相应的SocketID其实就是找到了唯一的Acitve,也就是找到了发命令的那台电脑(客户机)。当然也会出现一种情况,就是多台电脑(客户机)在对同一台下位机进行操作,这个时候该怎么做呢?看看我们的22~30行,是个大循环,原来只要符合要求的SocketID我们都会去转发数据。

当然说到现在我们还没有提到到哪个地方找到这些SocketID吧,其实我们一直在和SoketID链接池打交道,24行就使从SocketID链接池找到SocketID。当然如何编写一个链接池,你们可能要看看我写的《设计模式(四)Singleton》篇里对于Pooling的Delphi实现了。当然我在链接池里保存的是很多个结构。每个结构里储存着SocketID和其他一些重要的信息。这个链接池同时具有查找、增加、删除、修改、初始化等功能。我们24行就是它的查找功能函数。总体来说,你们可以将链接池看成存放n多个Active的信息的仓库。

为了论述简洁性,我就不累诉了,防止你们对总体框架产生混淆。

第二个功能,将Active控件的数据转发给ServerIN。
 1   for i:=0 to  G_ActiveNo-1 do
 2          begin
 3            if ActiveSocketArr.InnerActiveSocketArr[i].Flg=true then//表明有数据
 4              if ActiveSocketArr.InnerActiveSocketArr[i].Valid =false then //表明在此次循环中还没有被使用
 5                begin
 6                  ActiveSocketArr.InnerActiveSocketArr[i].Valid:=true;
 7                  ActiveSocketArr.TimerUsedRecordNomber:=ActiveSocketArr.TimerUsedRecordNomber+1;
 8                  stemp:=copy(ActiveSocketArr.InnerActiveSocketArr[i].Info,1,46);
 9                    if ActiveSocketArr.TimerUsedRecordNomber>=ActiveSocketArr.ValidTrueRecordNomber then  //表明到了循环结束
10                       begin
11                          for j:=0 to  G_ActiveNo-1 do
12                          ActiveSocketArr.InnerActiveSocketArr[j].Valid:=false;
13                       end;
14                  goto H1;
15                end;
16          end;
17          H1:
18    hwndReceiver:=findwindow('TFormClientIn',nil);
19         if  hwndReceiver<>0 then
20         SendMessageTo(hwndReceiver,stemp,ServerInSendToClientInInfo,0,true);
21

上面的大部分内容是针对链接池中的结构进行的判别操作,你们看看就行了。不要求你们理解。我们看最后一行,这行其实我们在其他模块中也出现过很多次。这行的含义是将数据发送给哪个模块,ServerInSendToClientInInfo这个参数含义很明显,将数据传递给ClientIn模块,好像我们刚刚讲的ServerIn模块它的功能是将数据转发给GPRSServer模块阿?这里怎么传递给了ClientIn呢?这里我偷懒了,因为上一节我给你们讲过Java后台发送出来的数据是不能直接传递给下位机的,需要进行转换,那么这个转换功能在哪个模块作了呢?是在ClientIn模块作了。这里可能你们要混淆了。其实整个系统有两种转换,第一种是下位机(也就是我们上面讲的DSP硬件系统)将数据传递给GPRSServer的向上传递过程,在这个过程中数据的转换工作是在GPRSServer模块中进行的,转换完成之后,将数据转发给ClientIn,ClientIn这个时候什么都不做,它只是简单的把数据扔给Java后台就OK了。第二种是Java后台将数据传递给ClientIn模块的向下传递过程。在这个过程中数据的转换工作是在ClientIn中进行的,还记不记得上一章讲的接口了,那个接口就是负责具体转换工作的。但ClientIn将数据转换好之后,就发送给GPRSServer或SERVER(无线电模块)这两个模块收到数据后也是什么都不做,直接将数据扔给下位机。

      那么既然我已经在ClientIn中做好了那个接口,我为什么还要在ServerIn中再做一回呢同样的事呢,所以我直接将数据发送给了ClientIn,欺骗ClientIn,让ClientIn认为是Java后台发送的数据,ClientIn一旦收到这样的数据,它当然要进行转换和转发工作了。当然这样做性能上会收到一些影响。但影响不太大,是微秒级的。

     至此ServerIn模块的大体结构就完成了。下一节我将会给你们讲Active的实现机理。

posted on 2006-05-06 13:08  coffeeliu  阅读(963)  评论(18编辑  收藏  举报