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。
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。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的实现机理。