【bf88必发唯一官网】深刻剖析SocketServer模块,Python的socket模块源码中的一些兑现中央分析

by admin on 2019年2月9日

一、简介(翻译)

 

 通用socket server 类

 该模块尽力从各个差距的上边定义server:

 对于socket-based servers:
 — address family:
    – AF_INET{,6}: IP socket (default)
    – AF_UNIX: Unix domain sockets
    – others, 如 AF_DECNET (见<socket.h>) (不常用)
 — socket type:
    – SOCK_STREAM (可信三番五次 TCP)
    – SOCK_DGRAM (UDP)
bf88必发唯一官网, 
 对于request-based servers:
— client
address在发出进一步的呼吁从前必要验证(那实质上把持有须求发出请求的进程在经过认证在此以前给阻塞住了)
— 如何处理多请求:
   – 同步 (一回只好处理一个伸手)
   – forking (fork一个新的经过来拍卖一个伸手)
   – threading (创立一个新的线程来拍卖一个呼吁)
 
   在这一个模块的各个别中,最简易的服务器类型就是synchronous TCP/IP
server。那是一个糟糕的类设计,可是也保留了部分安顿的门类理念。

上面是两个类的接轨关系图表,其中的八个代表四体系型的同步服务器:
        +————–+
        | BaseServer |
        +————–+
              |
              v
        +————+            +———————-+
        | TCPServer |——->| UnixStreamServer |
        +————+            +———————-+
              |
              v
        +————-+           +————————–+
        | UDPServer |——->| UnixDatagramServer |
        +————-+           +————————–+
       
瞩目:UnixDatagramServer继承于UDPServer,而不是UnixStreamServer,IP和Unix
stream server之间仅部分差别就是address
family,五个服务器类的情节半数以上是简约的双重。

  forking和threading
可以被创设用于ForkingMixIn和TreadingMixIn mix-in类。例如: threading UDP
server类会被如下方式创设:
 class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
 (详细可知后文示例)

  Mix-in
那一个类必须首先落成,因为它重写了定义UDPServer的形式。设置分裂的积极分子变量也转移了中央的服务器构造方法。

 
为了落实一个劳动,你必须从基类BaseRequestHandler中另行定义它的handle方法。然后经过把服务类与您重写的Handle方法类结合,以此运行新的服务类。

 
请求处理类的TCP和UDP的不二法门是差其他,那些可以通过运用请求处理的子类StreamRequestHandler或者DatagramRequestHandler来隐藏。

本来,你还足以考虑其他的办法。
    例如,要是服务中隐含呼吁修改的内存的气象,那么使用forking
server没有其他意义(因为在子进度中修改将不对父进度的开头化状态有震慑,父进程也不会把那一个修改的参数传递给其他子进度)。那种情状下,你可以应用threading
server,而且你更有可能要求使用“锁”,以此来防止多少个请求同时到达而使服务器状态爆发争论。
   
其余,如若您在搭建如HTTP服务器等,所有的数额都会储存在表面(如文件系统中),当客户端的一项请求被拍卖时,并且客户端的读取数据的快慢很慢,synchronous
class将会使服务不做出响应,那说不定要求保持很长日子。
   
在一部分意况下,请求同步可能要求适量的不二法门,不过为了在子进度中完毕请求要面临请求数据的熏陶。那足以经过动用同步服务器来促成,并且在伸手处理类中的Handle方法中显著指定fork的进度。
   
另一种处理两个同时发生的哀求的艺术是维系一张显然的到位请求的表单,使用select()方法来判断哪些请求应该在接下去做出响应(或者判断是或不是要处理新到来的伏乞),当每一个客户端需求树立很长日子的接连时,那对于stream
services来说尤其主要。(前提是不行使线程和子进度的主意)

二、用到的有所的类措施

import socket
import select
import sys
import os
import errno
try:
    import threading
except ImportError:
    import dummy_threading as threading

__all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer",
           "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler",
           "StreamRequestHandler","DatagramRequestHandler",
           "ThreadingMixIn", "ForkingMixIn"]
if hasattr(socket, "AF_UNIX"):
    __all__.extend(["UnixStreamServer","UnixDatagramServer",
                    "ThreadingUnixStreamServer",
                    "ThreadingUnixDatagramServer"])

 

**三、BaseServer和BaseRequestHandler

       
Python把网络服务抽象成多个举足轻重的类,一个是Server类,用于拍卖连接相关的互联网操作,此外一个则是RequestHandler类,用于拍卖数量有关的操作。并且提供多少个MixIn
类,用于增加 Server,完成多进度或四线程。在打造互联网服务的时候,Server 和
RequestHandler 并不是分开的,RequestHandler的实例对象在Server 内合作Server工作。**

       3.1 BaseServer分析

 
BaseServer可供外部调用的形式:

**- __init__(server_address,
RequestHandlerClass)

  • serve_forever(poll_interval=0.5)
  • shutdown()
  • handle_request()  # if you do not use serve_forever()
  • fileno() -> int   # for select()**

即我们可以通过init起初化,对外提供serve_forever()和handle_request()方法

3.1.1 init初始化

timeout = None

    def __init__(self, server_address, RequestHandlerClass):
        """Constructor.  May be extended, do not override."""
        self.server_address = server_address
        self.RequestHandlerClass = RequestHandlerClass
        self.__is_shut_down = threading.Event()
        self.__shutdown_request = False

 

**__init__的机要功效就是创设server对象,并伊始化server_【bf88必发唯一官网】深刻剖析SocketServer模块,Python的socket模块源码中的一些兑现中央分析。address和RequestHandlerClass。
**

server_address就是包罗主机地址和端口的元组。

 

3.1.2 serve_forever

 

    def serve_forever(self, poll_interval=0.5):
        """Handle one request at a time until shutdown.

        Polls for shutdown every poll_interval seconds. Ignores
        self.timeout. If you need to do periodic tasks, do them in
        another thread.
        """
        self.__is_shut_down.clear()
        try:
            while not self.__shutdown_request:

                r, w, e = _eintr_retry(select.select, [self], [], [],
                                       poll_interval)
                if self in r:
                    self._handle_request_noblock()
        finally:
            self.__shutdown_request = False
            self.__is_shut_down.set()

 

  
那里运用了select()函数,即server_forever接受了一个poll_interval=0.5的参数传入,那意味用于select轮询的时日,然后进入一个最为循环中,在这几个轮回中,select每隔poll_interval秒轮询一遍(阻塞于此),以此来实行互联网IO的监听。一旦有新的网络连接请求到来,则会调用_handle_request_noblock()方法处理新的接连。


3.1.3 
_handle_request_noblock()**

    def _handle_request_noblock(self):
        """Handle one request, without blocking.

        I assume that select.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 socket.error:
            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)

 

英文表明已经说的很扎眼,该形式处理的是一个非阻塞请求,首先通过get_request()方法赢得连接,具体完成在其子类,一旦拿到了再而三,立时调用verify_request认证连接音信,通过验证,则调用process_request()方法处理请求,即便中途出现谬误,则调用handle_error处理错误,同时,调用shutdown_request()方法截至那么些一而再。

这上面大家就先看上边提到的其余多少个函数调用:

    def verify_request(self, request, client_address):
        """Verify the request.  May be overridden.

        Return True if we should proceed with this request.

        """
        return True


    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 handle_error(self, request, client_address):
        """Handle an error gracefully.  May be overridden.

        The default is to print a traceback and continue.

        """
        print '-'*40
        print 'Exception happened during processing of request from',
        print client_address
        import traceback
        traceback.print_exc() # XXX But this goes to stderr!
        print '-'*40


    def shutdown_request(self, request):
        """Called to shutdown and close an individual request."""
        self.close_request(request)<pre name="code" class="python">    

    def finish_request(self, request, client_address):
        """Finish one request by instantiating RequestHandlerClass."""
        self.RequestHandlerClass(request, client_address, self)

 

verify_request()方法对request举办认证,平常会被子类重写。

process_request要求小心一下,它被ForkingMixIn

ThreadingMixIn重写,由此是mixin的入口,ForkingMixIn和ThreadingMixIn分别展开多进度和多线程的安排,并且调用finish_request()完结请求,调用shutdown_request()停止请求。

handle_error也可以被子类重写,打印错误的音信和客户端地址。

**finish_request()处理达成请求,在__init__中开创requestHandler对象,并因而requestHandler做出具体的处理。

3.1.4 handle_request()**

    def handle_request(self):
        """Handle one request, possibly blocking.

        Respects self.timeout.
        """
        # Support people who used socket.settimeout() to escape
        # handle_request before self.timeout was available.
        timeout = self.socket.gettimeout()
        if timeout is None:
            timeout = self.timeout
        elif self.timeout is not None:
            timeout = min(timeout, self.timeout)
        fd_sets = _eintr_retry(select.select, [self], [], [], timeout)
        if not fd_sets[0]:
            self.handle_timeout()
            return
        self._handle_request_noblock()

 

地点已经关系,假诺你从未动用server_forever()方法,表明你指望利用的是阻塞请求来处理连接,如英文描述所说,该方式只是拍卖一个围堵的央浼,依然接纳select()方法轮询来监听互连网连接,可是急需考虑时间超时影响,一旦过期,调用handle_timeout()方法处理超时,一般在子类重写该措施;如果在逾期事先监听到了网络的连年请求,则同server_forever一样,调用_handle_request_noblock()方法,落成对新的连接的乞请处理。

3.2 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 arbitrary other instance variariables.

    """

    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

 

     
以上描述表达,所有requestHandler都延续BaseRequestHandler基类,该类会处理每一个呼吁。在__【bf88必发唯一官网】深刻剖析SocketServer模块,Python的socket模块源码中的一些兑现中央分析。init__中初步化实例变量request、client_address、server,然后调用handle()方法成功请求处理。那么,大家唯一须要做的就是重写好Handle()方法,处理所有的呼吁。

 

小结:营造一个互连网服务,须求一个BaseServer用于拍卖互联网IO,同时在里头创设requestHandler对象,对富有具体的呼吁做处理。

四、种种子类

4.1 由BaseServer衍生的子类

4.1.1 TCPServer

class TCPServer(BaseServer):
    address_family = socket.AF_INET

    socket_type = socket.SOCK_STREAM

    request_queue_size = 5

    allow_reuse_address = False

    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

    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()

    def server_activate(self):
        """Called by constructor to activate the server.

        May be overridden.

        """
        self.socket.listen(self.request_queue_size)

    def server_close(self):
        """Called to clean-up the server.

        May be overridden.

        """
        self.socket.close()

    def fileno(self):
        """Return socket file number.

        Interface required by select().

        """
        return self.socket.fileno()

    def get_request(self):
        """Get the request and client address from the socket.

        May be overridden.

        """
        return self.socket.accept()

    def shutdown_request(self, request):
        """Called to shutdown and close an individual request."""
        try:
            #explicitly shutdown.  socket.close() merely releases
            #the socket and waits for GC to perform the actual close.
            request.shutdown(socket.SHUT_WR)
        except socket.error:
            pass #some platforms may raise ENOTCONN here
        self.close_request(request)

    def close_request(self, request):
        """Called to clean up an individual request."""
        request.close()

 

 在BaseServer基础上加码了一个TCP的socket连接,使用server_bind、server_activate、server_close处理TCP启停等操作,同时伸张了get_request、shutdown_request、close_request处理客户端请求。

4.1.2 UDPServer

class UDPServer(TCPServer):

    """UDP server class."""

    allow_reuse_address = False

    socket_type = socket.SOCK_DGRAM

    max_packet_size = 8192

    def get_request(self):
        data, client_addr = self.socket.recvfrom(self.max_packet_size)
        return (data, self.socket), client_addr

    def server_activate(self):
        # No need to call listen() for UDP.
        pass

    def shutdown_request(self, request):
        # No need to shutdown anything.
        self.close_request(request)

    def close_request(self, request):
        # No need to close anything.
        pass

 

继承自TCPServer,将socket改为了SOCK_DGRAM型,并修改了get_request,用于从SOCK_DGRAM中获取request。同时server_activate、shutdown_request、close_request都改成了空(UDP不须要),比TCP不难一些。

4.2
由BaseRequestHandler衍生的子类

4.2.1 StreamRequestHandler

class StreamRequestHandler(BaseRequestHandler):
    rbufsize = -1
    wbufsize = 0
    timeout = None
    disable_nagle_algorithm = False
    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)

    def finish(self):
        if not self.wfile.closed:
            try:
                self.wfile.flush()
            except socket.error:
                # An final socket error may have occurred here, such as
                # the local error ECONNABORTED.
                pass
        self.wfile.close()
        self.rfile.close()

 

   
最要紧的效果是依据socket生成了读写socket用的几个文本对象(可以领略为句柄)rfile和wfile

4.2.2 DatagramRequestHandler

class DatagramRequestHandler(BaseRequestHandler):

    # XXX Regrettably, I cannot get this working on Linux;
    # s.recvfrom() doesn't return a meaningful client address.

    """Define self.rfile and self.wfile for datagram sockets."""

    def setup(self):
        try:
            from cStringIO import StringIO
        except ImportError:
            from StringIO import StringIO
        self.packet, self.socket = self.request
        self.rfile = StringIO(self.packet)
        self.wfile = StringIO()

    def finish(self):
        self.socket.sendto(self.wfile.getvalue(), self.client_address)

 

如出一辙是生成rfile和wfile,但UDP不直接关乎socket。这里的rfile是直接由从UDP中读取的数目变化的,wfile则是新建了一个StringIO,用于写多少。

(标题起的有点大,部分分析的不佳,等随后再往祖坟上刨。。。。^-^)

参考博客:

            

**

 

**

**

 

 

 

 

 

一、简介(翻译)

 

 通用socket server 类

 该模块尽力从种种不相同的方面定义server:

 对于socket-based servers:
 — address family:
    – AF_INET{,6}: IP socket (default)
    – AF_UNIX: Unix domain sockets
    – others, 如 AF_DECNET (见<socket.h>) (不常用)
 — socket type:
    – SOCK_STREAM (可信一连 TCP)
    – SOCK_DGRAM (UDP)
 
 对于request-based servers:
— client
address在产生进一步的哀告从前须求验证(那实在把具有必要发出请求的历程在经过验证以前给阻塞住了)
— 怎样处理多请求:
   – 同步 (四次只好处理一个伸手)
   – forking (fork一个新的进度来拍卖一个伸手)
   – threading (创造一个新的线程来处理一个呼吁)
 
   在这么些模块的各体系中,最简便的服务器类型就是synchronous TCP/IP
server。那是一个不好的类设计,可是也保留了一部分企划的体系理念。

上面是四个类的继承关系图表,其中的五个代表二种档次的联手服务器:
        +————–+
        | BaseServer |
        +————–+
              |
              v
        +————+            +———————-+
        | TCPServer |——->| UnixStreamServer |
        +————+            +———————-+
              |
              v
        +————-+           +————————–+
        | UDPServer |——->| UnixDatagramServer |
        +————-+           +————————–+
       
专注:UnixDatagramServer继承于UDPServer,而不是UnixStreamServer,IP和Unix
stream server之间仅部分差别就是address
family,八个劳务器类的情节半数以上是差不离的重复。

  forking和threading
可以被成立用于ForkingMixIn和TreadingMixIn mix-in类。例如: threading UDP
server类会被如下形式开创:
 class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
 (详细可知后文示例)

  Mix-in
这一个类必须首先落实,因为它重写了定义UDPServer的法门。设置不相同的积极分子变量也转移了宗旨的服务器构造方法。

 
为了贯彻一个劳动,你必须从基类BaseRequestHandler中重复定义它的handle方法。然后经过把服务类与你重写的Handle方法类结合,以此运行新的服务类。

 
请求处理类的TCP和UDP的法门是不一样的,那一个能够经过行使请求处理的子类StreamRequestHandler或者DatagramRequestHandler来隐藏。

理所当然,你还是能考虑其余的不二法门。
    例如,假若服务中富含呼吁修改的内存的情景,那么使用forking
server没有任何意义(因为在子进度中修改将不对父进度的开始化状态有影响,父进度也不会把这么些修改的参数传递给其它子进度)。那种情形下,你可以利用threading
server,而且你更有可能要求运用“锁”,以此来避免四个请求同时抵达而使服务器状态发生争辨。
   
其余,假诺您在搭建如HTTP服务器等,所有的数目都会储存在外表(如文件系统中),当客户端的一项请求被拍卖时,并且客户端的读取数据的速度很慢,synchronous
class将会使服务不做出响应,那恐怕必要保持很长日子。
   
在局地境况下,请求同步可能须求适度的章程,但是为了在子进程中做到请求要面临请求数据的影响。这能够通过使用同步服务器来完成,并且在呼吁处理类中的Handle方法中显明指定fork的进程。
   
另一种处理多少个同时爆发的呼吁的章程是涵养一张显明的成就请求的表单,使用select()方法来判定哪些请求应该在接下去做出响应(或者判断是不是要拍卖新到来的哀求),当每一个客户端须求建立很长日子的总是时,这对于stream
services来说极度关键。(前提是不拔取线程和子进程的办法)

二、用到的持有的类格局

import socket
import select
import sys
import os
import errno
try:
    import threading
except ImportError:
    import dummy_threading as threading

__all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer",
           "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler",
           "StreamRequestHandler","DatagramRequestHandler",
           "ThreadingMixIn", "ForkingMixIn"]
if hasattr(socket, "AF_UNIX"):
    __all__.extend(["UnixStreamServer","UnixDatagramServer",
                    "ThreadingUnixStreamServer",
                    "ThreadingUnixDatagramServer"])

 

**三、BaseServer和BaseRequestHandler

       
Python把互联网服务抽象成五个至关紧要的类,一个是Server类,用于拍卖连接相关的互连网操作,此外一个则是RequestHandler类,用于拍卖数据有关的操作。并且提供八个MixIn
类,用于增加 Server,完毕多进度或四线程。在打造网络服务的时候,Server 和
RequestHandler 并不是分离的,RequestHandler的实例对象在Server 内合营Server工作。**

       3.1 BaseServer分析

 
BaseServer可供外部调用的艺术:

**- __init__(server_address,
RequestHandlerClass)

  • serve_forever(poll_interval=0.5)
  • shutdown()
  • handle_request()  # if you do not use serve_forever()
  • fileno() -> int   # for select()**

即我们得以因而init开首化,对外提供serve_forever()和handle_request()方法

3.1.1 init初始化

timeout = None

    def __init__(self, server_address, RequestHandlerClass):
        """Constructor.  May be extended, do not override."""
        self.server_address = server_address
        self.RequestHandlerClass = RequestHandlerClass
        self.__is_shut_down = threading.Event()
        self.__shutdown_request = False

 

**__init__的显要成效就是开创server对象,并开端化server_address和RequestHandlerClass。
**

server_address就是富含主机地址和端口的元组。

 

3.1.2 serve_forever

 

    def serve_forever(self, poll_interval=0.5):
        """Handle one request at a time until shutdown.

        Polls for shutdown every poll_interval seconds. Ignores
        self.timeout. If you need to do periodic tasks, do them in
        another thread.
        """
        self.__is_shut_down.clear()
        try:
            while not self.__shutdown_request:

                r, w, e = _eintr_retry(select.select, [self], [], [],
                                       poll_interval)
                if self in r:
                    self._handle_request_noblock()
        finally:
            self.__shutdown_request = False
            self.__is_shut_down.set()

 

  
这里运用了select()函数,即server_forever接受了一个poll_interval=0.5的参数传入,那意味用于select轮询的时间,然后进入一个无限循环中,在那几个轮回中,select每隔poll_interval秒轮询三回(阻塞于此),以此来进展互连网IO的监听。一旦有新的网络连接请求到来,则会调用_handle_request_noblock()方法处理新的连年。


3.1.3 
_handle_request_noblock()**

    def _handle_request_noblock(self):
        """Handle one request, without blocking.

        I assume that select.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 socket.error:
            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)

 

英文表明已经说的很让人侧目,该措施处理的是一个非阻塞请求,首先通过get_request()方法得到连接,具体落到实处在其子类,一旦取得了连接,立即调用verify_request认证连接消息,通过认证,则调用process_request()方法处理请求,倘若中途现身谬误,则调用handle_error处理错误,同时,调用shutdown_request()方法截止那么些一连。

这上面大家就先看上面提到的别样多少个函数调用:

    def verify_request(self, request, client_address):
        """Verify the request.  May be overridden.

        Return True if we should proceed with this request.

        """
        return True


    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 handle_error(self, request, client_address):
        """Handle an error gracefully.  May be overridden.

        The default is to print a traceback and continue.

        """
        print '-'*40
        print 'Exception happened during processing of request from',
        print client_address
        import traceback
        traceback.print_exc() # XXX But this goes to stderr!
        print '-'*40


    def shutdown_request(self, request):
        """Called to shutdown and close an individual request."""
        self.close_request(request)<pre name="code" class="python">    

    def finish_request(self, request, client_address):
        """Finish one request by instantiating RequestHandlerClass."""
        self.RequestHandlerClass(request, client_address, self)

 

verify_request()方法对request举办求证,平时会被子类重写。

process_request要求留意一下,它被ForkingMixIn

ThreadingMixIn重写,因而是mixin的进口,ForkingMixIn和ThreadingMixIn分别开展多进程和多线程的布署,并且调用finish_request()落成请求,调用shutdown_request()停止请求。

handle_error也足以被子类重写,打印错误的新闻和客户端地址。

**finish_request()处理完结请求,在__init__中创造requestHandler对象,并透过requestHandler做出切实的拍卖。

3.1.4 handle_request()**

    def handle_request(self):
        """Handle one request, possibly blocking.

        Respects self.timeout.
        """
        # Support people who used socket.settimeout() to escape
        # handle_request before self.timeout was available.
        timeout = self.socket.gettimeout()
        if timeout is None:
            timeout = self.timeout
        elif self.timeout is not None:
            timeout = min(timeout, self.timeout)
        fd_sets = _eintr_retry(select.select, [self], [], [], timeout)
        if not fd_sets[0]:
            self.handle_timeout()
            return
        self._handle_request_noblock()

 

上面已经涉及,即便您未曾应用server_forever()方法,表明您期望选拔的是阻塞请求来拍卖连接,如英文描述所说,该方式只是处理一个打断的乞求,依旧拔取select()方法轮询来监听互连网连接,不过必要考虑时间超时影响,一旦过期,调用handle_timeout()方法处理超时,一般在子类重写该措施;即使在逾期事先监听到了网络的连年请求,则同server_forever一样,调用_handle_request_noblock()方法,达成对新的接连的呼吁处理。

3.2 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 arbitrary other instance variariables.

    """

    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

 

     
以上描述表达,所有requestHandler都一而再BaseRequestHandler基类,该类会处理每一个呼吁。在__init__中开端化实例变量request、client_address、server,然后调用handle()方法成功请求处理。那么,大家唯一需求做的就是重写好Handle()方法,处理所有的伸手。

 

统计:营造一个网络服务,须要一个BaseServer用于拍卖网络IO,同时在其间创制requestHandler对象,对具有具体的伸手做拍卖。

四、各个子类

4.1 由BaseServer衍生的子类

4.1.1 TCPServer

class TCPServer(BaseServer):
    address_family = socket.AF_INET

    socket_type = socket.SOCK_STREAM

    request_queue_size = 5

    allow_reuse_address = False

    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

    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()

    def server_activate(self):
        """Called by constructor to activate the server.

        May be overridden.

        """
        self.socket.listen(self.request_queue_size)

    def server_close(self):
        """Called to clean-up the server.

        May be overridden.

        """
        self.socket.close()

    def fileno(self):
        """Return socket file number.

        Interface required by select().

        """
        return self.socket.fileno()

    def get_request(self):
        """Get the request and client address from the socket.

        May be overridden.

        """
        return self.socket.accept()

    def shutdown_request(self, request):
        """Called to shutdown and close an individual request."""
        try:
            #explicitly shutdown.  socket.close() merely releases
            #the socket and waits for GC to perform the actual close.
            request.shutdown(socket.SHUT_WR)
        except socket.error:
            pass #some platforms may raise ENOTCONN here
        self.close_request(request)

    def close_request(self, request):
        """Called to clean up an individual request."""
        request.close()

 

 在BaseServer基础上扩充了一个TCP的socket连接,使用server_bind、server_activate、server_close处理TCP启停等操作,同时扩展了get_request、shutdown_request、close_request处理客户端请求。

4.1.2 UDPServer

class UDPServer(TCPServer):

    """UDP server class."""

    allow_reuse_address = False

    socket_type = socket.SOCK_DGRAM

    max_packet_size = 8192

    def get_request(self):
        data, client_addr = self.socket.recvfrom(self.max_packet_size)
        return (data, self.socket), client_addr

    def server_activate(self):
        # No need to call listen() for UDP.
        pass

    def shutdown_request(self, request):
        # No need to shutdown anything.
        self.close_request(request)

    def close_request(self, request):
        # No need to close anything.
        pass

 

继承自TCPServer,将socket改为了SOCK_DGRAM型,并修改了get_request,用于从SOCK_DGRAM中获取request。同时server_activate、shutdown_request、close_request都改成了空(UDP不须要),比TCP简单一些。

4.2
由BaseRequestHandler衍生的子类

4.2.1 StreamRequestHandler

class StreamRequestHandler(BaseRequestHandler):
    rbufsize = -1
    wbufsize = 0
    timeout = None
    disable_nagle_algorithm = False
    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)

    def finish(self):
        if not self.wfile.closed:
            try:
                self.wfile.flush()
            except socket.error:
                # An final socket error may have occurred here, such as
                # the local error ECONNABORTED.
                pass
        self.wfile.close()
        self.rfile.close()

 

   
最重点的职能是根据socket生成了读写socket用的多个公文对象(可以知道为句柄)rfile和wfile

4.2.2 DatagramRequestHandler

class DatagramRequestHandler(BaseRequestHandler):

    # XXX Regrettably, I cannot get this working on Linux;
    # s.recvfrom() doesn't return a meaningful client address.

    """Define self.rfile and self.wfile for datagram sockets."""

    def setup(self):
        try:
            from cStringIO import StringIO
        except ImportError:
            from StringIO import StringIO
        self.packet, self.socket = self.request
        self.rfile = StringIO(self.packet)
        self.wfile = StringIO()

    def finish(self):
        self.socket.sendto(self.wfile.getvalue(), self.client_address)

 

平等是生成rfile和wfile,但UDP不直接关系socket。那里的rfile是直接由从UDP中读取的数量变动的,wfile则是新建了一个StringIO,用于写多少。

(标题起的有点大,部分分析的糟糕,等之后再往祖坟上刨。。。。^-^)

参照博客:

            

**

 

**

**

 

 

 

 

 

Python的socket模块源码中的一些完成中央分析,pythonsocket

BaseServer 和 BaseRequestHandler Python为互连网编程升高了更高级的卷入。SocketServer.py
提供了不可胜言互连网服务的类。它们的规划很优雅。Python把互联网服务抽象成多个关键的类,一个是Server类,用于拍卖连接相关的互联网操作,其余一个则是RequestHandler类,用于拍卖数量相关的操作。并且提供多少个MixIn
类,用于扩大 Server,完成多进程或四线程。在创设网络服务的时候,Server 和
RequestHandler 并不是分其他,RequestHandler的实例对象在Server 内合作Server工作。

改模块的关键多少个Server关系如下:

    +------------+
    | BaseServer |
    +------------+
       |
       v
    +-----------+    +------------------+
    | TCPServer |------->| UnixStreamServer |
    +-----------+    +------------------+
       |
       v
    +-----------+    +--------------------+
    | UDPServer |------->| UnixDatagramServer |
    +-----------+    +--------------------+

BaseServer 分析 BaseServer 通过__init__伊始化,对外提供serve_forever和
handler_request方法。

init 初始化:

  def __init__(self, server_address, RequestHandlerClass):
    """Constructor. May be extended, do not override."""
    self.server_address = server_address
    self.RequestHandlerClass = RequestHandlerClass
    self.__is_shut_down = threading.Event()
    self.__shutdown_request = False

__init__源码很粗略。首要功效是创设server对象,并开始化server地址和拍卖请求的class。谙习socket编程应该很了解,server_address是一个包罗主机和端口的元组。

serve_forever 成立了server对象之后,就需求利用server对象开启一个最为循环,上边来分析serve_forever的源码。

  def serve_forever(self, poll_interval=0.5):
    self.__is_shut_down.clear()
    try:
      while not self.__shutdown_request:
        r, w, e = _eintr_retry(select.select, [self], [], [],
                    poll_interval)
        if self in r:
          self._handle_request_noblock()
    finally:
      self.__shutdown_request = False
      self.__is_shut_down.set()

serve_forever接受一个参数poll_interval,用于表示select轮询的年月。然后进入一个无比循环,调用select格局展开互连网IO的监听。

若果select函数重返,表示有IO连接或数额,那么将会调用_handle_request_noblock方法。

_handle_request_noblock
  def _handle_request_noblock(self):
    try:
      request, client_address = self.get_request()
    except socket.error:
      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)

_handle_request_noblock方法即起来拍卖一个呼吁,并且是非阻塞。该措施通过get_request方法取得连接,具体的兑现在其子类。一旦得到了连年,调用verify_request方法求证请求。验证通过,即调用process_request处理请求。即便中途出现错误,则调用handle_error处理错误,以及shutdown_request甘休两次三番。

verify_request
  def verify_request(self, request, client_address):
    return True

该形式对request举办验证,常常会被子类重写。简单的回到True即可,然后进入process_request方法处理请求。

process_request
  def process_request(self, request, client_address):
    self.finish_request(request, client_address)
    self.shutdown_request(request)

process_request方法是mixin的输入,MixIn子类通过重写该措施,举办十六线程或多进度的安插。调用finish_request达成请求的处理,同时调用shutdown_request截至请求。

finish_request
  def finish_request(self, request, client_address):
    self.RequestHandlerClass(request, client_address, self)

finish_request方法将会处理完成请求。创制requestHandler对象,并经过requestHandler抓实际的拍卖。

BaseRequestHandler 分析 所有requestHandler都继承BaseRequestHandler基类。

  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()

该类会处理每一个呼吁。初阶化对象的时候,设置请求request对象。然后调用setup方法,子类会重写该格局,用于拍卖socket连接。接下来的将是handler和finish方法。所有对请求的处理,都得以重写handler方法。

从那之后,整个Python提供的Server情势即介绍已毕。计算一下,打造一个互连网服务,须要一个BaseServer用于拍卖互联网IO,同时在中间创制requestHandler对象,对具有具体的央浼做拍卖。

BaseServer – BaseRequestHandler

__init__(server_address, RequestHandlerClass): 
  BaseServer.server_address
  BaseServer.RequestHandlerClass

serve_forever(): 

  select() 

  BaseServer._handle_request_noblock()

    BaseServer.get_request() -> request, client_addres

    BaseServer.verify_request()

      BaseServer.process_request()

        BaseServer.process_request()

          BaseServer.finish_request()

            BaseServer.RequestHandlerClass()

              BaseRequestHandler.__init__(request)

                BaseRequestHandler.request
                BaseRequestHandler.client_address = client_address

                BaseRequestHandler.setup()

                BaseRequestHandler.handle()

          BaseServer.shutdown_request()

            BaseServer.close_request()

      BaseServer.shutdown_request()

        BaseServer.close_request()

BaseServer 和
BaseRequestHandler是互联网拍卖的五个基类。实际利用中,网络操作越多是利用
TCP 或 HTTP 协议。SocketServer.py
也提供了更高级的TCP、UDP封装。上边就来看下关于TCP方面的互联网模块(UDP和TCP的在代码协会上差异不是专程大,暂且忽略)。

TCPServer TCPServer 继承了BaseServer,初步化的时候,举办了socket套接字的创造。

def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
  BaseServer.__init__(self, server_address, RequestHandlerClass)
  self.socket = socket.socket(self.address_family,
                self.socket_type)
  if bind_and_activate:
    self.server_bind()
    self.server_activate()

__init__ 方法通过
socket模块创制了socket对象,然后开展调用server_bind和server_activate。

server_bind
def server_bind(self):
  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()

server_bind
方法开展socket对象的bind操作,以及安装socket相关属性,如网络地址的复用。

server_activate
def server_activate(self):
  self.socket.listen(self.request_queue_size)

server_activate 方法也相比简单,添加socket对象的listen。

get_request 此类最关键的不二法门就是
get_request。该措施举办重回socket对象的请求连接。

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

get_request方法是在BaseServer基类中的_handle_request_noblock中调用,从那边里传到套接字对象得到的连年音信。借使是UDPServer,那里得到的就是UDP连接。

其余,TCPServer还提供了一个 fileno
方法,提必要基类的select调用重返文件讲述符。

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)

setup判断了是还是不是使用nagle算法。然后设置相应的连天属性。最关键的就是成立了一个可读(rfile)和一个可写(wfile)的“文件”对象,他们实在并不是成立了文件,而是包装了读取数据和发送数据的操作,抽象成为对文本的操作。可以清楚为
self.rfile
就是读取客户端数据的目的,它有一部分主意可以读取数据。self.wfile则是用来发送数据给客户端的对象。前边的操作,客户端数据到来会被写入缓冲区可读,需求向客户端发送数据的时候,只需求向可写的文书中write数据即可。

心想事成TCP服务要求选取TCPServer和StreamRequestHandler共同同盟。大致函数调用流程如下,函数调用用括号表示,赋值不带括号,没有类前缀的象征系统调用:

TCPServer – StreamRequestHandler

__init__(server_address, RequestHandlerClass): 
  BaseServer.server_address
  BaseServer.RequestHandlerClass

  TCPServer.socket = socket.socket(self.address_family, self.socket_type)
  TCPServer.server_bind()
  TCPServer.server_activate()

serve_forever(): 

  select() 

  BaseServer._handle_request_noblock()

    TCPServer.get_request() -> request, client_addres
      socket.accept()

    BaseServer.verify_request()

      BaseServer.process_request()

        BaseServer.process_request()

          BaseServer.finish_request(request, client_address)

            BaseServer.RequestHandlerClass()

              BaseRequestHandler.__init__(request)

                BaseRequestHandler.request
                BaseRequestHandler.client_address = client_address

                StreamRequestHandler.setup()

                  StreamRequestHandler.connection = StreamRequestHandler.request
                  StreamRequestHandler.rfile
                  StreamRequestHandler.wfile

                BaseRequestHandler.handle()

                StreamRequestHandler.finsih()
                  StreamRequestHandler.wfile.close()
                  StreamRequestHandler.rfile.close()

          BaseServer.shutdown_request(request)
            TCPServer.shutdown()
              request.shutdown()
            TCPServer.close_request(request)
              request.close()

      TCPServer.shutdown_request(request)
        TCPServer.shutdown(request)
          request.shutdown()
        TCPServer.close_request(request)
          request.close()

最早关于介绍BaseServer的时候,大家领略python对BaseServer设计的时候,预留了可用于Mixin伸张八线程或多进程的接口。mixin通过复写父类的parse_request方法完结。

ThreadingMixIn ThreadingMixIn
类落成了多线程的办法,它只有五个点子,分别是process_request和
process_request_thread方法。多进度的法门是ForkingMixIn,暂且略过。

process_request
def process_request(self, request, client_address):
  t = threading.Thread(target = self.process_request_thread,
             args = (request, client_address))
  t.daemon = self.daemon_threads
  t.start()

process_request方法复写了父类的此格局。以此为接口入口,对每一个请求,调用Thread开启一个新的线程。每一个线程都绑定process_request_thread方法。

process_request_thread
  def process_request_thread(self, request, client_address):
    try:
      self.finish_request(request, client_address)
      self.shutdown_request(request)
    except:
      self.handle_error(request, client_address)
      self.shutdown_request(request)

process_request_thread方法和BaseServer里的parse_request大概一样。只然而是三三十二线程的办法调用。

行使的时候,通过多接二连三调用接口,例如:

class ThreadingTCPServer(ThreadingMixIn, TCPServer): 
  pass

切实的调用进程如下:

ThreadingMixIn -- TCPServer - StreamRequestHandler

__init__(server_address, RequestHandlerClass): 
  BaseServer.server_address
  BaseServer.RequestHandlerClass

  TCPServer.socket = socket.socket(self.address_family, self.socket_type)
  TCPServer.server_bind()
  TCPServer.server_activate()

serve_forever(): 

  select() 

  BaseServer._handle_request_noblock()

    TCPServer.get_request() -> request, client_addres
      socket.accept()

    BaseServer.verify_request()

      BaseServer.process_request()

        ThreadingMixIn.process_request()
          t = threading.Thread(target = ThreadingMixIn.process_request_thread)

          ThreadingMixIn.process_request_thread

            BaseServer.finish_request(request, client_address)

              BaseServer.RequestHandlerClass()

                BaseRequestHandler.__init__(request)

                  BaseRequestHandler.request
                  BaseRequestHandler.client_address = client_address

                  StreamRequestHandler.setup()

                    StreamRequestHandler.connection = StreamRequestHandler.request
                    StreamRequestHandler.rfile
                    StreamRequestHandler.wfile

                  BaseRequestHandler.handle()

                  StreamRequestHandler.finsih()
                    StreamRequestHandler.wfile.close()
                    StreamRequestHandler.rfile.close()

            BaseServer.shutdown_request(request)
              TCPServer.shutdown()
                request.shutdown()
              TCPServer.close_request(request)
                request.close()

      TCPServer.shutdown_request(request)
        TCPServer.shutdown(request)
          request.shutdown()
        TCPServer.close_request(request)
          request.close()

BaseServer 和 BaseRequestHandler
Python为互连网编程提升了更高级的卷入。SocketServer.py 提供了…

Python提供了SocketServer用于创设网络服务器。

服务器类型

SocketServer中定义了多少个例外的劳务器类,它们中间的关联如下:

        +------------+
        | BaseServer |
        +------------+
              |
              v
        +-----------+        +------------------+
        | TCPServer |------->| UnixStreamServer |
        +-----------+        +------------------+
              |
              v
        +-----------+        +--------------------+
        | UDPServer |------->| UnixDatagramServer |
        +-----------+        +--------------------+

BaseServer是基类,它无法实例化使用,TCPServer使用TCP协议通讯,UDPServer使用UDP磋商通讯,UnixStreamServer和UnixDatagramServer使用Unix域套接字,只适用于UNIX平台。

始建服务器流程

创造服务器的步子。首先,你无法不创设一个呼吁处理类,它是BaseRequestHandler的子类人己一视载其handle()方法。其次,你不可以不实例化一个劳动器类,传入服务器的地址和呼吁处理程序类。最终,调用handle_request()或serve_forever()。

BaseServer还提供了此外一些办法,我们能够重载那么些主意以落到实处特定功效:

  • verify_request(request,
    client_address)
    :再次回到一个布尔值,如果该值为True
    ,则该请求将被处理,反之请求将被驳回。此功能可以重写来完成对服务器的访问控制。默许的兑现始终再次回到True。client_address可以界定客户端,比如只处理指定ip区间的伸手,常用。
  • *process_request(request, client_address)
    *:调用finish_request()创设RequestHandlerClass的实例。即使须求,此作用可以创造新的长河或线程来处理请求,ForkingMixIn和ThreadingMixIn类做到这一点,常用。
  • 实际上处理RequestHandlerClass发起的呼吁并调用其handle()方法, 常用。

伸手处理器

电脑接收数据并控制如何操作。它负责在socket层之上已毕协议(i.e., HTTP,
XML-RPC, or AMQP),读取数据,处理并写反应。可以重载的主意如下:

  • setup(): 准备呼吁处理.
    默许什么都不做,StreamRequestHandler中会成立文件类似的靶子以读写socket.
  • handle():
    处理请求。解析传入的呼吁,处理数量,并发送响应。默许什么都不做。常用变量:self.request,self.client_address,self.server。
  • finish():
    环境清理。默许什么都不做,假设setup爆发极度,不会履行finish。

一般性只需求重载handle。

self.request的品种和数码报或流的劳动分化。

对此流服务,self.request是socket
对象;对于数据报服务,self.request是字符串和socket 。

可以在子类StreamRequestHandler或DatagramRequestHandler中重载,重写setup()和finish()
,并提供self.rfile和self.wfile属性。

self.rfile和self.wfile可以读取或写入,以取得请求数据或将数据再次回到到客户端。

实例

下边完结一个简约的带日志作用的Echo服务器,它接受TCP连接,然后响应客户端发送哦所有多少:

import sys
import logging
import SocketServer

logging.basicConfig(level=logging.DEBUG, format="%(name)s:%(message)s")

# 请求处理器类
class EchoRequestHandler(SocketServer.BaseRequestHandler):

    def __init__(self, request, client_address, server):
        self.logger = logging.getLogger("EchoRequestHandler")
        self.logger.debug("__init__")
        SocketServer.BaseRequestHandler.__init__(self, request,client_address, server)
        return

    def setup(self):
        self.logger.debug("setup")
        return SocketServer.BaseRequestHandler.setup(self)

    def handle(self):
        self.logger.debug("handle")
        data = self.request.recv(1024)
        self.request.send(data)
        return

    def finish(self):
        self.logger.debug("finish")
        return SocketServer.BaseRequestHandler.finish(self)

# 服务器类
class EchoServer(SocketServer.TCPServer):
    def __init__(self, server_address, handler_class=EchoRequestHandler):
        self.logger = logging.getLogger("EchoServer")
        self.logger.debug("__init__")
        SocketServer.TCPServer.__init__(self, server_address, handler_class)
        return

    def server_activate(self):
        self.logger.debug("server activate")
        SocketServer.TCPServer.server_activate(self)
        return

    def serve_forever(self, poll_interval=0.5):
        self.logger.debug("waiting for request")
        self.logger.info("Handling requests, press <Ctrl-C> to quit")
        SocketServer.TCPServer.serve_forever(self, poll_interval)
        return

    def handle_request(self, request, client_address):
        self.logger.debug("verify_request %s, %s",request, client_address)
        return SocketServer.TCPServer.verify_request(request, client_address)

    def process_request(self, request, client_address):
        self.logger.debug("process request %s, %s", request, client_address)
        return SocketServer.TCPServer.process_request(self, request, client_address)

    def server_close(self):
        self.logger.debug("server close")
        return SocketServer.TCPServer.server_close(self)

    def finish_request(self, request, client_address):
        self.logger.debug("finish request %s, %s", request, client_address)
        return SocketServer.TCPServer.finish_request(self, request, client_address)

    def close_request(self, request_address):
        self.logger.debug("close request %s", request_address)
        return SocketServer.TCPServer.close_request(self, request_address)

    def shutdown(self):
        self.logger.debug("shutdown")
        return SocketServer.TCPServer.shutdown(self)

# 程序入口
if __name__ == "__main__":
    import socket
    import threading
    address = ("localhost", 0)
    server = EchoServer(address, EchoRequestHandler)
    ip, port = server.server_address
    t = threading.Thread(target=server.serve_forever)
    t.setDaemon(True)
    t.start()

    logger = logging.getLogger("client")
    logger.debug("Server on %s:%s", ip, port)

    logger.debug("creating socket")
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    logger.debug("connecting to server")
    s.connect((ip, port))
    message  = "Hello, world"
    logger.debug("sending data: %s", message)
    len_sent = s.send(message)

    logger.debug("waiting for response")
    response = s.recv(len_sent)
    logger.debug("response from server %s", response)

    server.shutdown()
    logger.debug("closing socket")
    s.close()
    logger.debug("done")
    server.socket.close()

运作代码,输出以下结果:

EchoServer:__init__
EchoServer:server activate
EchoServer:waiting for request
EchoServer:Handling requests, press <Ctrl-C> to quit
client:Server on 127.0.0.1:63245
client:creating socket
client:connecting to server
client:sending data: Hello, world
client:waiting for response
EchoServer:process request <socket._socketobject object at 0x026FD6C0>, ('127.0.0.1', 63246)
EchoServer:finish request <socket._socketobject object at 0x026FD6C0>, ('127.0.0.1', 63246)
EchoRequestHandler:__init__
EchoRequestHandler:setup
EchoRequestHandler:handle
EchoRequestHandler:finish
EchoServer:close request <socket._socketobject object at 0x026FD6C0>
client:response from server Hello, world
EchoServer:shutdown
client:closing socket

线程和进程

TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer。那4个类是同步进行处理的,其它通过ForkingMixIn和ThreadingMixIn类来接济异步,那五个类重载了process_request()方法,当准备
处理一个伸手时,就开端一个新的长河或者线程,从而把现实做事放到进度或者线程中运行。

对此线程,须要动用ThreadingMiXin:

import threading
import socket
import SocketServer

class ThreadEchoRequestHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        data = self.request.recv(1024)
        cur_thread = threading.currentThread()
        response = "%s:%s" % (cur_thread.getName(), data)
        print "ok" , response
        self.request.send(response)
        return

class ThreadEchoServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    pass


if __name__ == "__main__":
    address = ("localhost", 0)
    server = ThreadEchoServer(address, ThreadEchoRequestHandler)
    ip, port = server.server_address
    t = threading.Thread(target=server.serve_forever)
    t.setDaemon(True)
    t.start()
    print "Server loop running in thread: ", t.getName()

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((ip, port))
    message  = "Hello, world"
    len_sent = s.send(message)

    response = s.recv(1024)
    print "Received:%s" % response

    s.close()
    server.socket.close()

运作结果如下:

Server loop running in thread:  Thread-1
ok Thread-2:Hello, world
Received:Thread-2:Hello, world

对此不相同进度,则选取ForkingMixIn:

import os
import SocketServer

class ForkingEchoRequestHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        # Echo the back to the client
        data = self.request.recv(1024)
        cur_pid = os.getpid()
        response = '%s: %s' % (cur_pid, data)
        self.request.send(response)
        return

class ForkingEchoServer(SocketServer.ForkingMixIn, SocketServer.TCPServer):
    pass

if __name__ == '__main__':
    import socket
    import threading

    address = ('localhost', 0) # let the kernel give us a port
    server = ForkingEchoServer(address, ForkingEchoRequestHandler)
    ip, port = server.server_address # find out what port we were given

    t = threading.Thread(target=server.serve_forever)
    t.setDaemon(True) # don't hang on exit
    t.start()
    print 'Server loop running in process:', os.getpid()

    # Connect to the server
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((ip, port))

    # Send the data
    message = 'Hello, world'
    print 'Sending : "%s"' % message
    len_sent = s.send(message)

    # Receive a response
    response = s.recv(1024)
    print 'Received: "%s"' % response

    # Clean up
    s.close()
    server.socket.close()

运作结果如下:

Server loop running in process: 96038
Sending : "Hello, world"
Received: "96040: Hello, world"

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图