socketserver

socketserver模块简化了编写网络服务器的任务

有4个基本的服务器类(server class):
socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)

socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)

socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)

socketserver.UnixDatagramServer(server_address, RequestHandlerClass, bind_and_activate=True)

这四个类是同步(Synchronous)进行处理的。要处理异步(Asynchronous),需使用ThreadingMixIn和ForkingMixIn类。

创建服务器需要几个步骤:

  1. you must create a request handler class by subclassing the BaseRequestHandler class and overriding its handle() method; this method will process incoming requests. 你必须创建一个请求处理类,这个类需继承BaseRequestHandler,并且重写父类的handle方法
  2. you must instantiate one of the server classes, passing it the server’s address and the request handler class. Then call the handle_request() or serve_forever() method of the server object to process one or many requests.  你必须实例化server classes(如TCPServer),并且传递server address和上面创建的请求处理类给server classes(如TCPServer),然后调用服务器对象(实例化的server classes)的handle_request()或serve_forever()方法来处理一个或多个请求。
  3. call server_close() to close the socket.调用server_close()关闭套接字。
import socket

HOST,PORT = "localhost",9999
with socket.socket() as sock:
    sock.connect((HOST,PORT))
    sock.send("abc".encode())

    received = sock.recv(1024).decode()

    print("sent: {}".format("abc"))
    print("received:{}".format(received))
socketserver_client
import socketserver

class MyTcpHandle(socketserver.BaseRequestHandler):  #第一步,创建一个请求处理类,并且重写handle

    def handle(self):   #客户端的请求都在handle来实现
        #self.request is the TCP socket conneted to le client
        self.data = self.request.recv(1024).strip()    #
        print("{} wrote:".format(self.client_address))
        print(self.data)

        self.request.send(self.data.upper())


if __name__ == "__main__":
    HOST,PORT = "localhost",9999

    server = socketserver.TCPServer((HOST,PORT),MyTcpHandle)  #第二步,实例化服务器类
    server.serve_forever()
socketserver_server

 

 上面仍不能与多个用户通信,此时我们需要用到异步,即ThreadingMixIn和ForkingMixIn,直接看代码

import socket

HOST,PORT = "localhost",9999
with socket.socket() as sock:

   sock.connect((HOST,PORT))
   while True:
       data = input(">>").strip()
       if len(data) == 0:
           continue
       sock.send(data.encode())

       received = sock.recv(1024).decode()

       print("sent: {}".format(data))
       print("received:{}".format(received))
socketserver_thread_client
import socketserver
import threading,socket


class MyTcpHandle(socketserver.BaseRequestHandler):

    def handle(self):
        #self.request is the TCP socket conneted to le client
        while True:
            try:
                self.data = self.request.recv(1024).strip()    #当客户端没有数据时会产生ConnectionResetError异常
            except ConnectionResetError as e:
                print(e)
                break

            print("{} wrote:".format(self.client_address))
            print(self.data)
            self.request.send(self.data.upper())


class ThreadTCPServer(socketserver.ThreadingMixIn,socketserver.TCPServer):
    pass
if __name__ == "__main__":
    HOST,PORT = "localhost",9999

    server = socketserver.ThreadingTCPServer((HOST,PORT),MyTcpHandle)  #继承ThreadingMixIn, TCPServer
    #实例化ThreadingTCPServer其实就是实例化TCPServer((HOST,PORT),MyTcpHandle)
    server.serve_forever()
    #最后其实是MyTcpHandle(finish_request中实现)实例化,self.request相当于在套接字中的conn(用户端实例), client_address(用户端地址和端口号)
socketserver_thread_server

 

根据源码分析可得,ThreadindTCPServer继承ThreadMixIn和TCPServer

 

先看下第一步初始化

server = socketserver.ThreadingTCPServer((HOST,PORT),MyTcpHandle)做了什么操作:

1、通过继承关系知道ThreadingTCPServer初始化就是TCPServer初始化

2、TCPServer初始化里面做了什么操作呢?先继承了BaseServer的构造方法然后初始化生成一个套接字socket,然后bind和listen

3、BaseServer做了什么操作呢?对传进来的两个参数进行初始化分别赋值给:server_address和RequestHandlerClass,生成一个线程事件__is_shut_down=threading.Event来进行同步,对__shutdown_request 赋值False

等学完select和多线程,要来分析下socketserver源码并做记录

第二步:server.serve_forever()

1、使用了事件驱动selectors模块,当有连接进来时,运行_handle_request_noblock()

2、accept得到request,client_address

3、创建一个线程来处理连接过来的请求

更多

posted @ 2017-07-13 19:07  zj-luxj  阅读(139)  评论(0编辑  收藏  举报