|
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] 下一页 没有相关教程
|