zoukankan      html  css  js  c++  java
  • Python之基于socket和select模块实现IO多路复用

     

     
    '''IO指的是输入输出,一部分指的是文件操作,还有一部分
    网络传输操作,例如soekct就是其中之一;多路复用指的是
    利用一种机制,同时使用多个IO,例如同时监听多个文件句
    柄(socket对象一旦传送或者接收信息),一旦文件句柄出
    现变化就会立刻感知到
    '''
    1、下面通过IO多路复用实现多人同时连接socket服务器

    这是服务端代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    import socket
     
    sk1 = socket.socket()#sk1,sk2,sk3这就是一个文件描述符
    sk1.bind(('127.0.0.1',8002))
    sk1.listen()
     
     
    sk2 = socket.socket()
    sk2.bind(('127.0.0.1',8003))
    sk2.listen()
     
    sk3 = socket.socket()
    sk3.bind(('127.0.0.1',8004))
    sk3.listen()
     
    inputs = [sk1,sk2,sk3]
    import select
    while True:
        '''[sk1,sk2,sk3],select内部会自动监听sk1,sk21,sk3三个对象
        一旦某个句柄发生变化就会被监听到
        '''
        #如果有人链接sk1,则会被添加进列表,r_list = [sk1]
        r_list,w_list,e_list = select.select(inputs,[],[],1)#1表示等一秒,在while执行到这里的时候监测一秒,没有人来链接的话就接着循环
        #print(r_list,sk1.listen())
        for sk in r_list:
            conn,address = sk.accept()
            #print(conn,address)
            conn.sendall(bytes('你好',encoding='utf-8'))
            conn.close()

      客户端的代码都是一样的,就差个端口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    #客户端一
    import socket
     
     
    obj = socket.socket()
    obj.connect(('127.0.0.1',8002))
    content = str(obj.recv(1024),encoding='utf-8')
    print(content)
     
    obj.close()
     
    #客户端二
    import socket
     
     
    obj = socket.socket()
    obj.connect(('127.0.0.1',8003))
    content = str(obj.recv(1024),encoding='utf-8')
    print(content)
     
    obj.close()
     
     
    #客户端三
    import socket
     
     
    obj = socket.socket()
    obj.connect(('127.0.0.1',8004))
    content = str(obj.recv(1024),encoding='utf-8')
    print(content)
     
    obj.close()

      执行结果:只要启动服务器端,然后不同的客户端多次启动都能收到信息,多个端口成功被监听

    2、下面使用select模块实现多路复用,使同一个端口同时接收多个链接

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    import socket
     
    sk1 = socket.socket()#sk1,sk2,sk3这就是一个文件描述符
    sk1.bind(('127.0.0.1',8002))
    sk1.listen()
     
    #
    # sk2 = socket.socket()
    # sk2.bind(('127.0.0.1',8003))
    # sk2.listen()
    #
    # sk3 = socket.socket()
    # sk3.bind(('127.0.0.1',8004))
    # sk3.listen()
     
    inputs = [sk1]
    import select
     
    #epoll效率更高,但是Windows不支持,它是谁有问题就告诉它,不用循坏
    while True:
        '''[sk1,sk2,sk3],select内部会自动监听sk1,sk21,sk3三个对象
        一旦某个句柄发生变化(某人来链接)就会被监听到
        '''
        #如果有人链接sk1,则会被添加进列表,r_list = [sk1]
        r_list,w_list,e_list = select.select(inputs,[],[],1)
        '''第三个参数是监听错误的,只要有错误出现,就会被监听到,返回e_list
           第二个参数返回给w_list,只要传了什么,就原封不动的传给w_list'''
        print('正在监听 %s 多少个对象' % len(inputs))
        for sk in r_list:
            if sk == sk1:
                #句柄跟服务器端的对象一样,表示有新用户来链接了
                conn,address = sk.accept()
                inputs.append(conn)#加入去之后,inputs有一个链接对象和服务器对象
            else:
                #有老用户发消息了
                try:
                    data_byte =sk.recv(1024)
     
                    data_str =str(data_byte,encoding='utf-8')
                    sk.sendall(bytes(data_str+'收到了',encoding='utf-8'))
                except:#空信息表示客户端断开链接,所以要在监听中移除
                    
                    inputs.remove(sk)#这里的sk就是之前传进去的conn,因为r_list接收的是有变化的值
                    

     启动这个服务端之后,就可以实现多路复用了,可以接收多个客户端同时连接

    3、下面介绍一些多路操作里面的读写分离

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    import socket
     
    sk1 = socket.socket()#sk1就是一个文件描述符
    sk1.bind(('127.0.0.1',8002))
    sk1.listen()
    inputs = [sk1]#被检测发生变动的句柄放这里
    outputs=[]#用来记录谁给服务端发过信息,以便回复
    message_dict = {}#接收信息的,根据句柄形成键值对
    import select
     
    #epoll效率更高,但是Windows不支持,它是谁有问题就告诉它,不用循坏
    while True:
        '''[sk1,sk2,sk3],select内部会自动监听sk1,sk21,sk3三个对象
        一旦某个句柄发生变化(某人来链接)就会被监听到
        '''
        #如果有人链接sk1,则会被添加进列表,r_list = [sk1]
        r_list,w_list,e_list = select.select(inputs,outputs,inputs,1)
        '''第三个参数是监听错误的,只要有错误出现,就会被监听到,返回e_list
           第二个参数返回给w_list,只要传了什么,就原封不动的传给w_list'''
        print('正在监听 %s 多少个对象' % len(inputs))
        for sk in r_list:
            if sk == sk1:
                #句柄跟服务器端的对象一样,表示有新用户来链接了
                conn,address = sk.accept()
                inputs.append(conn)#加入去之后,inputs有一个链接对象和服务器对象
                message_dict[conn]=[]#字典的key是具体的链接对象
            else:
                #有老用户发消息了
                try:
                    data_byte =sk.recv(1024)
     
                except Exception as e:#空信息表示客户端断开链接,所以要在监听中移除
                    print(e)
                    inputs.remove(sk)#这里的sk就是之前传进去的conn,因为r_list接收的是有变化的值
                else:
                    data_str = str(data_byte, encoding='utf-8')
     
                    message_dict[sk].append(data_str)
                    outputs.append(sk)#把传送数据的句柄添加进去第二个参数
        for conn in w_list:
            recv_str=message_dict[conn][0]#拿到我们收到了的信息
            del message_dict[conn][0]#删除信息,防止下次出现一样的消息
            print(recv_str)
            conn.sendall(bytes(recv_str+'收到了',encoding='utf-8'))
            outputs.remove(conn)#回复完成之后在列表删除
        for sk_or_conn in e_list:
            e_list.remove(sk_or_conn)

      这样可以形成简单的读写分离操作

    对于select里面的参数关系,这里有个武sir画的图

     
  • 相关阅读:
    图灵访谈之二十二——Brian W. Kernighan与CS的半个世纪 (翻译)
    GIT 初探
    关于SQL的分组汇总统计(关键字 Grouping)
    根据表名生成该表的插入语句
    利用sys.dm_db_index_physical_stats查看索引碎片等数据
    SQL SERVER CURSOR
    Configuring a readonly replicated folder on Windows Server 2008 R2.
    securestring
    Sql Server查询性能优化
    七大排序速查版
  • 原文地址:https://www.cnblogs.com/xc1234/p/9129762.html
Copyright © 2011-2022 走看看