Select的用法(select是一个单线程) s.bind(('127.0.0.1', 8888)) s.listen(5) r_list = [s, ] num = 0 while True: print(u"开始进入监听状态...") rl, wl, error = select.select(r_list, [], [], 10)#所有的过程都是单线程 要操作的对象都会放在rl里面的 # 第一次执行循环体:客户端建立的连接的时候,rl和r_list分别是[s,]和[s,] # 执行连接之后,r_list变为了[s,conn],建立连接会走if逻辑 # 第二次执行循环体:有需要读取的时候,rl和r_list分别是[conn,]和[s,conn],执行else逻辑 # 。。。。。如果客户端没有发送消息rl是[] ##第n次执行循环体:rl和r_list分别是[conn,]和[s,conn],执行else逻辑 #简单来说rl会在建立连接后,添加socket对象,但是以后就不会在添加socket对象了, #因为建立连接的事件只会被select监听到一次。 #然后select就一直监听已经建立的连接对象是否有数据发来了。当有异常的时候,会把链接对象从rl中删除掉。 num += 1 print(u'执行次数%s'% num) print("rl's length is %s" % len(rl)) print("r_list length %s" % len(r_list)) print([i for i in rl]) for fd in rl: if fd == s:#客户端连接的时候会被触发一次 conn, addr = fd.accept()#建立连接 r_list.append(conn)#加入到监听列表里面 msg = conn.recv(200)#收取从客户端来的数据 conn.sendall(('first----%s' % msg.upper()).encode("utf-8"))#给客户端回复数据 else:#客户端建立连接后发来了新的消息,会执行else分支 try: msg = fd.recv(200) fd.sendall(msg.upper())#把收到的数据转换为大写后,发回给客户端 except (ConnectionAbortedError, ConnectionResetError): r_list.remove(fd) s.close() Select的解释 fd_r_list, fd_w_list, fd_e_list = select.select(rlist, wlist, xlist, [timeout]) 参数: 可接受四个参数(前三个必须) rlist: 等待准备阅读 wlist: 等待准备写作(一般不使用) xlist: 等待“例外情况” timeout: 超时时间,表示多少秒监听一次,如果为None或者为空则阻塞直到至少有一个文件描述符已经准备好了。 s.bind(('127.0.0.1', 8888)) s.listen(5) r_list = [s, ] num = 0 while True: print(u"开始进入监听状态...") rl, wl, error = select.select(r_list, [], [], 10) # 第一次执行循环体:客户端建立的连接的时候,rl和r_list分别是[s,]和[s,] # 执行连接之后,r_list变为了[s,conn],建立连接会走if逻辑 # 第二次执行循环体:有需要读取的时候,rl和r_list分别是[conn,]和[s,conn],执行else逻辑 # 。。。。。如果客户端没有发送消息rl是[] ##第n次执行循环体:rl和r_list分别是[conn,]和[s,conn],执行else逻辑 #简单来说rl会在建立连接后,添加socket对象,但是以后就不会在添加socket对象了, #因为建立连接的事件只会被select监听到一次。 #然后select就一直监听已经建立的连接对象是否有数据发来了。当有异常的时候,会把链接对象从rl中删除掉。 num += 1 print(u'执行次数%s'% num) print("rl's length is %s" % len(rl)) print("r_list length %s" % len(r_list)) print([i for i in rl]) for fd in rl: if fd == s:#客户端连接的时候会被触发一次 conn, addr = fd.accept()#建立连接 r_list.append(conn)#加入到监听列表里面 msg = conn.recv(200)#收取从客户端来的数据 conn.sendall(('first----%s' % msg.upper()).encode("utf-8"))#给客户端回复数据 else:#客户端建立连接后发来了新的消息,会执行else分支 try: msg = fd.recv(200) fd.sendall(msg.upper())#把收到的数据转换为大写后,发回给客户端 except (ConnectionAbortedError, ConnectionResetError): r_list.remove(fd) s.close() 服务端的代码 r_list:select需要监听的文件对象。 开始的时候我初始化这个列表:r_list = [s, ] 把socket放进去了。 1)开始执行:rl, wl, error = select.select(r_list, [], [], 10) 等待10秒,看看有没有人来建立连接,如果没有 2)代码继续执行从num += 1开始执行,然后执行到if,if和else并没有被触发 因为rl里面是空,什么都没有。 继续下一次循环,从1开始执行,如此反复。 如果有客户端进行连接了呢?开始代码向下执行: rl从[]---->[s], 代码继续执行从num += 1开始执行,然后执行到if if 的条件被触发了,客户端和server的连接被建立了。 if fd == s:#客户端连接的时候会被触发一次 conn, addr = fd.accept()#建立连接 r_list.append(conn)#加入到监听列表里面 msg = conn.recv(200)#收取从客户端来的数据 conn.sendall(('first----%s' % msg.upper()).encode("utf-8"))#给客户端回复数据 结束当前循环,继续从1)开始。这个时候除了监控s对象有没有新建连接 请求外,conn也被监控看看客户端是否发来了数据。 如果没有新建链接也没有conn被发来数据,rl=[] -->if和else都不会被执行 继续下一次循环,从1)开始执行,如此反复。 r_list包含了conn对象(被监听),如果客户端发来数据, rl, wl, error = select.select(r_list, [], [], 10) rl=[] 变成了[conn],会触发else:操作,从连接中读取发来的数据,并 转换为大写之后返回给客户端 try: msg = fd.recv(200) fd.sendall(msg.upper())#把收到的数据转换为大写后,发回给客户端 except (ConnectionAbortedError, ConnectionResetError): r_list.remove(fd) 继续下一次循环,从1)开始执行,如此反复。 15.3.客户端的情况 rl:客户端既没有连接,有没有发送数据的情况下,rl一直是[] 只有在客户端有动作的时候, 它才从[]--->[s]或者[conn1]或者[conn1,conn2...] 1)新建连接的请求,s(socket对象) 2)已经建立连接后发送数据的连接对象conn对象(可能是一个也可能是多个。) 客户端的代码 import socket flag = 1 s = socket.socket() s.connect(('127.0.0.1', 8888)) while flag: input_msg = input('input>>>') if input_msg == '0': break s.sendall(input_msg.encode()) msg = s.recv(1024) print(msg.decode()) s.close()