深入解析SocketServer模块,Python的socket模块源码中的一些贯彻中央分析

一、简介(翻译)

 

 通用socket server 类

 该模块尽力从各类不相同的地方定义server:

 对于socket-based servers:
 — address family:
    – AF_INET{,6}: IP socket (default)
    – AF_UNIX: Unix domain sockets
    – others, 如 AF_DECNET (见<socket.h>) (不常用)
深入解析SocketServer模块,Python的socket模块源码中的一些贯彻中央分析。 — socket type:
    – SOCK_STREAM (可相信一连 TCP)
    – SOCK_DGRAM (UDP)
 
 对于request-based servers:
— client
address在爆发进一步的呼吁在此之前须求表达(那实在把富有须求发出请求的长河在通过验证此前给阻塞住了)
— 怎么着处理多请求:
   – 同步 (一次只可以处理2个伸手)
   – forking (fork一个新的经过来处理2个伸手)
   – threading (创造贰个新的线程来拍卖3个伸手)
 
   在那么些模块的各体系中,最简易的服务器类型正是synchronous TCP/IP
server。那是一个倒霉的类设计,不过也保留了有的统一筹划的项目理念。

下边是四个类的继续关系图表,当中的七个代表种种档次的3只服务器:
        +————–+
        | 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把互联网服务抽象成多个第2的类,三个是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轮询的时间,然后进入3个极致循环中,在这么些轮回中,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)

 

英文表达已经说的很引人侧目,该办法处理的是3个非阻塞请求,首先通过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()方法,处理全体的央浼。

 

总括:营造3个网络服务,须求三个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则是新建了3个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在发生进一步的央求以前要求证实(那实在把具有须求发出请求的历程在通过验证以前给阻塞住了)
— 怎样处理多请求:
   – 同步 (贰回只可以处理3个呼吁)
   – forking (fork贰个新的进程来拍卖二个呼吁)
   – threading (创立1个新的线程来拍卖二个呼吁)
 
   在那几个模块的各类别中,最简易的服务器类型正是synchronous TCP/IP
server。那是3个不佳的类设计,然而也保留了一些企划的类型理念。

上边是四个类的接轨关系图表,在这之中的多少个代表种种档次的1头服务器:
        +————–+
        | 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()方法来判断哪些请求应该在接下去做出响应(也许判断是或不是要拍卖新到来的请求),当每2个客户端供给树立非常短日子的连日时,那对于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基类,该类会处理每1个请求。在__init__中开首化实例变量request、client_address、server,然后调用handle()方法成功请求处理。那么,大家唯一须求做的正是重写好Handle()方法,处理全体的伸手。

 

小结:创设3个互连网服务,须要3个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把互联网服务抽象成多少个重大的类,3个是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接受3个参数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()

此类会处理每3个伸手。早先化对象的时候,设置请求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)和3个可写(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开启多个新的线程。每2个线程都绑定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()方法。其次,你必须实例化1个服务器类,传入服务器的地方和伸手处理程序类。最后,调用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。那6个类是同步实行处理的,别的通过ForkingMixIn和ThreadingMixIn类来支撑异步,那一个类重载了process_request()方法,当准备
处理二个呼吁时,就从头1个新的历程也许线程,从而把实际做事置于进度只怕线程中运作。

对于线程,须要使用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地图