04协程番外:IO多路复用之select服务器案例第一版

Python的select使用关键点就select模块的select函数
import select
readables,writeables,exceptions=select.select(readable_list,writeable_list,exception_list,time_out) #1
每执行 1 这句话话,
情况一:
time_out为空的情况下,select会监听:
readable_list中的资源是否可读,将读就绪的资源返回到readables
writeable_list中的资源是否可写,将写就绪的资源返回到writeables
exception_list中的资源是否发生异常,将发生异常的资源放入exceptions
当所有资源都没有就绪的时候,select.select会阻塞当前线程,直到有某个资源就绪,然后返回
情况二:
time_out不为空的情况下,select会监听:
readable_list中的资源是否可读,将读就绪的资源返回到readables
writeable_list中的资源是否可写,将写就绪的资源返回到writeables
exception_list中的资源是否发生异常,将发生异常的资源放入exceptions
当所有资源都没有就绪的时候,select.select会阻塞当前线程,直到在time_out时间内有某个资源就绪,然后返回;如果在timeout时间内没有资源就绪,那就返回三个空列表,也就是readables=writerables=exceptisons=[]

import select
import socket
import time
SERVER_HOST=('127.0.0.1',9999)

class Select_Server_01:
    '''
    使用select和可读队列,可写队列实现服务器
    '''
    def __init__(self):
        #创建套接字
        self.server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        #绑定端口
        self.server_socket.bind(SERVER_HOST)
        #设置为监听套接字
        self.server_socket.listen(5)
        #可读就绪资源列表
        self.readable_list=[self.server_socket]
        #可写就绪资源列表
        self.writeable_list=[]
        '''
        存储客户端socket传递过来的参数
        存储结构如下
        键为:客户端socket对象,值为socket对象传入的值
        '''
        self.client_socket_args={}

    def handle_request(self,request_args):
        #根据传入参数返回对应的参数
        return "{}时刻,经过不负责任的socket处理过的数据:{}".format(time.time(),request_args)

    '''
    服务器运行核心,通过while循环 
    '''
    def run(self):
        """
        主循环,不断循环处理可读与可写队列
        :return:
        """
        while True:
            #select检查并返回可读与可写列表中那些就绪的socket
            readables,writerables,exceptions=select.select(self.readable_list,self.writeable_list,[])

            #处理每个可读的socket
            for readable_item in readables:
                if readable_item==self.server_socket: #如果可读就绪的是服务器socket,则表示有新的客户端接入
                    client_socket,client_socket_address=readable_item.accept()
                    #将新的客户端socket存入可读列表
                    self.readable_list.append(client_socket)
                    print('接收到新socket:{}'.format(client_socket))
                else:   #除了服务器socket就是客户端socket可读了,我们这里接收一下客户端socket数据(这里是普通参数)
                    recv_data=readable_item.recv(1024).decode('utf-8')  #这是一个堵塞操作,客户端最好不要一次发送太多的数据
                    if recv_data=='':
                        #如果客户端发送空字符串,表示自己要关闭,所以我们要清除这个客户端
                        #先关闭掉它
                        try:
                            readable_item.close()
                        except:
                            pass
                        #从客户端请求参数列表中清除
                        if readable_item in self.client_socket_args:
                            del self.client_socket_args[readable_item]
                        #从可读队列中清除
                        if readable_item in self.readable_list:
                            self.readable_list.remove(readable_item)
                        #从可写队列中清除
                        if readable_item in self.writeable_list:
                            self.writeable_list.remove(readable_item)
                        #从本轮的写就绪队列中删除(因为我们接下来会处理可写socket)
                        if readable_item in writerables:
                            writerables.remove(readable_item)
                        print('清除socket:{}'.format(readable_item))
                    elif recv_data!='CLOSE_SERVER_ZHOUYUQING':
                        #将请求参数存入客户端请求参数字典
                        self.client_socket_args[readable_item]=recv_data
                        #接下来我们要将客户端socket放入可写队列
                        if readable_item not in self.writeable_list:
                            self.writeable_list.append(readable_item)
                        print('处理socket:{}'.format(readable_item))
                    else: #客户端发过来是关闭指令
                        self.close()
                        return
            #处理每个可写的socket
            for writeable_item in writerables:
                #获取这个socket对应传入参数
                client_send_data=self.client_socket_args.get(writeable_item)
                #向可写socket发送数据
                print('当前关于该socket:{} 的传入参数是:{}'.format(writeable_item,client_send_data))
                writeable_item.send(self.handle_request(client_send_data).encode('utf-8')) #阻塞操作
                print('发送数据给:{}'.format(writeable_item))
                #处理完这个可读socket后从可读队列中删除,知道它再次发送请求参数过来才会被添加到可读队列中
                self.writeable_list.remove(writeable_item)


    '''
    关闭select_socket服务器
    '''
    def close(self):
        #关闭所有存在的socket
        for _socket in self.readable_list+self.writeable_list:
            try:
                _socket.close()
            except:
                pass
        print('服务器执行关闭所有操作')

class Client_Socket_01:
    '''
    测试客户端socket
    '''
    def __init__(self):
        self.client_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    def run(self,info,num):
        self.client_socket.connect(SERVER_HOST)
        for _ in range(num):
            self.client_socket.send(info.encode('utf-8'))
            print('\n\n         {} 接收响应:{}\n\n'.format(info,self.client_socket.recv(1024).decode('utf-8')))

        #发送关闭动作(发送一个为空字符串)
        self.client_socket.send(''.encode('utf-8'))
        try:
            self.client_socket.close()
        except:
            pass

import multiprocessing
def main_01():
    #先启动服务器
    server_socket=Select_Server_01()
    multiprocessing.Process(target=server_socket.run).start()

    #启动测试客户端
    client_socket_01=Client_Socket_01()
    multiprocessing.Process(target=client_socket_01.run,args=('测试客户端1',1)).start()
    client_socket_02=Client_Socket_01()
    multiprocessing.Process(target=client_socket_02.run,args=('测试客户端2',3)).start()
    client_socket_03=Client_Socket_01()
    multiprocessing.Process(target=client_socket_03.run,args=('测试客户端3',6)).start()
    client_socket_04=Client_Socket_01()
    multiprocessing.Process(target=client_socket_04.run,args=('测试客户端4',9)).start()

    #创建一个客户端发送一个关闭指令给服务器
    time.sleep(30) #这句话很重要,你不要一上来就把服务器关了
    final_client_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    final_client_socket.connect(SERVER_HOST)
    final_client_socket.send('CLOSE_SERVER_ZHOUYUQING'.encode('utf-8'))
    try:
        final_client_socket.close()
    except:
        pass
    print('-------------------------->>>>>>>>>>>>>>>>执行关闭服务器完毕')

"""
执行:
    main_01()
执行结果:

    接收到新socket:
    接收到新socket:
    处理socket:
    当前关于该socket: 的传入参数是:测试客户端1
    发送数据给:


             测试客户端1 接收响应:1548409232.0193949时刻,经过不负责任的socket处理过的数据:测试客户端1


    处理socket:
    当前关于该socket: 的传入参数是:测试客户端2
    发送数据给:


             测试客户端2 接收响应:1548409232.0195627时刻,经过不负责任的socket处理过的数据:测试客户端2


    处理socket:
    当前关于该socket: 的传入参数是:测试客户端2
    发送数据给:


             测试客户端2 接收响应:1548409232.0199127时刻,经过不负责任的socket处理过的数据:测试客户端2


    处理socket:
    当前关于该socket: 的传入参数是:测试客户端2
    发送数据给:
    接收到新socket:
    处理socket:
    当前关于该socket: 的传入参数是:测试客户端3
    发送数据给:


             测试客户端3 接收响应:1548409232.0201845时刻,经过不负责任的socket处理过的数据:测试客户端3



             测试客户端2 接收响应:1548409232.020043时刻,经过不负责任的socket处理过的数据:测试客户端2



    处理socket:
    当前关于该socket: 的传入参数是:测试客户端3
    发送数据给:


             测试客户端3 接收响应:1548409232.020338时刻,经过不负责任的socket处理过的数据:测试客户端3


    处理socket:
    当前关于该socket: 的传入参数是:测试客户端3
    发送数据给:
    接收到新socket:
    处理socket:
    当前关于该socket: 的传入参数是:测试客户端4
    发送数据给:


             测试客户端4 接收响应:1548409232.0205855时刻,经过不负责任的socket处理过的数据:测试客户端4



             测试客户端3 接收响应:1548409232.020468时刻,经过不负责任的socket处理过的数据:测试客户端3



    处理socket:
    处理socket:
    当前关于该socket: 的传入参数是:测试客户端3


             测试客户端3 接收响应:1548409232.0207088时刻,经过不负责任的socket处理过的数据:测试客户端3


    发送数据给:
    当前关于该socket: 的传入参数是:测试客户端4
    发送数据给:
    处理socket:
    当前关于该socket: 的传入参数是:测试客户端3


             测试客户端3 接收响应:1548409232.0208163时刻,经过不负责任的socket处理过的数据:测试客户端3


    发送数据给:
    处理socket:
    当前关于该socket: 的传入参数是:测试客户端3


             测试客户端3 接收响应:1548409232.0208836时刻,经过不负责任的socket处理过的数据:测试客户端3


    发送数据给:


             测试客户端4 接收响应:1548409232.0207596时刻,经过不负责任的socket处理过的数据:测试客户端4


    处理socket:
    当前关于该socket: 的传入参数是:测试客户端4
    发送数据给:


             测试客户端4 接收响应:1548409232.0210006时刻,经过不负责任的socket处理过的数据:测试客户端4


    处理socket:
    当前关于该socket: 的传入参数是:测试客户端4
    发送数据给:


             测试客户端4 接收响应:1548409232.0211372时刻,经过不负责任的socket处理过的数据:测试客户端4


    处理socket:
    当前关于该socket: 的传入参数是:测试客户端4
    发送数据给:


             测试客户端4 接收响应:1548409232.021273时刻,经过不负责任的socket处理过的数据:测试客户端4


    处理socket:
    当前关于该socket: 的传入参数是:测试客户端4


             测试客户端4 接收响应:1548409232.0214124时刻,经过不负责任的socket处理过的数据:测试客户端4


    发送数据给:
    处理socket:
    当前关于该socket: 的传入参数是:测试客户端4


             测试客户端4 接收响应:1548409232.021508时刻,经过不负责任的socket处理过的数据:测试客户端4


    发送数据给:
    处理socket:
    当前关于该socket: 的传入参数是:测试客户端4


             测试客户端4 接收响应:1548409232.0216038时刻,经过不负责任的socket处理过的数据:测试客户端4


    发送数据给:
    处理socket:
    当前关于该socket: 的传入参数是:测试客户端4


             测试客户端4 接收响应:1548409232.0217009时刻,经过不负责任的socket处理过的数据:测试客户端4


    发送数据给:
    -------------------------->>>>>>>>>>>>>>>>执行关闭服务器完毕
    接收到新socket:
    服务器执行关闭所有操作  
    
"""

你可能感兴趣的:(04协程番外:IO多路复用之select服务器案例第一版)