<span style="color: #0000ff;">import</span><span style="color: #000000;"> socket
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> select
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> sys
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> os
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> errno
</span><span style="color: #0000ff;">try</span><span style="color: #000000;">:
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> threading
</span><span style="color: #0000ff;">except</span><span style="color: #000000;"> ImportError:
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> dummy_threading as threading
</span><span style="color: #800080;">__all__</span> = [<span style="color: #800000;">"</span><span style="color: #800000;">TCPServer</span><span style="color: #800000;">"</span>,<span style="color: #800000;">"</span><span style="color: #800000;">UDPServer</span><span style="color: #800000;">"</span>,<span style="color: #800000;">"</span><span style="color: #800000;">ForkingUDPServer</span><span style="color: #800000;">"</span>,<span style="color: #800000;">"</span><span style="color: #800000;">ForkingTCPServer</span><span style="color: #800000;">"</span><span style="color: #000000;">,
</span><span style="color: #800000;">"</span><span style="color: #800000;">ThreadingUDPServer</span><span style="color: #800000;">"</span>,<span style="color: #800000;">"</span><span style="color: #800000;">ThreadingTCPServer</span><span style="color: #800000;">"</span>,<span style="color: #800000;">"</span><span style="color: #800000;">BaseRequestHandler</span><span style="color: #800000;">"</span><span style="color: #000000;">,
</span><span style="color: #800000;">"</span><span style="color: #800000;">StreamRequestHandler</span><span style="color: #800000;">"</span>,<span style="color: #800000;">"</span><span style="color: #800000;">DatagramRequestHandler</span><span style="color: #800000;">"</span><span style="color: #000000;">,
</span><span style="color: #800000;">"</span><span style="color: #800000;">ThreadingMixIn</span><span style="color: #800000;">"</span>, <span style="color: #800000;">"</span><span style="color: #800000;">ForkingMixIn</span><span style="color: #800000;">"</span><span style="color: #000000;">]
</span><span style="color: #0000ff;">if</span> hasattr(socket, <span style="color: #800000;">"</span><span style="color: #800000;">AF_UNIX</span><span style="color: #800000;">"</span><span style="color: #000000;">):
</span><span style="color: #800080;">__all__</span>.extend([<span style="color: #800000;">"</span><span style="color: #800000;">UnixStreamServer</span><span style="color: #800000;">"</span>,<span style="color: #800000;">"</span><span style="color: #800000;">UnixDatagramServer</span><span style="color: #800000;">"</span><span style="color: #000000;">,
</span><span style="color: #800000;">"</span><span style="color: #800000;">ThreadingUnixStreamServer</span><span style="color: #800000;">"</span><span style="color: #000000;">,
</span><span style="color: #800000;">"</span><span style="color: #800000;">ThreadingUnixDatagramServer</span><span style="color: #800000;">"</span>])
立即学习“Python免费学习笔记(深入)”;
timeout =<span style="color: #000000;"> None
</span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span><span style="color: #000000;">(self, server_address, RequestHandlerClass):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Constructor. May be extended, do not override.</span><span style="color: #800000;">"""</span><span style="color: #000000;">
self.server_address </span>=<span style="color: #000000;"> server_address
self.RequestHandlerClass </span>=<span style="color: #000000;"> RequestHandlerClass
self.</span><span style="color: #800080;">__is_shut_down</span> =<span style="color: #000000;"> threading.Event()
self.</span><span style="color: #800080;">__shutdown_request</span> = False
立即学习“Python免费学习笔记(深入)”;
<span style="color: #0000ff;">def</span> serve_forever(self, poll_interval=0.5<span style="color: #000000;">):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">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.
</span><span style="color: #800000;">"""</span><span style="color: #000000;">
self.</span><span style="color: #800080;">__is_shut_down</span><span style="color: #000000;">.clear()
</span><span style="color: #0000ff;">try</span><span style="color: #000000;">:
</span><span style="color: #0000ff;">while</span> <span style="color: #0000ff;">not</span> self.<span style="color: #800080;">__shutdown_request</span><span style="color: #000000;">:
r, w, e </span>=<span style="color: #000000;"> _eintr_retry(select.select, [self], [], [],
poll_interval)
</span><span style="color: #0000ff;">if</span> self <span style="color: #0000ff;">in</span><span style="color: #000000;"> r:
self._handle_request_noblock()
</span><span style="color: #0000ff;">finally</span><span style="color: #000000;">:
self.</span><span style="color: #800080;">__shutdown_request</span> =<span style="color: #000000;"> False
self.</span><span style="color: #800080;">__is_shut_down</span>.set()
立即学习“Python免费学习笔记(深入)”;
这里用到了select()函数,即server_forever接受了一个poll_interval=0.5的参数传入,这表示用于select轮询的时间,然后进入一个无限循环中,在这个循环中,select每隔poll_interval秒轮询一次(阻塞于此),以此来进行网络IO的监听。一旦有新的网络连接请求到来,则会调用_handle_request_noblock()方法处理新的连接。 <span style="color: #0000ff;">def</span><span style="color: #000000;"> _handle_request_noblock(self):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">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().
</span><span style="color: #800000;">"""</span>
<span style="color: #0000ff;">try</span><span style="color: #000000;">:
request, client_address </span>=<span style="color: #000000;"> self.get_request()
</span><span style="color: #0000ff;">except</span><span style="color: #000000;"> socket.error:
</span><span style="color: #0000ff;">return</span>
<span style="color: #0000ff;">if</span><span style="color: #000000;"> self.verify_request(request, client_address):
</span><span style="color: #0000ff;">try</span><span style="color: #000000;">:
self.process_request(request, client_address)
</span><span style="color: #0000ff;">except</span><span style="color: #000000;">:
self.handle_error(request, client_address)
self.shutdown_request(request)</span>
立即学习“Python免费学习笔记(深入)”;
英文说明已经说的很明确,该方法处理的是一个非阻塞请求,首先通过get_request()方法获取连接,具体实现在其子类,一旦获取了连接,立即调用verify_request认证连接信息,通过认证,则调用process_request()方法处理请求,如果中途出现错误,则调用handle_error处理错误,同时,调用shutdown_request()方法结束这个连接。 <span style="color: #0000ff;">def</span><span style="color: #000000;"> verify_request(self, request, client_address):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Verify the request. May be overridden.
Return True if we should proceed with this request.
</span><span style="color: #800000;">"""</span>
<span style="color: #0000ff;">return</span><span style="color: #000000;"> True
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> process_request(self, request, client_address):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Call finish_request.
Overridden by ForkingMixIn and ThreadingMixIn.
</span><span style="color: #800000;">"""</span><span style="color: #000000;">
self.finish_request(request, client_address)
self.shutdown_request(request)
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> handle_error(self, request, client_address):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Handle an error gracefully. May be overridden.
The default is to print a traceback and continue.
</span><span style="color: #800000;">"""</span>
<span style="color: #0000ff;">print</span> <span style="color: #800000;">'</span><span style="color: #800000;">-</span><span style="color: #800000;">'</span>*40
<span style="color: #0000ff;">print</span> <span style="color: #800000;">'</span><span style="color: #800000;">Exception happened during processing of request from</span><span style="color: #800000;">'</span><span style="color: #000000;">,
</span><span style="color: #0000ff;">print</span><span style="color: #000000;"> client_address
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> traceback
traceback.print_exc() </span><span style="color: #008000;">#</span><span style="color: #008000;"> XXX But this goes to stderr!</span>
<span style="color: #0000ff;">print</span> <span style="color: #800000;">'</span><span style="color: #800000;">-</span><span style="color: #800000;">'</span>*40
<span style="color: #0000ff;">def</span><span style="color: #000000;"> shutdown_request(self, request):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Called to shutdown and close an individual request.</span><span style="color: #800000;">"""</span><span style="color: #000000;">
self.close_request(request)</span><pre class="brush:php;toolbar:false;" name=<span style="color: #800000;">"</span><span style="color: #800000;">code</span><span style="color: #800000;">"</span> <span style="color: #0000ff;">class</span>=<span style="color: #800000;">"</span><span style="color: #800000;">python</span><span style="color: #800000;">"</span>>
<span style="color: #0000ff;">def</span><span style="color: #000000;"> finish_request(self, request, client_address):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Finish one request by instantiating RequestHandlerClass.</span><span style="color: #800000;">"""</span><span style="color: #000000;">
self.RequestHandlerClass(request, client_address, self)</span>
立即学习“Python免费学习笔记(深入)”;
<span style="color: #0000ff;">def</span><span style="color: #000000;"> handle_request(self):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Handle one request, possibly blocking.
Respects self.timeout.
</span><span style="color: #800000;">"""</span>
<span style="color: #008000;">#</span><span style="color: #008000;"> Support people who used socket.settimeout() to escape</span>
<span style="color: #008000;">#</span><span style="color: #008000;"> handle_request before self.timeout was available.</span>
timeout =<span style="color: #000000;"> self.socket.gettimeout()
</span><span style="color: #0000ff;">if</span> timeout <span style="color: #0000ff;">is</span><span style="color: #000000;"> None:
timeout </span>=<span style="color: #000000;"> self.timeout
</span><span style="color: #0000ff;">elif</span> self.timeout <span style="color: #0000ff;">is</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> None:
timeout </span>=<span style="color: #000000;"> min(timeout, self.timeout)
fd_sets </span>=<span style="color: #000000;"> _eintr_retry(select.select, [self], [], [], timeout)
</span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> fd_sets[0]:
self.handle_timeout()
</span><span style="color: #0000ff;">return</span><span style="color: #000000;">
self._handle_request_noblock()</span>
立即学习“Python免费学习笔记(深入)”;
上面已经提到,如果你没有用到server_forever()方法,说明你希望使用的是阻塞请求来处理连接,如英文描述所说,该方法只是处理一个阻塞的请求,仍然使用select()方法轮询来监听网络连接,但是需要考虑时间超时影响,一旦超时,调用handle_timeout()方法处理超时,一般在子类重写该方法;如果在超时之前监听到了网络的连接请求,则同server_forever一样,调用_handle_request_noblock()方法,完成对新的连接的请求处理。<span style="color: #0000ff;">class</span><span style="color: #000000;"> BaseRequestHandler:
</span><span style="color: #800000;">"""</span><span style="color: #800000;">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.
</span><span style="color: #800000;">"""</span>
<span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span><span style="color: #000000;">(self, request, client_address, server):
self.request </span>=<span style="color: #000000;"> request
self.client_address </span>=<span style="color: #000000;"> client_address
self.server </span>=<span style="color: #000000;"> server
self.setup()
</span><span style="color: #0000ff;">try</span><span style="color: #000000;">:
self.handle()
</span><span style="color: #0000ff;">finally</span><span style="color: #000000;">:
self.finish()
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> setup(self):
</span><span style="color: #0000ff;">pass</span>
<span style="color: #0000ff;">def</span><span style="color: #000000;"> handle(self):
</span><span style="color: #0000ff;">pass</span>
<span style="color: #0000ff;">def</span><span style="color: #000000;"> finish(self):
</span><span style="color: #0000ff;">pass</span>
立即学习“Python免费学习笔记(深入)”;
以上描述说明,所有requestHandler都继承BaseRequestHandler基类,该类会处理每一个请求。在__init__中初始化实例变量request、client_address、server,然后调用handle()方法完成请求处理。那么,我们唯一需要做的就是重写好Handle()方法,处理所有的请求。<span style="color: #0000ff;">class</span><span style="color: #000000;"> TCPServer(BaseServer):
address_family </span>=<span style="color: #000000;"> socket.AF_INET
socket_type </span>=<span style="color: #000000;"> socket.SOCK_STREAM
request_queue_size </span>= 5<span style="color: #000000;">
allow_reuse_address </span>=<span style="color: #000000;"> False
</span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span>(self, server_address, RequestHandlerClass, bind_and_activate=<span style="color: #000000;">True):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Constructor. May be extended, do not override.</span><span style="color: #800000;">"""</span><span style="color: #000000;">
BaseServer.</span><span style="color: #800080;">__init__</span><span style="color: #000000;">(self, server_address, RequestHandlerClass)
self.socket </span>=<span style="color: #000000;"> socket.socket(self.address_family,
self.socket_type)
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> bind_and_activate:
</span><span style="color: #0000ff;">try</span><span style="color: #000000;">:
self.server_bind()
self.server_activate()
</span><span style="color: #0000ff;">except</span><span style="color: #000000;">:
self.server_close()
</span><span style="color: #0000ff;">raise</span>
<span style="color: #0000ff;">def</span><span style="color: #000000;"> server_bind(self):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Called by constructor to bind the socket.
May be overridden.
</span><span style="color: #800000;">"""</span>
<span style="color: #0000ff;">if</span><span style="color: #000000;"> self.allow_reuse_address:
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, </span>1<span style="color: #000000;">)
self.socket.bind(self.server_address)
self.server_address </span>=<span style="color: #000000;"> self.socket.getsockname()
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> server_activate(self):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Called by constructor to activate the server.
May be overridden.
</span><span style="color: #800000;">"""</span><span style="color: #000000;">
self.socket.listen(self.request_queue_size)
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> server_close(self):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Called to clean-up the server.
May be overridden.
</span><span style="color: #800000;">"""</span><span style="color: #000000;">
self.socket.close()
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> fileno(self):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Return socket file number.
Interface required by select().
</span><span style="color: #800000;">"""</span>
<span style="color: #0000ff;">return</span><span style="color: #000000;"> self.socket.fileno()
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> get_request(self):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Get the request and client address from the socket.
May be overridden.
</span><span style="color: #800000;">"""</span>
<span style="color: #0000ff;">return</span><span style="color: #000000;"> self.socket.accept()
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> shutdown_request(self, request):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Called to shutdown and close an individual request.</span><span style="color: #800000;">"""</span>
<span style="color: #0000ff;">try</span><span style="color: #000000;">:
</span><span style="color: #008000;">#</span><span style="color: #008000;">explicitly shutdown. socket.close() merely releases</span>
<span style="color: #008000;">#</span><span style="color: #008000;">the socket and waits for GC to perform the actual close.</span>
<span style="color: #000000;"> request.shutdown(socket.SHUT_WR)
</span><span style="color: #0000ff;">except</span><span style="color: #000000;"> socket.error:
</span><span style="color: #0000ff;">pass</span> <span style="color: #008000;">#</span><span style="color: #008000;">some platforms may raise ENOTCONN here</span>
<span style="color: #000000;"> self.close_request(request)
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> close_request(self, request):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">Called to clean up an individual request.</span><span style="color: #800000;">"""</span><span style="color: #000000;">
request.close()</span>
立即学习“Python免费学习笔记(深入)”;
<span style="color: #0000ff;">class</span><span style="color: #000000;"> UDPServer(TCPServer):
</span><span style="color: #800000;">"""</span><span style="color: #800000;">UDP server class.</span><span style="color: #800000;">"""</span><span style="color: #000000;">
allow_reuse_address </span>=<span style="color: #000000;"> False
socket_type </span>=<span style="color: #000000;"> socket.SOCK_DGRAM
max_packet_size </span>= 8192
<span style="color: #0000ff;">def</span><span style="color: #000000;"> get_request(self):
data, client_addr </span>=<span style="color: #000000;"> self.socket.recvfrom(self.max_packet_size)
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> (data, self.socket), client_addr
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> server_activate(self):
</span><span style="color: #008000;">#</span><span style="color: #008000;"> No need to call listen() for UDP.</span>
<span style="color: #0000ff;">pass</span>
<span style="color: #0000ff;">def</span><span style="color: #000000;"> shutdown_request(self, request):
</span><span style="color: #008000;">#</span><span style="color: #008000;"> No need to shutdown anything.</span>
<span style="color: #000000;"> self.close_request(request)
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> close_request(self, request):
</span><span style="color: #008000;">#</span><span style="color: #008000;"> No need to close anything.</span>
<span style="color: #0000ff;">pass</span>
立即学习“Python免费学习笔记(深入)”;
继承自TCPServer,将socket改为了SOCK_DGRAM型,并修改了get_request,用于从SOCK_DGRAM中获取request。同时server_activate、shutdown_request、close_request都改成了空(UDP不需要),比TCP简单一些。<span style="color: #0000ff;">class</span><span style="color: #000000;"> StreamRequestHandler(BaseRequestHandler):
rbufsize </span>= -1<span style="color: #000000;">
wbufsize </span>=<span style="color: #000000;"> 0
timeout </span>=<span style="color: #000000;"> None
disable_nagle_algorithm </span>=<span style="color: #000000;"> False
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> setup(self):
self.connection </span>=<span style="color: #000000;"> self.request
</span><span style="color: #0000ff;">if</span> self.timeout <span style="color: #0000ff;">is</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> None:
self.connection.settimeout(self.timeout)
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> self.disable_nagle_algorithm:
self.connection.setsockopt(socket.IPPROTO_TCP,
socket.TCP_NODELAY, True)
self.rfile </span>= self.connection.makefile(<span style="color: #800000;">'</span><span style="color: #800000;">rb</span><span style="color: #800000;">'</span><span style="color: #000000;">, self.rbufsize)
self.wfile </span>= self.connection.makefile(<span style="color: #800000;">'</span><span style="color: #800000;">wb</span><span style="color: #800000;">'</span><span style="color: #000000;">, self.wbufsize)
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> finish(self):
</span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> self.wfile.closed:
</span><span style="color: #0000ff;">try</span><span style="color: #000000;">:
self.wfile.flush()
</span><span style="color: #0000ff;">except</span><span style="color: #000000;"> socket.error:
</span><span style="color: #008000;">#</span><span style="color: #008000;"> An final socket error may have occurred here, such as</span>
<span style="color: #008000;">#</span><span style="color: #008000;"> the local error ECONNABORTED.</span>
<span style="color: #0000ff;">pass</span><span style="color: #000000;">
self.wfile.close()
self.rfile.close()</span>
立即学习“Python免费学习笔记(深入)”;
最主要的功能是根据socket生成了读写socket用的两个文件对象(可以理解为句柄)rfile和wfile<span style="color: #0000ff;">class</span><span style="color: #000000;"> DatagramRequestHandler(BaseRequestHandler):
</span><span style="color: #008000;">#</span><span style="color: #008000;"> XXX Regrettably, I cannot get this working on Linux;</span>
<span style="color: #008000;">#</span><span style="color: #008000;"> s.recvfrom() doesn't return a meaningful client address.</span>
<span style="color: #800000;">"""</span><span style="color: #800000;">Define self.rfile and self.wfile for datagram sockets.</span><span style="color: #800000;">"""</span>
<span style="color: #0000ff;">def</span><span style="color: #000000;"> setup(self):
</span><span style="color: #0000ff;">try</span><span style="color: #000000;">:
</span><span style="color: #0000ff;">from</span> cStringIO <span style="color: #0000ff;">import</span><span style="color: #000000;"> StringIO
</span><span style="color: #0000ff;">except</span><span style="color: #000000;"> ImportError:
</span><span style="color: #0000ff;">from</span> StringIO <span style="color: #0000ff;">import</span><span style="color: #000000;"> StringIO
self.packet, self.socket </span>=<span style="color: #000000;"> self.request
self.rfile </span>=<span style="color: #000000;"> StringIO(self.packet)
self.wfile </span>=<span style="color: #000000;"> StringIO()
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> finish(self):
self.socket.sendto(self.wfile.getvalue(), self.client_address)</span>
立即学习“Python免费学习笔记(深入)”;
同样是生成rfile和wfile,但UDP不直接关联socket。这里的rfile是直接由从UDP中读取的数据生成的,wfile则是新建了一个StringIO,用于写数据。
立即学习“Python免费学习笔记(深入)”;
立即学习“Python免费学习笔记(深入)”;
python怎么学习?python怎么入门?python在哪学?python怎么学才快?不用担心,这里为大家提供了python速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号