|
FLookupState := lsIdle;
if Client then
DoOpen
else DoListen(QueueSize);
我们看到FLookupState已经又回到了IsIdle,所以就不再递归了。
最好,我们得来看看DoListen这个方法,这个大概就是万事具务,只欠东风的东风了,我们猜测它会在这里调用Bind和Listen等API,并触发Oolisten事件:
(2211121)
procedure TCustomWinSocket.DoListen(QueueSize: Integer);
begin
CheckSocketResult(bind(FSocket, FAddr, SizeOf(FAddr)), ''''bind'''');
DoSetASyncStyles;
if QueueSize > SOMAXCONN then QueueSize := SOMAXCONN;
Event(Self, seListen);
CheckSocketResult(Winsock.listen(FSocket, QueueSize), ''''listen'''');
FLookupState := lsIdle;
FConnected := True;
end;
哈,一切都明朗了,所有API都在这里调用了,事件也触发了。现在就等客户来连接了
只是还没有完,还有一个DoSetASyncStyles方法,坚持走下去吧,会到挑花园的:
(22111211)
procedure TCustomWinSocket.DoSetAsyncStyles;
var
Msg: Integer;
Wnd: HWnd;
Blocking: Longint;
begin
Msg := 0;
Wnd := 0;
if FAsyncStyles <> [] then
begin
Msg := CM_SOCKETMESSAGE;
Wnd := Handle;
end;
WSAAsyncSelect(FSocket, Wnd, Msg, Longint(Byte(FAsyncStyles)));
if FASyncStyles = [] then
begin
Blocking := 0;
ioctlsocket(FSocket, FIONBIO, Blocking);
end;
end;
有两个情况,当FAsyncStyles有元素时和没有元素时,从上面的代码中我们看到它是有元素的。则:
Msg := CM_SOCKETMESSAGE;
Wnd := Handle;
第一句应该是指针Socket消息了,用于与客户端的读写事件的触发的吧。而第二句,则我仔细看了,Handle是TCustomWinSocket的一个属性:
property Handle: HWnd read GetHandle;
再看看GetHandle方法
function TCustomWinSocket.GetHandle: HWnd;
begin
if FHandle = 0 then
FHandle := AllocateHwnd(WndProc);
Result := FHandle;
end;
我们记得上面并没有对FHandle进行赋值,所以它应该为0,则调用了AllocateHwnd,这个方法产生一个不可见的窗口用于接收消息,窗口过程就是WndProc,在CustomWinSocket有声明:
procedure TCustomWinSocket.WndProc(var Message: TMessage);
begin
try
Dispatch(Message);
except
if Assigned(ApplicationHandleException) then
ApplicationHandleException(Self);
end;
end;
可以知道,他调用Object的Dispatch(Message);进行消息分配,而我们看到类中有消息函数的声明:
procedure CMSocketMessage(var Message: TCMSocketMessage); message CM_SOCKETMESSAGE;
当事件发生时就会调用这些消息处理函数了。而这些消息是从那里发生的呢,得回过头去看看DoSetAsyncStyles方法,其中有这一个SocketAPI:
WSAAsyncSelect(FSocket, Wnd, Msg, Longint(Byte(FAsyncStyles)));
就是通过它,当有网络消息发生的时候,才会触发上面事件的,而Longint(Byte(FAsyncStyles)
则指定允许触发哪些事件。(具体的还是看看MSDN的说明吧)
呼还没有完吗,其实差不多了,我们现在知道了当有客户端连接或读写,是通过什么方式来让服务端知道并触发相应的事件的,说到底还是用了WinSock的API,只不过Delphi用自己的事件处理方式将那些Socket异步消息转化成自己的事件了,这个过程是非常精彩的,很值得我们学习。
但现在只剩下最一步了,TCustomWinSocket消息处理方法中,如何转化为事件,并传递到ServerSocket去的呢,答案只有在源代码中找了:
procedure TCustomWinSocket.CMSocketMessage(var Message: TCMSocketMessage);
function CheckError: Boolean;
var
ErrorEvent: TErrorEvent;
ErrorCode: Integer;
begin
if Message.SelectError <> 0 then
begin
Result := False;
ErrorCode := Message.SelectError;
case Message.SelectEvent of
FD_CONNECT: ErrorEvent := eeConnect;
FD_CLOSE: ErrorEvent := eeDisconnect;
FD_READ: ErrorEvent := eeReceive;
FD_WRITE: ErrorEvent := eeSend;
FD_ACCEPT: ErrorEvent := eeAccept;
else
ErrorEvent := eeGeneral;
end;
Error(Self, ErrorEvent, ErrorCode);
if ErrorCode <> 0 then
raise ESocketError.CreateResFmt(@sASyncSocketError, [ErrorCode]);
end else Result := True;
end;
begin
with Message do
if CheckError then
case SelectEvent of
FD_CONNECT: Connect(Socket);
&n 上一页 [1] [2] [3] [4] [5] [6] [7] [8] [9] 下一页 没有相关教程
|