• socketserver 源码浅读


    import SocketServer
    class MyServer(SocketServer.BaseRequestHandler):
        def handle(self):       #函数名必须是handle,源码BaseRequestHandler预定义;
            print self.request,self.client_address,self.server  #BaseRequestHandler的__init__定义好的;
            conn = self.request     #每个连接的socket
            conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
            Flag = True
            while Flag:
                data = conn.recv(1024)
                if data == 'exit':
                    Flag = False
                elif data == '0':
                    conn.sendall('通话可能会被录音.balabala一大推')
                else:
                    conn.sendall('请重新输入.')
    if __name__ == '__main__':
        server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)   #实例化ThreadingTCPServer,其实是继承TCPServer类的初始化,需要传入(server_address, RequestHandlerClass),RequestHandlerClass就是MyServer类。
        server.serve_forever()  #启动服务,用select一直在循环执行,继承自BaseServer类的方法serve_forever();

    分析这段代码

    服务器启动程序后:
    1、执行 TCPServer.__init__ 方法,创建服务端Socket对象并绑定 IP 和 端口
        解释:class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass,ThreadingTCPServer先要执行__init__构造函数,ThreadingMixIn里没有,就去TCPServer类里去找
    2、执行 BaseServer.__init__ 方法,将自定义的继承自SocketServer.BaseRequestHandler 的类 MyRequestHandle赋值给self.RequestHandlerClass
        解释:TCPServer构造方法中包含BaseServer.__init__(self, server_address, RequestHandlerClass),所以要把自己定义的类传给BaseServer的构造方法
    3、执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 ...
        解释:serve_forever是BaseServer类中的方法,里面有个while循环,一直调用select.select(),r, w, e = _eintr_retry(select.select, [self], [], [],poll_interval)
    客户端接入:
    4、执行BaseServer._handle_request_noblock方法
        解释:serve_forever的while循环里有一个判断if self in r:self._handle_request_noblock(),客户端连接句柄发生变化就会把句柄放到r列表里,所以,触发了_handle_request_noblock()。
    5、执行 ThreadingMixIn.process_request 方法,创建一个 “线程” 用来处理请求
        解释:调用process_request方法时,从继承类广度优先原则,所以它先调用ThreadingMixIn类中的process_request
    6、执行 ThreadingMixIn.process_request_thread 方法
        解释:t = threading.Thread(target = self.process_request_thread,args = (request, client_address))多线程模块方法,调用self.process_request_thread,此时才真正启动了线程。
    7、执行 BaseServer.finish_request 方法,执行 self.RequestHandlerClass()  即:执行 自定义 MyRequestHandler 的构造方法(自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用自定义的MyRequestHandler的handle方法)
        解释:连接创建完成,此时开始执行handle方法中的内容,开始和客户端交互,执行完,后面再执行shutdown_request方法关闭连接。
     
    import socket
    import threading
    import select
    def process(request, client_address):
        print request,client_address
        conn = request
        conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
        flag = True
        while flag:
            data = conn.recv(1024)
            if data == 'exit':
                flag = False
            elif data == '0':
                conn.sendall('通过可能会被录音.balabala一大推')
            else:
                conn.sendall('请重新输入.')
    sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sk.bind(('127.0.0.1',8002))
    sk.listen(5)
    while True:
        r, w, e = select.select([sk,],[],[],1)
        print 'looping'
        if sk in r:
            print 'get request'
            request, client_address = sk.accept()
            t = threading.Thread(target=process, args=(request, client_address))
            t.daemon = False
            t.start()
    sk.close()

    如精简代码可以看出,SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于 select 和 Threading 两个东西,其实本质上就是在服务器端为每一个客户端创建一个线程,当前线程用来处理对应客户端的请求,所以,可以支持同时n个客户端链接(长连接)。
    来源: http://www.cnblogs.com/wupeiqi/articles/5040823.html

  • 相关阅读:
    FlexGrid布局
    Grid 布局管理器
    StaticBox布局管理器
    鼠标事件
    screen 常用命令
    wxPython 安装 及参考文档
    wxPython 界面编程的有关事件
    关于用python作为第三方程序,来调用shell命令的问题,以及返回值格式解析
    Mysql的增删改查
    linux ubuntu 系统修改源
  • 原文地址:https://www.cnblogs.com/journey-mk5/p/9616242.html
Copyright © 2020-2023  润新知