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。
procedure TFormServerIn.WMCopyData(var M: TMessage);2
var3
count,i,l:integer;4
SS,S:String;5
PP:Pchar;6
SocketT:Tcustomwinsocket;7
SocketID:integer;8
begin9
if PcopyDataStruct(M.LParam)^.dwData=ServerSendToServerInInfo then10
begin11
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 do16
begin17
if (PP+i)^=chr($7F) then18
S:=S+chr(0)19
else20
S:=S+(PP+i)^;21
end;22
for i:=0 to G_ActiveNo-1 do23
begin24
SocketID:=FindActiveSocketArr(ActiveSocketArr.InnerActiveSocketArr[i],S);25
if SocketID<>0 then26
begin27
SocketT:=Tcustomwinsocket.Create(SocketID);28
SocketT.SendText(S);29
end;30
end;31
if G_ShowInfo then32
begin33
SS:='';34
for i:=0 to l-1 do35
SS:=SS+inttohex(ord(S[i+1]),2)+' ';36
memo1.Lines.Add(SS);37
end; 38
end;39
end;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。
for i:=0 to G_ActiveNo-1 do2
begin3
if ActiveSocketArr.InnerActiveSocketArr[i].Flg=true then//表明有数据4
if ActiveSocketArr.InnerActiveSocketArr[i].Valid =false then //表明在此次循环中还没有被使用5
begin6
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
begin11
for j:=0 to G_ActiveNo-1 do12
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 then20
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的实现机理。
浙公网安备 33010602011771号