博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SocketServer源码学习(二)
阅读量:4307 次
发布时间:2019-06-06

本文共 4863 字,大约阅读时间需要 16 分钟。

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

 

转载于:https://www.cnblogs.com/zhaof/p/8890600.html

你可能感兴趣的文章
Linux(SUSE 12)安装Tomcat
查看>>
Linux(SUSE 12)安装jboss4并实现远程访问
查看>>
Neutron在给虚拟机分配网络时,底层是如何实现的?
查看>>
netfilter/iptables全攻略
查看>>
Overlay之VXLAN架构
查看>>
Eclipse : An error occurred while filtering resources(Maven错误提示)
查看>>
在eclipse上用tomcat部署项目404解决方案
查看>>
web.xml 配置中classpath: 与classpath*:的区别
查看>>
suse如何修改ssh端口为2222?
查看>>
详细理解“>/dev/null 2>&1”
查看>>
suse如何创建定时任务?
查看>>
suse搭建ftp服务器方法
查看>>
centos虚拟机设置共享文件夹并通过我的电脑访问[增加smbd端口修改]
查看>>
文件拷贝(IFileOperation::CopyItem)
查看>>
MapReduce的 Speculative Execution机制
查看>>
大数据学习之路------借助HDP SANDBOX开始学习
查看>>
Hadoop基础学习:基于Hortonworks HDP
查看>>
为什么linux安装程序 都要放到/usr/local目录下
查看>>
Hive安装前扫盲之Derby和Metastore
查看>>
永久修改PATH环境变量的几种办法
查看>>