代码改变世界

2018.4.1学习笔记(I/O多路复用,利用到select模块)

2018-04-01 22:30  冒牌权限  阅读(102)  评论(0)    收藏  举报

利用select模块来实现I/O多路复用(I/O多路复用其实本身是由系统底层来实现的,windows只支持select,由系统去循环监测,效率较低,poll优化了select,不过还是循环,效率较低,linux支持epoll,由文件描述符主动告知epoll,异步,效率高)

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#####服务端#####
import socket,select

sk1 = socket.socket()
sk1.bind(('127.0.0.1',10001))
sk1.listen()

sk2 = socket.socket()
sk2.bind(('127.0.0.1',10002))
sk2.listen()

sk3 = socket.socket()
sk3.bind(('127.0.0.1',10003))
sk3.listen()

inputs = [sk1,sk2,sk3]

while True:
    r_list,w_list,e_list = select.select(inputs,[],inputs,1)#最后那个1代表每1秒监测一次
    #r_list监测的变化的文件描述符,有值就表示该描述符有变化
    #w_list监测所传过来的参数,传了什么就是什么
    #e_list监测出错的文件描述符,有值就表示该描述符出错
    for sk in r_list:
        conn,address = sk.accept()
        conn.sendall(bytes('老铁,你来啦',encoding='utf-8'))
        conn.close()
    for sk in e_list:
        inputs.remove(sk)#把出错的文件描述符去除

 伪造多用户连接

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#####服务端#####
import socket,select

sok = socket.socket()
sok.bind(('127.0.0.1',10001))
sok.listen()

inputs = [sok,]

while True:
    r_list,w_list,e_list = select.select(inputs,[],inputs,1)
    for sk in r_list:
        if sk == sok:
            conn,address = sk.accept()
            inputs.append(conn)#把连接(即客户端的信息)加入列表,当客户端有发消息过来时就可以利用了
        else:
            try:
                sk.recv(1024)#因为sk不等于sok,所以这时候sk就是上边那个conn了
                sk.sendall(bytes('老铁,你来啦',encoding='utf-8'))
            except Exception as ex:
                inputs.remove(sk)

#####客户端#####
import socket

obj = socket.socket()
obj.connect(('localhost',10001))#要请求的服务器ip和端口
while True:
    inp = input('>>>')
    no_str = ['exit']
    if inp in no_str:
        break
    obj.sendall(bytes(inp,encoding='utf-8'))
    ret = str(obj.recv(1024),encoding='utf-8')
    print(ret)
obj.close()

 读写分离式伪并发

#!/usr/bin/env python
# -*- coding:utf-8 -*-

#####服务端#####
import socket,select

sok = socket.socket()
sok.bind(('127.0.0.1',10001))
sok.listen()

sok_inp = [sok,]#r_list用
sok_li = []#w_list用
sok_dict = {}#消息记录用

while True:
    r_list,w_list,e_list = select.select(sok_inp,sok_li,sok_inp,1)
    for sk in r_list:
        if sk == sok:
            conn,address = sk.accept()#等待连接
            sok_inp.append(conn)#把连接添加进sok_inp
            sok_dict[conn] = []#消息记录里创建连接与值的对应关系
        else:
            try:
                value = str(sk.recv(1024),encoding='utf-8')#一但收到对端发来消息,则接收并转换为字符串
            except Exception as ex:
                sok_inp.remove(sk)#如果对端断开连接或出错,则删除这个连接
            else:
                sok_li.append(sk)#把发消息的连接添加到sok_li列表
                sok_dict[sk].append(value)#把消息添加到消息记录
    for conn in w_list:
            ret = sok_dict[conn][(len(sok_dict[conn]) - 1)]#获取发消息的那条连接的最后一条消息记录
            sk.sendall(bytes(ret + '老铁,你来啦', encoding='utf-8'))
            sok_li.remove(conn)#删除发消息的连接,这里可以看出sok_li里始终只有一条连接



#####客户端#####
import socket

obj = socket.socket()
obj.connect(('localhost',10001))#要请求的服务器ip和端口
while True:
    inp = input('>>>')
    no_str = ['exit']
    if inp in no_str:
        break
    obj.sendall(bytes(inp,encoding='utf-8'))
    ret = str(obj.recv(1024),encoding='utf-8')
    print(ret)
obj.close()