• Delphi TTcpClient 和 TTcpServer 类 (TBaseSocket、TIpSocket、TCustomIPClient、TTcpClient、TUdpSocket、TRawSocket、TCustomTcpServer、TTcpServer) 介绍


    Delphi TTcpClient 和 TTcpServer 类 (TBaseSocket、TIpSocket、TCustomIPClient、TTcpClient、TUdpSocket、TRawSocket、TCustomTcpServer、TTcpServer) 介绍

    1、继承关系 及 各类介绍

    windows socket部分 (sockets.pas) 中各个类的继承关系:

    TBaseSocket

    • TIpSocket
      • TCustomIPClient    
        • TTcpClient      
        • TUdpSocket          
      • TRawSocket            
      • TCustomTcpServer
        • TTcpServer

    TBaseSocket:

    这个是socket基类,此类中封装了winsocket的基本操作,如建立什么类型的socket,关闭socket,数据的发送、接收、检测是否可以读写及异常。

    并提供了几个控制反转调用。具有socket使用的地址族、协议、类型、socket句柄等成员变量。

    • ErrorCheck socket  //函数执行结果检测。
    • DoHandleError socket  //函数执行失败后的错误处理。
    • Open  //建立一个socket用户对象(windows内部处理)。
    • Close  //关闭建立的socket。
    • PeekBuf  //探测接收缓冲区数据长度。
    • SendBuf  //写入发送缓冲区。
    • ReceiveBuf  //从接收缓冲区读数据。
    • SendStream  //发送一个流对象中的数据。
    • WaitForData  //判断接收缓冲区是否有数据可读(对select调用)。

    TIpSocket

    这个类在TBaseSocket基础上增加了绑定地址、接收指定指定地址数据,发送数据到指定地址及主机名和地址转换等方法, 增加了本地地址、端口,远程地址、端口成员变量。

      默认建立的是af_inet地址族下的流式socket。

    • Bind  //绑定本地地址和端口到socket句柄。
    • ReceiveFrom  //接收指定地址的数据,一般udp使用。
    • SendTo  //发送数据到指定的地址端口,一般udp使用。

      到目前为止此类可以建立一个基本流式socket,但他没有连接,断开,监听等操作。

    TCustomIpClient

    客户端socket类,顾名思义,此类是作为socket客户端使用的(也许发起连接的就可以称为客户端吧!,连接后两边其实就是对等的了),所以此类增加了Connect, Disconnet方法,同时改写了TBaseSocket的Open,Close方法。并提供了连接及断开的控制反转。

    • Open  //建立socket并连接到远程地址端口。
    • Close  //关闭socket的收发同时关闭socket(closesocket)。
    • Connect  //对Open的调用。
    • Disconnec  //t对Close的调用。
    • GetThreadObject  //此方法在客户端无用,返回nil。由于服务端等会为每个请求的客户端建立TCustomIpClient来服务,同时每个连接成功的客户端用一条线程专门服务,这个函数便是取那个线程对象用的。线程的引用地址会保存在thread-local变量ThreadObject中。

    TRawSocket

    继承自TIpSocket,默认建立的是支持比较底层协议的socket,未尝试不做解释。

    TUdpSocket

      继承自TIpSocket,建立一个支持udp协议的socket客户端,主要是改变了建立socket的类型和协议,可以参考windows socket()函数建立不同类型的socket参数说明。

     

    TTcpClient

    继承自TCustomIpClient无自己的成员函数和变量。

    TClientSocketThread

    此线程类主要为服务端使用,当一个连接请求到来时server会取一个此线程类得对象来处理socket的连接,

    此线程类得对象主要是生成一个TCustomIpClient来接收sockets accept的返回参数。但注意到execute中在调用了服务端的Accept()后立即释放了TCustomIPClient,这样意味着立即和客户端断开了,是否无法做数据处理,只是从连接队列中取出一个连接socket而已!!!我们在接下来的TCustomTcpServer.Accept(var clientSocket: TCustomIpClient)中发现socket函数accept成功后会有DoAccept调用,那么在TTcpServer.OnAccept中加死循环处理通讯知道断开是一种方法,如下:

    procedure DoAccept(Sender: TObject; ClientSocket: TCustomIpClient);
    begin
        // 到这里时客户端建的连接已经被成功处理,ClientSocket便是和对方通讯的Socket的封装
        while not ClientSocket.GetThreadObject.Finished and ClientSocket.Connected do  // GetThreadObject就是那个获取那个为客户端服务的线程,上面已介绍
       begin
           // bRead, bExcept: Boolean
           if ClientSocket.Select(@bRead, nil, @bExcept, 100) then  // 判断此socket是否可读且没有异常,在客户端断开时也返回true同时读到得数据长度0,证明已经断开
           begin
              if bRead and not bExcept then
              begin
                  if ClientSocket.ReceiveBuf(buf, 512) = 0 then  // 已经断开 buff: array[0..511] of byte
                     ClientSocket.Disconnect   // 断开本地socket改变Connected值
                  else begin
                     // 处理接收的数据
                  end;
              end;
           end;
       end;
        //  到这里已经断开或者线程中发生异常退出
    end;
    • ExecuteSyncProc  //同步到主线程中执行方法(让主线程调用)。
    • ClientSocket  //此线程所建立的TCustomIPClient。
    • ServerSocketThread  //建立此线程的服务端线程。

    TServerSocketThread

    此线程是服务端用于来处理socket请求的线程,他内部有TClientSocketThread缓冲池,默认缓冲10个线程对象,以下介绍他几个方法。

    • AddClientSocketThread  //增加一个客户端socket处理线程并加入线程池,如果线程池中缓冲已满那就返回nil,意味着这个socket连接请求就没办法处理 。这个处理线程可以是TClientSocketThread以及他的派生类对象,如果你没有做派生那默认是TClientSocketThread。
    • CreateThread  //建立一个TClientSocketThread线程类对象。
    • FetchClientSocketThread  //从缓冲池获取一个已经挂起的对象。
    • RemoveClientSocketThread  //这个是供TClientSocketThread调用的,他在释放的时候需要处理。
    • ClearThreadPool  //释放缓冲池中对象。
    • Execute  //主要是等待客户端的连接,当有连接来时取一条线程来服务客户端,如果缓冲池已满此连接请求将无法处理。
    • OnGetThread  //此属性可以调用到派生的TClientSocketThread类对象。

    TCustomTcpServer

    socket服务端,主要是负责处理客户端的请求,继承自TIpSocket,此服务端类默认是线程阻塞模式(其实socket就只有阻塞于非阻塞,这里的线程阻塞是每个线程服务一个客户端,建立的通讯socket是阻塞的,这样代码好写),如果是阻塞或者非阻塞方式,那自己要处理的事多些,当然自由度应该大些。以下介绍此类得几个方法:

    • GetThread  //获取一个TClientSocketThread类对象,如果是线程阻塞模式此函数供TServerSocketThread调用。
    • DoAccept   //处理请求成功后的控制反转。
    • Listen //在socket上启动监听。
    • Open //改写父类方法,调用TBaseSocket.Open建立socket并绑定本地地址端口,启动监听,唤醒服务线程。
    • Close //改写父类方法,终止并释放服务线程TServerSocketThread,关闭监听socket。
    • Accept  //建立TCustomIpClient接收连接请求。
    • Accept  //如上面的Accept,成功后改变TCustomIpClient对象的属性,并调用DoAccept。
    • WaitForConnection //等待客户端连接,有连接才返回,否则阻塞导致执行线程挂起。

    TTcpServer

      继承自TCustomTcpServer,无自己的方法。

     

    2、其他

    线程阻塞模式下服务启动后,TServerSocketThread会调用WaitForConnection等待连接请求,有连接请求时会被唤醒,然后获取一个线程TclientSocketThread(可能生成)来处理这条连接,当缓冲池已满且获取不到空闲挂起的线程时此连接请求将无法处理,会一直存在连接队列,无法处理,所以使用TClientSocketThread服务时可以将ThreadCacheSize设置大些。而TClientSocketThread从连接队列获取到socket后会立即关闭,所以必须在DoAccept方法中处理此socket直到关闭,在TCustomTcpServer.OnAccept有公布。

     

    另一种方法是不用TServerSocketThread中建立的TClientSocketThread线程来处理数据读写,他们只处理连接请求,而且也不需要10条。这样就必须从TClientSocketThread

    派生从一个类来改写TClientSocketThread的一些逻辑(TClientSocketThread.Execute如果不在OnAccept中死循环socket将会被立即释放),同时在TCustomTcpServer.OnGetThread中提供派生类得对象供TServerSocketThread使用。

    TMyClientSocketThread = class(TClientSocketThread)
    protected
        procedure SyncProc; override;  // 要同步到主线程的代码
        procedure Execute; override;
    end;

    Execute如下:

    var
      Client: TCustomIpClient;
    begin
      // inherited;
      Client := TCustomIpClient.Create(nil);
      if Assigned(Client) then
      begin
        if ServerSocketThread.ServerSocket.Accept(Client) then   // 为Client赋值
        begin
            // 对建立成功的Client处理,比如加入TList,然后由其他线程处理,这里应该快速做完,这样这个线程就可以等待继续被调度,否则其他连接长时间无线程处理
            // 依然在连接队列中
        end else begin  // 失败就释放此socket
          Client.Free;
        end;
        if not Terminated then  // 接收客户端socket成功,挂起线程
          Suspend;
      end;
    end;
    

      

     

     

    创建时间:2015.03.30  更新时间:2020.05.28

  • 相关阅读:
    Mybatis学习(2)原始dao开发和使用mapper接口代理开发
    Mybatis学习(1)
    Leetcode | Merge Intervals
    GDB打印STL容器内容
    LeetCode | Max Points on a Line
    最长不减子序列【转】
    LeetCode | Evaluate Reverse Polish Notation
    LeetCode | Word Ladder II
    LeetCode | Valid Number
    LeetCode | Set Matrix Zeroes
  • 原文地址:https://www.cnblogs.com/guorongtao/p/4377668.html
Copyright © 2020-2023  润新知