打印本文 打印本文 关闭窗口 关闭窗口
ServerSocket,ClientSocket控件源码阅读笔记
作者:武汉SEO闵涛  文章来源:敏韬网  点击数7769  更新时间:2009/4/23 18:28:00  文章录入:mintao  责任编辑:mintao
bsp;      FD_CLOSE: Disconnect(Socket);

        FD_READ: Read(Socket);

        FD_WRITE: Write(Socket);

        FD_ACCEPT: Accept(Socket);//这个很特殊

      end;

end;

呵,又是一个大函数,不过理解起来倒是容易多了,先检查有没有错误,如果有就调用Error(Self, ErrorEvent, ErrorCode);如果没有,就根据相应标识,调用相就的函数,其实我们已经可以确定,像Read这些内部一定会调用Event,再由Event调用

FOnSocketEvent(Self, Socket, SocketEvent);,这样才能使得ServerSocket这些外部的类获得事件(上面已经说到它们是怎么把事件关联起来的了)。

而源代码中确实也是这样的,这里只列出一个read,其他的一样:

procedure TCustomWinSocket.Read(Socket: TSocket);

begin

  if (FSocket = INVALID_SOCKET) or (Socket <> FSocket) then Exit;

  Event(Self, seRead);

end;

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

begin

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

end;

 

完了吧,可惜还没有,回到上面的函数去,发现还有一个方法没有分析:

FServerSocket.Disconnect(FServerSocket.SocketHandle)可是按我们流程,还不会调用到它,所以这里暂不提它。

 

好了,第二步就这样结束了,再说下去,我自己也晕了。不过我们知道了这一步所完成的任务:连接一个监听的套接字,并设定好了事件方法指针,在适当的时机会调用适当的事件处理函数。真的得谢谢Delphi为我们做了这么多的事,使我们在使用的时候感觉到是如此的简单。

 

 

3.程序执行到这里,得看看ClientSocket吧,有了上面的分析,下面的分析都会简单得多:

constructor TClientSocket.Create(AOwner: TComponent);

begin

  inherited Create(AOwner);

  FClientSocket := TClientWinSocket.Create(INVALID_SOCKET);

  InitSocket(FClientSocket);

end;

没有什么值得讨论的FClientSocket也是继承父类的构造方法,上面已经说过了。

接设置Port,Address等,都是到祖先类设置,没有什么好说的,最后一句是

Active:=true;

上面的讨论已经知道,它最后会调用ClientSocket的覆盖方法:

procedure TClientSocket.DoActivate(Value: Boolean);

begin

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

  begin

    if FClientSocket.Connected then

      FClientSocket.Disconnect(FClientSocket.FSocket)

    else FClientSocket.Open(FHost, FAddress, FService, FPort, ClientType = ctBlocking);

  end;

end;

这里的Value为True,则调用

FClientSocket.Open(FHost, FAddress, FService, FPort, ClientType = ctBlocking);

去看看吧:

procedure TCustomWinSocket.Open(const Name, Address, Service: string; Port: Word; Block: Boolean);

begin

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

  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, True);

      DoOpen;

    end else

      AsyncInitSocket(Name, Address, Service, Port, 0, True);

  except

    Disconnect(FSocket);

    raise;

  end;

end;

没什么特别之处,以我们设置的方式,也一样调用AsyncInitSocket,同样也是完成Socket的设置

再回去看看第2步中的代码吧,而它的Client参数是设为True,所以最后的一定会调用:

DoOpen:

procedure TCustomWinSocket.DoOpen;

begin

  DoSetASyncStyles;

  Event(Self, seConnecting);

  CheckSocketResult(WinSock.connect(FSocket, FAddr, SizeOf(FAddr)), ''''connect'''');

  FLookupState := lsIdle;

  if not (asConnect in FAsyncStyles) then

  begin

    FConnected := FSocket <> INVALID_SOCKET;

    Event(Self, seConnect);

  end;

end;

和上面说到的Dolisten简直像极了,这里也没有必多说了。我们已经可以向更加简单的第四步进发了。

 

 

4.  ClientSocket向服务端连接后,WinSock会向服务端发送一个事件,,而上面已经过了事件获取函数:CMSocketMessage

其中的消息标识码是:FD_ACCEPT,所以会调用Accept(Socket);函数,这个与其他的事件方法不同,我们来看看它的源码就知道了:

procedure TCustomWinSocket.Accept(Socket: TSocket);

begin

end;

Socket的父类将这个方法设为虚方法,并什么事也不做,可知它的子类ServerWinSocket一定覆盖了这个方法,并可能要做一些线程分配方面的工作,但这又是一个大函数了,又要花一大篇来分析了,但离胜利之地已经不远了,这一步完成,其他就全部都是小菜一碟了。

(41)

procedure TServerWinSocket.Accept(Socket: TSocket);

var

  ClientSocket: TServerClientWinSocket;

  ClientWinSocket: TSocket;

  Addr: TSockAddrIn;

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

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