zoukankan      html  css  js  c++  java
  • SocketServer源码学习(二)

    SocketServer 中非常重要的两个基类就是:BaseServer 和 BaseRequestHandler
    在SocketServer 中也提供了对TCP以及UDP的高级封装,这次我们主要通过分析关于TCP的处理逻辑来对SocketServer模块进行一个很好的理解和学习

    TCPServer

    TCPServer 继承了BaseServer,初始化的时候,进行了socket套接字的创建。

    def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
        """Constructor.  May be extended, do not override."""
        BaseServer.__init__(self, server_address, RequestHandlerClass)
        self.socket = socket.socket(self.address_family,
                                    self.socket_type)
        if bind_and_activate:
            try:
                self.server_bind()
                self.server_activate()
            except:
                self.server_close()
                raise

    在这里我们看到了我们非常熟悉的关于socket的创建的内容:
    self.socket = socket.socket(self.address_family, self.socket_type)
    通过socket模块创建了socket对象,接着调用了server_bind和server_activate

    server_bind

    源码内容如下:

    def server_bind(self):
        """Called by constructor to bind the socket.
    
        May be overridden.
    
        """
        if self.allow_reuse_address:
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.bind(self.server_address)
        self.server_address = self.socket.getsockname()

    这里我们看到了非常熟悉的操作socket.bind方法,以及设置了socket的相关属性

    server_activate

    源码内容如下:

    def server_activate(self):
        """Called by constructor to activate the server.
    
        May be overridden.
    
        """
        self.socket.listen(self.request_queue_size)

    同样的这里的调用也非常简单就是执行了socket.listen

    get_request

    在TCPServer类中我们还看到了get_request方法,源码内容如下:

    def get_request(self):
        """Get the request and client address from the socket.
    
        May be overridden.
    
        """
        return self.socket.accept()

    这个的调用其实我们可以在BaseServer这个基类中看到,我们之前看过关于BaseServer中这个基类的源码
    我们可以从我们调用BaseServer基类中的serve_forever方法查看,这里是调用了_handle_request_noblock方法,我继续查看_handle_request_noblock这个源码

    def _handle_request_noblock(self):
        """Handle one request, without blocking.
    
        I assume that selector.select() has returned that the socket is
        readable before this function was called, so there should be no risk of
        blocking in get_request().
        """
        try:
            request, client_address = self.get_request()
        except OSError:
            return
        if self.verify_request(request, client_address):
            try:
                self.process_request(request, client_address)
            except:
                self.handle_error(request, client_address)
                self.shutdown_request(request)
        else:
            self.shutdown_request(request)

    可以看到这里最后是调用了process_request来处理请求,继续查看源码:

    def process_request(self, request, client_address):
        """Call finish_request.
    
        Overridden by ForkingMixIn and ThreadingMixIn.
    
        """
        self.finish_request(request, client_address)
        self.shutdown_request(request)
    
    def finish_request(self, request, client_address):
        """Finish one request by instantiating RequestHandlerClass."""
        self.RequestHandlerClass(request, client_address, self)

    从上面的代码我们可以到最后是在finish_request中实例化了RequestHandlerClass
    我们 这个时候查看一下BaseRequestHandler这个基类的源码如下:

    class BaseRequestHandler:
    
        """Base class for request handler classes.
    
        This class is instantiated for each request to be handled.  The
        constructor sets the instance variables request, client_address
        and server, and then calls the handle() method.  To implement a
        specific service, all you need to do is to derive a class which
        defines a handle() method.
    
        The handle() method can find the request as self.request, the
        client address as self.client_address, and the server (in case it
        needs access to per-server information) as self.server.  Since a
        separate instance is created for each request, the handle() method
        can define other arbitrary instance variables.
    
        """
    
        def __init__(self, request, client_address, server):
            self.request = request
            self.client_address = client_address
            self.server = server
            self.setup()
            try:
                self.handle()
            finally:
                self.finish()
    
        def setup(self):
            pass
    
        def handle(self):
            pass
    
        def finish(self):
            pass

    在初始化函数里我们看到了调用setup()方法,这setup在StreamRequestHandler会被重写

    StreamRequestHandler

    TCPServer实现了使用tcp套接字的网络服务,Handler方面则是对应的StreamRequestHandler。它继承了BaseRequestHandler。基类的setup方法和finish方法被它重写,用于通过连接实现缓存文件的读写操作。

    setup方法

    源码内容如下:

    def setup(self):
        self.connection = self.request
        if self.timeout is not None:
            self.connection.settimeout(self.timeout)
        if self.disable_nagle_algorithm:
            self.connection.setsockopt(socket.IPPROTO_TCP,
                                       socket.TCP_NODELAY, True)
        self.rfile = self.connection.makefile('rb', self.rbufsize)
        self.wfile = self.connection.makefile('wb', self.wbufsize)

    这里主要设置了对应连接的属性,其中创建了两个对象非常重要:
    一个可读(rfile)和一个可写(wfile)的“文件”对象
    但是实际并不是创建了文件,而是封装了读取数据和发送数据的操作,抽象成了对文件的操作
    可以理解:
    self.rfile 就是读取客户端数据的对象,它有一些方法可以读取数据。self.wfile则是用来发送数据给客户端的对象。

    整理流程(TCP)

    实现TCP服务需要使用TCPServer和StreamRequestHandler共同协作

  • 相关阅读:
    SpringBoot整合NoSql--(四)Session共享
    SpringBoot整合NoSql--(三)Redis集群
    SpringBoot整合NoSql--(二)MongoDB
    SpringBoot整合NoSql--(一)Redis
    SpringBoot整合持久层技术--(三)Spring Data JPA
    ArcGIS Server 10.4切片图的制作与发布
    ArcGIS api for JavaScript 3.27 聚合(cluster)
    ArcGIS api for JavaScript 3.27 按需显示需要的图层
    ArcGIS api for JavaScript 3.27 在线浏览的一些小部件
    WebGIS小理论(持续更新)
  • 原文地址:https://www.cnblogs.com/zhaof/p/8890600.html
Copyright © 2011-2022 走看看