• Delphi Socket 阻塞线程下为什么不触发OnRead和OnWrite事件


    //**********************************************************************************
    //说明: 阻塞线程下为什么不触发OnRead和OnWrite事件
    //作者: licwing          时间: 2001-5-18
    //Email: rurality@21cn.com
    //**********************************************************************************
    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事件了吧?

  • 相关阅读:
    Oracle RAC asm常用命令
    Oracle10g RAC关闭及启动步骤
    工具系列 | git checkout 可替换命令 git switch 和 git restore
    工具系列 | 博客签名
    工具系列 | Token认证方式之JWT【转载】
    PHP系列 | ThinkPHP5.1 如何自动加载第三方SDK(非composer包 )
    工具系列 | 虚拟化VMware ESXi 6.7服务器安装配置
    安全系列 | 【阿里云】安全告警处理-进程异常行为-访问恶意下载源
    其他系列 | Github 贡献统计异常的处理
    MySQL系列 | 安装 MySQL 5.7 on Ubuntu 16.04 | 18.04
  • 原文地址:https://www.cnblogs.com/zhangzhifeng/p/5867189.html
Copyright © 2020-2023  润新知