//********************************************************************************** //说明: 阻塞线程下为什么不触发OnRead和OnWrite事件 //作者: licwing 时间: 2001-5-18 //Email: [email protected] //********************************************************************************** 1.首先先分析TServerSocket的继承关系 TAbstractSocket->TCustomSocket->TCustomServerSocket->TServerSocket 属性 ServerType 是在 TCustomServerSocket 里面定义的 property ServerType: TServerType read GetServerType write SetServerType; 同时在TCustomServerSocket里定义了TServerWinSocket,用来处理客户连接 TServerWinSocket的继承关系如下: TCustomWinSocket->TServerWinSocket 也就是说我们在TServerSocket里面触发的OnRead,OnWrite事件事实上是由TServerSocket 的父类TCustomServerSocket中的TServerWinSocket触发的。
2.现在我们分析在TCustomServerSocket里定义的TServerWinSocket客户连接方法 procedure TServerWinSocket.Accept(Socket: TSocket); var ClientSocket: TServerClientWinSocket; ClientWinSocket: TSocket; Addr: TSockAddrIn; Len: Integer; OldOpenType, NewOpenType: Integer; begin Len := SizeOf(OldOpenType); if getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@OldOpenType), Len) = 0 then //从这里开始是处理多线程的 try if FServerType = stThreadBlocking then begin // SO_SYNCHRONOUS_NONALERT = $20 在winsock单元里面定义 //{$EXTERNALSYM SO_SYNCHRONOUS_NONALERT} NewOpenType := SO_SYNCHRONOUS_NONALERT; setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@NewOpenType), Len); end; Len := SizeOf(Addr); ClientWinSocket := WinSock.accept(Socket, @Addr, @Len); if ClientWinSocket <> INVALID_SOCKET then begin ClientSocket := GetClientSocket(ClientWinSocket); if Assigned(FOnSocketEvent) then FOnSocketEvent(Self, ClientSocket, seAccept); if FServerType = stThreadBlocking then begin //********多线程事件响应关键部分******* //TAsyncStyle = (asRead, asWrite, asOOB, asAccept, asConnect, asClose); //asRead The socket receives notification that the connection is ready for reading. //asWrite The socket receives notification that the connection is ready for writing. ClientSocket.ASyncStyles := []; //************************************* GetServerThread(ClientSocket); end; end; finally Len := SizeOf(OldOpenType); setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@OldOpenType), Len); end; end;
3.ASyncStyles属性只有在TCustomWinSocke类里面定义的,再看SetAsyncStyles过程 procedure TCustomWinSocket.DoSetAsyncStyles; var Msg: Integer; Wnd: HWnd; Blocking: Longint; begin Msg := 0; Wnd := 0; if FAsyncStyles <> [] then //非阻塞模式 begin Msg := CM_SOCKETMESSAGE; //由消息CM_SOCKETMESSAGE触发的过程是过程 //TCustomWinSocket.CMSocketMessage(var Message: TCMSocketMessage); Wnd := Handle; end; WSAAsyncSelect(FSocket, Wnd, Msg, Longint(Byte(FAsyncStyles))); //非阻塞模式处理 if FASyncStyles = [] then //阻塞模式 begin Blocking := 0; ioctlsocket(FSocket, FIONBIO, Blocking);//阻塞模式处理 end; end;
4.再看由消息CM_SOCKETMESSAGE触发的过程 procedure TCustomWinSocket.CMSocketMessage(var Message: TCMSocketMessage); begin with Message do if CheckError then case SelectEvent of FD_CONNECT: Connect(Socket); FD_CLOSE: Disconnect(Socket); FD_READ: Read(Socket); //触发Read事件 FD_WRITE: Write(Socket); //触发Write事件 FD_ACCEPT: Accept(Socket); end; end;
现在应该明白为什么在阻塞模式下不触发OnRead和OnWrite事件了吧?
|
请发表评论