• python16_day09【Select多路复用】


    一、select多路复用

     1 句柄列表11, 句柄列表22, 句柄列表33 = select.select(句柄序列1, 句柄序列2, 句柄序列3, 超时时间)
     2  
     3 参数: 可接受四个参数(前三个必须)
     4 返回值:三个列表
     5  
     6 select方法用来监视文件句柄,如果句柄发生变化,则获取该句柄。
     7 1、当 参数1 序列中的句柄发生可读时(accetp和read),则获取发生变化的句柄并添加到 返回值1 序列中
     8 2、当 参数2 序列中含有句柄时,则将该序列中所有的句柄添加到 返回值2 序列中
     9 3、当 参数3 序列中的句柄发生错误时,则将该发生错误的句柄添加到 返回值3 序列中
    10 4、当 超时时间 未设置,则select会一直阻塞,直到监听的句柄发生变化
    11    当 超时时间 = 1时,那么如果监听的句柄均无任何变化,则select会阻塞 1 秒,之后返回三个空列表,如果监听的句柄有变化,则直接执行。
     1 import select
     2 import socket
     3 
     4 sk1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     5 sk1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     6 sk1.bind(('127.0.0.1', 8001),)
     7 sk1.listen(5)
     8 
     9 sk2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    10 sk2.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    11 sk2.bind(('127.0.0.1', 8002),)
    12 sk2.listen(5)
    13 
    14 inputs = [sk1, sk2]
    15 w_inputs = []
    16 while True:
    17     # IO多路复用,同时监听多个SOCKET对象.
    18     r, w, e = select.select(inputs, w_inputs, inputs, 0.05)  #
    19 
    20     for obj in r:
    21         print("obj::::", obj)
    22         print("sk1::::", sk1)
    23         if obj in [sk1, sk2]:
    24             # 新连接
    25             print("新连接....", obj)
    26             conn, addr = obj.accept()
    27             inputs.append(conn)
    28         else:
    29             # 有连接用户发送消息来了...
    30             print("有用户发数据了", obj)
    31             try:
    32                 data = obj.recv(1024)
    33             except Exception as e:
    34                 data = ""
    35             if data:
    36                 w_inputs.append(obj)
    37                 # obj.sendall(data)
    38             else:
    39                 obj.close()
    40                 inputs.remove(obj)
    41                 w_inputs.remove(obj)
    42 
    43     for obj in w_inputs:
    44         obj.sendall(b'ok')
    45         w_inputs.remove(obj)
    利用select实现伪同时处理多个Socket客户端请求:服务端
     1 import socket
     2 
     3 client = socket.socket()
     4 
     5 client.connect(('127.0.0.1', 8001))
     6 
     7 while True:
     8     v = input(">>>>")
     9     if v == 'exit':
    10         break
    11     client.sendall(bytes(v, encoding='utf8'))
    12     ret = client.recv(1024)
    13     print("server respone:", ret)
    14 
    15 client.close()
    利用select实现伪同时处理多个Socket客户端请求:客户端

    二、socketserver模块

      SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。

      即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进程” 专门负责处理当前客户端的所有请求。

      

      1.ThreadingTCPServer

      ThreadingTCPServer实现的Soket服务器内部会为每个client创建一个 “线程”,该线程用来和客户端进行交互。

      使用ThreadingTCPServer:

    • 创建一个继承自 SocketServer.BaseRequestHandler 的类
    • 类中必须定义一个名称为 handle 的方法
    • 启动ThreadingTCPServer
     1 import SocketServer
     2 
     3 class MyServer(SocketServer.BaseRequestHandler):
     4 
     5     def handle(self):
     6         # print self.request,self.client_address,self.server
     7         conn = self.request
     8         conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
     9         Flag = True
    10         while Flag:
    11             data = conn.recv(1024)
    12             if data == 'exit':
    13                 Flag = False
    14             elif data == '0':
    15                 conn.sendall('通过可能会被录音.balabala一大推')
    16             else:
    17                 conn.sendall('请重新输入.')
    18 
    19 
    20 if __name__ == '__main__':
    21     server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
    22     server.serve_forever()
    secketserver服务端
     1 import socket
     2 
     3 
     4 ip_port = ('127.0.0.1',8009)
     5 sk = socket.socket()
     6 sk.connect(ip_port)
     7 sk.settimeout(5)
     8 
     9 while True:
    10     data = sk.recv(1024)
    11     print 'receive:',data
    12     inp = raw_input('please input:')
    13     sk.sendall(inp)
    14     if inp == 'exit':
    15         break
    16 
    17 sk.close()
    socketserver客户端

      2.源码剖析

      

    内部调用流程为:

    • 启动服务端程序
    • 执行 TCPServer.__init__ 方法,创建服务端Socket对象并绑定 IP 和 端口
    • 执行 BaseServer.__init__ 方法,将自定义的继承自SocketServer.BaseRequestHandler 的类 MyRequestHandle赋值给 self.RequestHandlerClass
    • 执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 ...
    • 当客户端连接到达服务器
    • 执行 ThreadingMixIn.process_request 方法,创建一个 “线程” 用来处理请求
    • 执行 ThreadingMixIn.process_request_thread 方法
    • 执行 BaseServer.finish_request 方法,执行 self.RequestHandlerClass()  即:执行 自定义 MyRequestHandler 的构造方法(自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用 MyRequestHandler的handle方法)
     1 import socket
     2 import threading
     3 import select
     4 
     5 
     6 def process(request, client_address):
     7     print request,client_address
     8     conn = request
     9     conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
    10     flag = True
    11     while flag:
    12         data = conn.recv(1024)
    13         if data == 'exit':
    14             flag = False
    15         elif data == '0':
    16             conn.sendall('通过可能会被录音.balabala一大推')
    17         else:
    18             conn.sendall('请重新输入.')
    19 
    20 sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    21 sk.bind(('127.0.0.1',8002))
    22 sk.listen(5)
    23 
    24 while True:
    25     r, w, e = select.select([sk,],[],[],1)
    26     print 'looping'
    27     if sk in r:
    28         print 'get request'
    29         request, client_address = sk.accept()
    30         t = threading.Thread(target=process, args=(request, client_address))
    31         t.daemon = False
    32         t.start()
    33 
    34 sk.close()
    精简版sockserver

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

  • 相关阅读:
    asp.net 发送邮件
    效控制C#中label输出文字的长度,自动换行
    无法连接到WMI 提供程序 请注意,你只能使用SQL Server 配置管理器来管理SQL Server 2005服务器。找不到指定的模块。[0x8007007e]
    查询区分大小写
    ASP.NET母版页引用外部css和js文件的写法
    VS2008 Debugging Breakpoint 补丁
    firefox下获得焦点
    IE打开出现windows找不到文件'(null)'解决方法Vinzipblog文之巴博客
    邪恶的web上下键焦点移动
    jQuery对下拉框Select操作总结
  • 原文地址:https://www.cnblogs.com/weibiao/p/6598514.html
Copyright © 2020-2023  润新知