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共同协作

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏友弟技术工作室

Beego Controllercontroller 逻辑控制器介绍Controller中数据参数处理获取参数

controller就是处理具体的逻辑的,router将请求分发到指定的controlller,controller处理请求,然后返回。 首先我们还是从源码分...

39420
来自专栏飞雪无情的博客

Go语言经典库使用分析(二)| Gorilla Context

在Go1.7之前,Go标准库还没有内置Context的时候,如果我们想在一个Http.Request里附加值,怎么做呢?一般都是Map对象,存储对应的Reque...

21830
来自专栏跟着阿笨一起玩NET

推荐一个代码自动完成的工具AutoCode

本文转载:http://www.cnblogs.com/xiaoxiangfeizi/archive/2012/07/24/2605884.html

55710
来自专栏LanceToBigData

JavaWeb(一)Servlet中的request与response

一、HttpServletRequest概述 1.1、HttpServletRequest简介   HttpServletRequest对象代表客户端的请求,当...

31780
来自专栏SDNLAB

SDN开发笔记(七):L2switch源码分析(上)

前言 一般按照odl官方文档或者wiki安装L2switch组件会采用在karaf控制台上输入feature:install odl-l2switch-all命...

42980
来自专栏Charlie's Road

didReceiveMemoryWarning iOS开发

iPhone下每个app可用的内存是被限制的,如果一个app使用的内存超过20M,则系统会向该app发送Memory Warning消息。收到此消息后,app必...

45230
来自专栏智能大石头

NewLife.XCode中如何借助分部抽象多个具有很多共同字段的实体类

背景: 两个实体类:租房图片、售房图片 这两个表用于存储房源图片记录,一个房源对应多个图片,两个表的差别就在于一个业务关联字段。 租房图片中的RentID记录这...

17660
来自专栏java 成神之路

基于ReentrantLock发生死锁的解决方案

33760
来自专栏分布式系统进阶

Kafka集群建立过程分析

11420
来自专栏Golang语言社区

Golang构建HTTP服务(二)--- Handler,ServeMux与中间件

Golang标准库http包提供了基础的http服务,这个服务又基于Handler接口和ServeMux结构的做Mutilpexer。实际上,go的作者设计Ha...

45430

扫码关注云+社区

领取腾讯云代金券