打印本文 打印本文 关闭窗口 关闭窗口
ServerSocket,ClientSocket控件源码阅读笔记
作者:武汉SEO闵涛  文章来源:敏韬网  点击数7769  更新时间:2009/4/23 18:28:00  文章录入:mintao  责任编辑:mintao
Active属性为True,一种直接调用Open方法。

其中Open方法如下:

procedure TAbstractSocket.Open;

begin

  Active := True;

end;

它还是用到了属性Active,所以我们可以集中来讨论Active属性。

property Active: Boolean read FActive write SetActive;

看看SetActive:

(22

procedure TAbstractSocket.SetActive(Value: Boolean);

begin

  if Value <> FActive then

  begin

    if (csDesigning in ComponentState) or (csLoading in ComponentState) then

      FActive := Value;

    if not (csLoading in ComponentState) then

      DoActivate(Value);

  end;

end;

我们可以这样认为,当设计时就直接设FActive,当运行时,就调用DoActivate(Value);

而TAbstractSocket覆盖了Loaded方法,则当窗体开始运行,从Form文件中开始流入时,也调用了DoActive方法。

再看DoActive了:

(221

procedure DoActivate(Value: Boolean); virtual; abstract;又是一种抽象方法,得到它的子类去看了,在它的子类TCustomServerSocket找到这个方法:

procedure TCustomServerSocket.DoActivate(Value: Boolean);

begin

  if (Value <> FServerSocket.Connected) and not (csDesigning in ComponentState) then

  begin

    if FServerSocket.Connected then

      FServerSocket.Disconnect(FServerSocket.SocketHandle)

    else FServerSocket.Listen(FHost, FAddress, FService, FPort, SOMAXCONN);

  end;

end;

可以这样理解,不在设计时,当Value不等它的成员FServerSocket.Connected时(我们可先认为这个表示当前的监听状态),而如果此时FServerSocket.Connected为True,则表示Value为False,,那么这时要断开连接,调用FServerSocket.Disconnect(FServerSocket.SocketHandle)

很多时候ServerSocket都是调用它的成员FServerSocket来完成操作的,这一点我已经看到了,下面还有更多这样的情况。否则,则Value为True,调用

FServerSocket.Listen(FHost, FAddress, FService, FPort, SOMAXCONN);来开始进行监视。好的,现在我们就要打开FServerSocket的源码,看看它是怎么样完成断开连接和开始连接的了。

先看开始监听的:

(2211

procedure TServerWinSocket.Listen(var Name, Address, Service: string; Port: Word;

  QueueSize: Integer);

begin

  inherited Listen(Name, Address, Service, Port, QueueSize, ServerType = stThreadBlocking);

  if FConnected and (ServerType = stThreadBlocking) then

    FServerAcceptThread := TServerAcceptThread.Create(False, Self);

end;

这里调用其父类的Listen方法,如果它是阻塞方式的,则还要生成一个线程类,由于我用的非阻塞方式,所以暂不去理它,看看他的父类的Listen方法:

(22111

procedure TCustomWinSocket.Listen(const Name, Address, Service: string; Port: Word;

  QueueSize: Integer; Block: Boolean);

begin

  if FConnected then raise ESocketError.CreateRes(@sCannotListenOnOpen);

  FSocket := socket(PF_INET, SOCK_STREAM, IPPROTO_IP);

  if FSocket = INVALID_SOCKET then raise ESocketError.CreateRes(@sCannotCreateSocket);

  try

    Event(Self, seLookUp);

    if Block then

    begin

      FAddr := InitSocket(Name, Address, Service, Port, False);

      DoListen(QueueSize);

    end else

      AsyncInitSocket(Name, Address, Service, Port, QueueSize, False);

  except

    Disconnect(FSocket);

    raise;

  end;

end;

这里第一句重要函数出现了:

FSocket := socket(PF_INET, SOCK_STREAM, IPPROTO_IP);

记得上面Fsockeet曾被赋过值吗,是INVALID_SOCKET;,而这里终于被替回了一个可用的套接字了。

第二个重要的函数:Event(Self, seLookUp);可以先猜测这个方法最终于会调用事件指针,等一下再看。

接下来判断Block的值,回头看看这一句:

inherited Listen(Name, Address, Service, Port, QueueSize, ServerType = stThreadBlocking);

如果为阻塞方式,则为True,否则为False,非阻塞为这时为False,调用下方法:

AsyncInitSocket(Name, Address, Service, Port, QueueSize, False);

好了,再看一下Even吧:

(221111

procedure TCustomWinSocket.Event(Socket: TCustomWinSocket; SocketEvent: TSocketEvent);

begin

  if Assigned(FOnSocketEvent) then FOnSocketEvent(Self, Socket, SocketEvent);

end;

不出所料,调用事件指针了,这时ServerSocket的事件就会触发了,回过头去看看,

seLookup: if Assigned(FOnLookup) then FOnLookup(Self, Socket);

这里CustomSocket的OnLookup事件发生,但ServerSocket并没有显化它,ClientSocket就有这个事件。

按我们所设的方式,接下来要调用如下函数了(另外一些方法以后再说):

AsyncInitSocket(Name, Address, Service, Port, QueueSize, False);

这函数很大,但所用到的技巧也非常精彩,得好好分析它:

(221112

procedure TCustomWinSocket.AsyncInitSocket(const Name, Address,

  Service: string; Port: Word; QueueSize: Integer; Client: Boolean);

var

  ErrorCode: Integer;

begin

  try

    case FLookupState of

      lsIdle:

        begin

          if not Client then

         

上一页  [1] [2] [3] [4] [5] [6] [7] [8] [9]  下一页

打印本文 打印本文 关闭窗口 关闭窗口