国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

讀一讀Scktsrvr.exe的源程序

2019-11-18 18:45:55
字體:
來源:轉載
供稿:網(wǎng)友
讀一讀Scktsrvr.exe的源程序

使用DELPHI做多層開發(fā)的朋友們都應該對Scktsrvr.exe這個程序不陌生的,
Borland公司在DELPHI中給出了它的源代碼。
這是一個900來行的程序,程序不算長,
現(xiàn)在我只選其中部分仔細讀一讀。
走的線路大致是,從服務器接到客戶端連接,處理客戶端的一個請求(這兒
選了客戶端向服務器發(fā)出的'取應用服務器列表'請求)


服務器接受了客戶端連接后,
因為ServerSocket采用的是阻塞模式,服務器執(zhí)行了下面這個線程來
服務客戶端:


//SCKTMAIN.PAS

PRocedure TSocketDispatcherThread.ClientExecute;
var
  Data: IDataBlock;
  msg: TMsg;
  Obj: ISendDataBlock;
  Event: THandle;
  WaitTime: DWord;
begin
  CoInitialize(nil);                 //初始化COM
  try
    Synchronize(AddClient);             //在程序界面上顯示客戶信息,
        //用同步保證AddClient線程安全性
    FTransport := CreateServerTransport;
    try
      Event := FTransport.GetWaitEvent;
      PeekMessage(msg, 0, WM_USER, WM_USER, PM_NOREMOVE);
      GetInterface(ISendDataBlock, Obj);
      if FRegisteredOnly then
        FInterpreter := TDataBlockInterpreter.Create(Obj, SSockets) else
        FInterpreter := TDataBlockInterpreter.Create(Obj, ');
      try
        Obj := nil;
        if FTimeout = 0 then
          WaitTime := INFINITE else
          WaitTime := 60000;
        while not Terminated and FTransport.Connected do
        try
          case MsgWaitForMultipleObjects(1, Event, False, WaitTime, QS_ALLEVENTS) of
              //MsgWaitForMultipleObjects保持線程同步之用,
              //本文暫不細說它.
            WAIT_OBJECT_0:  //有數(shù)據(jù)來了
            begin
              WSAResetEvent(Event);
              Data := FTransport.Receive(False, 0);  //從客戶端接收數(shù)據(jù)塊
              if Assigned(Data) then
              begin
                FLastActivity := Now;
                FInterpreter.InterpretData(Data);//下面接著分析這兒
                Data := nil;
                FLastActivity := Now;
              end;
            end;
            WAIT_OBJECT_0 + 1:
              while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
                DispatchMessage(msg);
            WAIT_TIMEOUT:
              if (FTimeout > 0) and ((Now - FLastActivity) > FTimeout) then
                FTransport.Connected := False;
          end;
        except
          FTransport.Connected := False;
        end;
      finally
        FInterpreter.Free;
        FInterpreter := nil;
      end;
    finally
      FTransport := nil;
    end;
  finally
    CoUninitialize;
    Synchronize(RemoveClient);
  end;
end;
就這么舒舒服服的六十來行。
除開那些流程控制的語句,我們主要看到兩個東西:
數(shù)據(jù)傳輸(FTransport) 和  數(shù)據(jù)解析(FInterpreter)。

在本文中,我更感興趣的是它的應用協(xié)議的實現(xiàn),
數(shù)據(jù)傳輸(FTransport)就先扔在一邊,以后再看了.

現(xiàn)在我們就來看看它的數(shù)據(jù)解析部分。
。。。
FInterpreter := TDataBlockInterpreter.Create(Obj, SSockets) else
FInterpreter := TDataBlockInterpreter.Create(Obj, ');
//這兩種創(chuàng)建TDataBlockInterpreter類實例的方法的區(qū)別也不去管它.
。。。
 FInterpreter.InterpretData(Data);
。。。
就是這兒,就是這么一句。
它具體到底干了些什么呢??
================
。。。
 type
  TSocketDispatcherThread = class(TServerClientThread, ISendDataBlock)
  private
。。。
    FInterpreter: TDataBlockInterpreter;
    FTransport: ITransport;
。。。
 
================
FInterpreter這個對象引用就是這兒定義的。


procedure TDataBlockInterpreter.InterpretData(const Data: IDataBlock);
var
  Action: Integer;
begin
  Action := Data.Signature;//取出由客戶端傳來的數(shù)據(jù)塊中請求標志值
        //客戶端數(shù)據(jù)塊的具體數(shù)據(jù)格式等會兒說.
  if (Action and asMask) = asError then DoException(Data);
  try
    case (Action and asMask) of     //根據(jù)客戶端的請求標志值作相應的處理.
            //呵,就只有這么幾個。一個大型的MIDAS系統(tǒng)
           //就全站在它們肩上.
      asInvoke: DoInvoke(Data);
      asGetID: DoGetIDsOfNames(Data);
      asCreateObject: DoCreateObject(Data);
      asFreeObject: DoFreeObject(Data);
      asGetServers: DoGetServerList(Data);
      asGetAppServers: DoGetAppServerList(Data);//取這個再進一步讀一讀.
    else
      if not DoCustomAction(Action and asMask, Data) then
        raise EInterpreterError.CreateResFmt(@SInvalidAction, [Action and asMask]);
    end;
  except
    on E: Exception do
    begin
      Data.Clear;
      WriteVariant(E.Message, Data);
      Data.Signature := ResultSig or asError;
      FSendDataBlock.Send(Data, False);
    end;
  end;
end;
==========================
順著線一步步摸下去,
看它是怎么取APPSERVER列表返回客戶端的。

很簡單,就是通過GetMIDASAppServerList取本地的MIDAS應用服務
器列表,然后將其寫在Data中,傳回客戶端就了事。
===========================
procedure TDataBlockInterpreter.DoGetAppServerList(const Data: IDataBlock);
var
  VList: OleVariant;
  List: TStringList;
  i: Integer;
begin
  Data.Clear;
  List := TStringList.Create;
  try
    GetMIDASAppServerList(List, FCheckRegValue);//取本機的應用服務器列表
          //想知道它是怎么做的嗎?
          //源碼上都有,自己看. 
    if List.Count > 0 then
    begin
      VList := VarArrayCreate([0, List.Count - 1], varOleStr);
      for i := 0 to List.Count - 1 do
        VList[i] := List[i];
    end else
      VList := NULL;
  finally
    List.Free;
  end;
  WriteVariant(VList, Data);
  Data.Signature := ResultSig or asGetAppServers;
  FSendDataBlock.Send(Data, False);//將應用服務器列表傳回客戶端
end;

========================================================
哦..前面還有一個地方?jīng)]有說,就是這個神秘的Data的數(shù)據(jù)格式,它是以接口
形式提供的,
這個程序中用的是TDataBlock中實現(xiàn)的這個接口.
源碼中可以看出,TDataBlock中包含了一個Stream,
function TDataBlock.GetSize: Integer;
begin
  Result := FStream.Size - BytesReserved;//BytesReserved的值這兒是8
end;
從這兒可以看出.數(shù)據(jù)塊是從Stream的第8個字節(jié)算起,前面就是兩個int型數(shù)的位置了.
function TDataBlock.GetSignature: Integer;
begin
  FStream.Position := 0;
  FStream.Read(Result, SizeOf(Result));
end;
呵, 沒錯, Stream的頭四字節(jié)就是它的Signature.客戶端的請求標志就是放在這兒.

function TDataBlock.GetStream: TStream;
var
  DataSize: Integer;
begin
  FStream.Position := 4;
  DataSize := FStream.Size - BytesReserved;
  FStream.Write(DataSize, SizeOf(DataSize));
  FStream.Position := 0;
  Result := FStream;
end;
這兒很明顯,就是Data中包含數(shù)據(jù)的長度值.

需要提一下的是,如果你想改變一下傳輸數(shù)據(jù)塊的格式,比如給它加密加壓什么的,
中需要自己來實現(xiàn)IDataBlock接口,替掉TDataBlock就是了.


從這些源碼中可以得到很多東西,無論是從優(yōu)美的風格上,
無論是通訊程序開發(fā)還是MIDAS數(shù)據(jù)庫以及DCOM學習或應用者,
它都是值得一讀的源程序.
我覺得,更重要的是,它提供了一個嚴謹優(yōu)美和實際的范例,更給出了
一個靈活實用的框架體系。

 


                                             halfdream(哈欠) 于2001-10-14晚


上一篇:StatusBar有多個子欄時,如何確定鼠標在狀態(tài)欄上雙擊時是雙擊哪一個子欄

下一篇:使用DLL文件中封裝的窗口

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
學習交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網(wǎng)友關注

主站蜘蛛池模板: 阿鲁科尔沁旗| 民权县| 襄城县| 铜川市| 武定县| 灵台县| 晋中市| 临潭县| 奎屯市| 金乡县| 迁西县| 白城市| 安徽省| 若羌县| 安陆市| 五原县| 平远县| 酉阳| 濮阳县| 博野县| 栖霞市| 金华市| 青川县| 郁南县| 隆昌县| 绥德县| 五指山市| 安新县| 聊城市| 贺州市| 贡嘎县| 英超| 澜沧| 沅江市| 平度市| 张掖市| 芦溪县| 盐源县| 盐池县| 云南省| 都昌县|