Scktsrvr.exe的源程序

以下内容摘自http://www.sudu.cn/info/html/edu/20071227/54284.html

读一读Scktsrvr.exe的源程序

使用DELPHI做多层开发的朋友们都应该对Scktsrvr.exe这个程序不陌生的,
Borland公司在DELPHI中给出了它的源代码。
这是一个Array00来行的程序,程序不算长,
现在我只选其中部分仔细读一读。
走的线路大致是,从服务器接到客户端连接,处理客户端的一个请求(这儿
选了客户端向服务器发出的取应用服务器列表请求)


服务器接受了客户端连接后,
因为ServerSocket采用的是阻塞模式,服务器执行了下面这个线程来
服务客户端:

 1 //SCKTMAIN.PAS
 2 
 3 procedure TSocketDispatcherThread.ClientExecute;
 4 var
 5   Data: IDataBlock;
 6   msg: TMsg;
 7   Obj: ISendDataBlock;
 8   Event: THandle;
 9   WaitTime: DWord;
10 begin
11   CoInitialize(nil);                 //初始化COM
12   try
13     Synchronize(AddClient);             //在程序界面上显示客户信息,
14         //用同步保证AddClient线程安全性
15     FTransport := CreateServerTransport;
16     try
17       Event := FTransport.GetWaitEvent;
18       PeekMessage(msg, 0, WM_USER, WM_USER, PM_NOREMOVE);
19       GetInterface(ISendDataBlock, Obj);
20       if FRegisteredOnly then
21         FInterpreter := TDataBlockInterpreter.Create(Obj, SSockets) else 
22         FInterpreter := TDataBlockInterpreter.Create(Obj, );
23       try
24         Obj := nil;
25         if FTimeout = 0 then
26           WaitTime := INFINITE else
27           WaitTime := 60000;
28         while not Terminated and FTransport.Connected do
29         try
30           case MsgWaitForMultipleObjects(1, Event, False, WaitTime, QS_ALLEVENTS) of
31               //MsgWaitForMultipleObjects保持线程同步之用,
32               //本文暂不细说它.
33             WAIT_OBJECT_0:  //有数据来了
34             begin
35               WSAResetEvent(Event);
36               Data := FTransport.Receive(False, 0);  //从客户端接收数据块
37               if Assigned(Data) then
38               begin
39                 FLastActivity := Now;
40                 FInterpreter.InterpretData(Data);//下面接着分析这儿
41                 Data := nil;
42                 FLastActivity := Now;
43               end;
44             end;
45             WAIT_OBJECT_0 + 1:
46               while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
47                 DispatchMessage(msg);
48             WAIT_TIMEOUT:
49               if (FTimeout > 0) and ((Now - FLastActivity) > FTimeout) then
50                 FTransport.Connected := False;
51           end;
52         except
53           FTransport.Connected := False;
54         end;
55       finally
56         FInterpreter.Free;
57         FInterpreter := nil;
58       end;
59     finally
60       FTransport := nil;
61     end;
62   finally
63     CoUninitialize;
64     Synchronize(RemoveClient);
65   end;
66 end;
View Code

 

就这么舒舒服服的六十来行。
除开那些流程控制的语句,我们主要看到两个东西:
数据传输(FTransport) 和  数据解析(FInterpreter)。

在本文中,我更感兴趣的是它的应用协议的实现,
数据传输(FTransport)就先扔在一边,以后再看了.

现在我们就来看看它的数据解析部分。
。。。

 1 FInterpreter := TDataBlockInterpreter.Create(Obj, SSockets) else 
 2 FInterpreter := TDataBlockInterpreter.Create(Obj, );
 3 //这两种创建TDataBlockInterpreter类实例的方法的区别也不去管它.
 4 //。。。
 5  FInterpreter.InterpretData(Data);
 6 //。。。
 7 //就是这儿,就是这么一句。
 8 //它具体到底干了些什么呢??
 9 //================
10 。。。
11  type
12   TSocketDispatcherThread = class(TServerClientThread, ISendDataBlock)
13   private
14 //。。。
15     FInterpreter: TDataBlockInterpreter;
16     FTransport: ITransport;
17 //。。。
18  
19 //================
20 //FInterpreter这个对象引用就是这儿定义的。
21 
22 
23 procedure TDataBlockInterpreter.InterpretData(const Data: IDataBlock);
24 var
25   Action: Integer;
26 begin
27   Action := Data.Signature;//取出由客户端传来的数据块中请求标志值
28         //客户端数据块的具体数据格式等会儿说.
29   if (Action and asMask) = asError then DoException(Data);
30   try
31     case (Action and asMask) of     //根据客户端的请求标志值作相应的处理.
32             //呵,就只有这么几个。一个大型的MIDAS系统
33            //就全站在它们肩上.
34       asInvoke: DoInvoke(Data);
35       asGetID: DoGetIDsOfNames(Data);
36       asCreateObject: DoCreateObject(Data);
37       asFreeObject: DoFreeObject(Data);
38       asGetServers: DoGetServerList(Data);
39       asGetAppServers: DoGetAppServerList(Data);//取这个再进一步读一读.
40     else
41       if not DoCustomAction(Action and asMask, Data) then
42         raise EInterpreterError.CreateResFmt(@SInvalidAction, [Action and asMask]);
43     end;
44   except
45     on E: Exception do
46     begin
47       Data.Clear;
48       WriteVariant(E.Message, Data);
49       Data.Signature := ResultSig or asError;
50       FSendDataBlock.Send(Data, False);
51     end;
52   end;
53 end;
54 //==========================
View Code

 

顺着线一步步摸下去,
看它是怎么取APPSERVER列表返回客户端的。

很简单,就是通过GetMIDASAppServerList取本地的MIDAS应用服务
器列表,然后将其写在Data中,传回客户端就了事。
===========================

 1 procedure TDataBlockInterpreter.DoGetAppServerList(const Data: IDataBlock);
 2 var
 3   VList: OleVariant;
 4   List: TStringList;
 5   i: Integer;
 6 begin
 7   Data.Clear;
 8   List := TStringList.Create;
 9   try
10     GetMIDASAppServerList(List, FCheckRegValue);//取本机的应用服务器列表
11           //想知道它是怎么做的吗?
12           //源码上都有,自己看. 
13     if List.Count > 0 then
14     begin
15       VList := VarArrayCreate([0, List.Count - 1], varOleStr);
16       for i := 0 to List.Count - 1 do
17         VList[i] := List[i];
18     end else
19       VList := NULL;
20   finally
21     List.Free;
22   end;
23   WriteVariant(VList, Data);
24   Data.Signature := ResultSig or asGetAppServers;
25   FSendDataBlock.Send(Data, False);//将应用服务器列表传回客户端
26 end;
View Code

 

========================================================
哦..前面还有一个地方没有说,就是这个神秘的Data的数据格式,它是以接口
形式提供的,
这个程序中用的是TDataBlock中实现的这个接口.
源码中可以看出,TDataBlock中包含了一个Stream,

 1 function TDataBlock.GetSize: Integer;
 2 begin
 3   Result := FStream.Size - BytesReserved;//BytesReserved的值这儿是8
 4 end;
 5 从这儿可以看出.数据块是从Stream的第8个字节算起,前面就是两个int型数的位置了.
 6 function TDataBlock.GetSignature: Integer;
 7 begin
 8   FStream.Position := 0;
 9   FStream.Read(Result, SizeOf(Result));
10 end;
11 呵, 没错, Stream的头四字节就是它的Signature.客户端的请求标志就是放在这儿.
12 
13 function TDataBlock.GetStream: TStream;
14 var
15   DataSize: Integer;
16 begin
17   FStream.Position := 4;
18   DataSize := FStream.Size - BytesReserved;
19   FStream.Write(DataSize, SizeOf(DataSize));
20   FStream.Position := 0;
21   Result := FStream;
22 end;
View Code

 

这儿很明显,就是Data中包含数据的长度值.

需要提一下的是,如果你想改变一下传输数据块的格式,比如给它加密加压什么的,
中需要自己来实现IDataBlock接口,替掉TDataBlock就是了.


从这些源码中可以得到很多东西,无论是从优美的风格上,
无论是通讯程序开发还是MIDAS数据库以及DCOM学习或应用者,
它都是值得一读的源程序.
我觉得,更重要的是,它提供了一个严谨优美和实际的范例,更给出了
一个灵活实用的框架体系

posted on 2015-11-09 11:32  zhaoyuncai  阅读(950)  评论(0编辑  收藏  举报

导航