前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SocketServer源码学习(二)

SocketServer源码学习(二)

作者头像
coders
发布2018-05-28 16:44:09
6150
发布2018-05-28 16:44:09
举报
文章被收录于专栏:coder修行路coder修行路

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

TCPServer

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

代码语言:javascript
复制
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

源码内容如下:

代码语言:javascript
复制
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

源码内容如下:

代码语言:javascript
复制
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方法,源码内容如下:

代码语言:javascript
复制
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这个源码

代码语言:javascript
复制
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来处理请求,继续查看源码:

代码语言:javascript
复制
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这个基类的源码如下:

代码语言:javascript
复制
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方法

源码内容如下:

代码语言:javascript
复制
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共同协作

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-04-20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • TCPServer
    • server_bind
      • server_activate
      • get_request
      • StreamRequestHandler
        • setup方法
        • 整理流程(TCP)
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档