def data_received(self, data): """负责数据的接收、处理和发送,可以会被调用多次""" self.data+=data if self.data.endswith(b'?'): answer = zen_utils.get_answer(self.data) self.transport.write(answer) self.data = b''
def data_received(self, data): self.data += data if self.data.endswith(b'?'): answer = zen_utils.get_answer(self.data) #向传输中写入一些数据字节。此方法不会阻塞;它缓冲数据并安排将其异步发送出去。 self.transport.write(answer) self.data = b''
def serve(listener): sockets = {listener.fileno(): listener} addresses = {} bytes_received = {} bytes_to_send = {} poll_object = select.poll() poll_object.register(listener, select.POLLIN) for fd, event in all_events_forever(poll_object): sock = socket[fd] #Socket closed: remove it from our data structures. if event & (select.POLLHUP | select.POLLERR | select.POLLNVAL): address = addresses.pop(sock) rb = bytes_received.pop(sock, b'') sb = bytes_to_send.pop(sock, b'') if rb: print('Client {} sent {} but then closed'.format(address, rb)) elif sb: print('Client {} closed before we sent {}'.format(address, sb)) else: print('Client {} closed socket normally'.format(address)) poll_object.unregister(fd) del socket[fd] # New socket:add it to our data structures. elif sock is listener: sock, address = sock.accept() print('Accepted connection from {}'.format(address)) sock.setblocking(False) # force socket.timeout if we blunder sockets[sock.fileno()] = sock addresses[sock] = address poll_object.register(sock, select.POLLIN) # Incoming data: keep receiving until we see the suffix. elif event & select.POLLIN: more_data = sock.recv(4096) if not more_data: # end-of-file sock.close() # next poll() with POLLNVAL, and thus clean up continue data = byte_received.pop(sock, b'') + more_data if data.endwith(b'?'): bytes_to_send[sock] = zen_utils.get_answer(data) poll_object.modify(sock, select.POLLOUT) else: bytes_received[sock] = data # Socket ready to send: keep sending until all bytes are delivered. elif event & select.POLLout: data = bytes_to_send.pop(sock) n = sock.send(data) if n < len(data): bytes_to_send[sock] = data[n:] else: poll_object.modify(sock, select.POLLIN)
def serve(listener): sockets = {listener.fileno(): listener} addresses = {} bytes_received = {} bytes_to_send = {} poll_object = select.poll() poll_object.register(listener, select.POLLIN) for fd, event in all_events_forever(poll_object): sock = sockets[fd] # Socket closed: remove it from our data structures. if event & (select.POLLHUP | select.POLLERR | select.POLLNVAL): address = addresses.pop(sock) rb = bytes_received.pop(sock, b'') sb = bytes_to_send.pop(sock, b'') if rb: print('Client {} sent {} but then closed'.format(address, rb)) elif sb: print('Client {} closed before we sent {}'.format(address, sb)) else: print('Client {} closed socket normally'.format(address)) poll_object.unregister(fd) del sockets[fd] # New socket: add it to our data structures. elif sock is listener: sock, address = sock.accept() print('Accepted connection from {}'.format(address)) sock.setblocking(False) # force socket.timeout if we blunder sockets[sock.fileno()] = sock addresses[sock] = address poll_object.register(sock, select.POLLIN) # Incoming data: keep receiving until we see the suffix. elif event & select.POLLIN: more_data = sock.recv(4096) if not more_data: # end-of-file sock.close() # next poll() will POLLNVAL, and thus clean up continue data = bytes_received.pop(sock, b'') + more_data if data.endswith(b'?'): bytes_to_send[sock] = zen_utils.get_answer(data) poll_object.modify(sock, select.POLLOUT) else: bytes_received[sock] = data # Socket ready to send: keep sending until all bytes are delivered. elif event & select.POLLOUT: data = bytes_to_send.pop(sock) n = sock.send(data) if n < len(data): bytes_to_send[sock] = data[n:] else: poll_object.modify(sock, select.POLLIN)
def serve(listener): sockets = {listener.fileno(): listener} #用监听套接字的文件描述符作为字典的键 addresses = {} bytes_received = {} bytes_to_send = {} poll_object = select.poll() #注意:Windows系统只支持select.select() poll_object.register( listener, select.POLLIN) #向poll对象注册listener监听套接字,以监视它的【POLLIN事件】 while True: #事件监视循环 for fd, event in poll_object.poll( ): #fd是文件描述符,event是事件掩码;poll()类似selectors模块的sel.select()方法 sock = sockets[fd] #先从sockets字典中获得sock套接字对象 if event & (select.POLLHUP | select.POLLERR | select.POLLNVAL): address = addresses.pop(sock) #从字典中弹出sock键,返回sock键对应的值 rb = bytes_received.pop(sock, b'') sb = bytes_to_send.pop(sock, b'') if rb: print('client {} sent {} but then closed'.format( address, rb)) elif sb: print('client {} closed before we sent {}'.format( address, sb)) else: print('client {} closed socket normally'.format(address)) poll_object.unregister(fd) del sockets[fd] elif sock is listener: #这段elif块结束后,会不会直接执行下面的select.POLLIN块??因为监听套接字注册的事件就是“select.POLLIN”??但是监听套接字是无法使用下面的sock.recv()方法的?? sock, address = sock.accept() #把左边的sock改成conn,以避免歧义?? print('accepted connection from {}'.format(address)) sock.setblocking(False) sockets[sock.fileno()] = sock #将连接套接字添加进sockets字典中 addresses[sock] = address #将连接套接字的远端地址添加进address字典中 poll_object.register( sock, select.POLLIN) #向poll对象注册sock连接套接字,以监视它的【POLLIN事件】 elif event & select.POLLIN: more_data = sock.recv(4096) if not more_data: sock.close() continue data = bytes_received.pop(sock, b'') + more_data if data.endswith(b'?'): bytes_to_send[sock] = zen_utils.get_answer(data) poll_object.modify(sock, select.POLLOUT) else: bytes_received[sock] = data elif event & select.POLLOUT: data = bytes_to_send.pop(sock) n = sock.send(data) if n < len(data): bytes_to_send[sock] = data[n:] else: poll_object.modify(sock, select.POLLIN)
def server(listener): sockets = { listener.fileno(): listener } # listener.fileno() 返回一个文件描述符用于底层io操作 文件描述符: 套接字 addresses = {} bytes_received = {} # 接收缓冲区 bytes_to_send = {} # 发送缓冲区 poll_object = select.poll() # posix select 返回一个 fd_set 数据结构 poll_object.register(listener, select.POLLIN) # 注册监听套接字 默认为 poll input 模式 for fd, event in all_events_forever(poll_object): sock = sockets[fd] # socket closed: remove it from our data structures. if event & (select.POLLHUP | select.POLLER | select.PLLNVAL): address = addresses.pop(sock) rb = bytes_received.pop(sock, b'') sb = bytes_to_send.pop(sock, b'') if rb: print("client {} send {} but then closed".format(address, rb)) elif sb: print("client {} closed before we sent {}".format(address, sb)) else: print("clint {} closed socket normally".format(address)) poll_object.unregister(fd) del sockets[fd] # new socket: add it to our data structures. elif sock is listener: sock, address = sock.accept() print("accepted connection from {}".format(address)) sock.setblocking(False) # force socket.timeout if we blunder sockets[sock.fileno()] = sock # 把套接字文件描述符和套接字本身做字典映射 addresses[sock] = address # 把套接字名在字典做映射 poll_object.register( sock, select.POLLIN) # 在 fd_set 数据结构中注册当前套接字并设定 poll in 状态 # incoming data: keep receiving until we see the suffix elif event & select.POLLIN: more_data = sock.recv(4096) if not more_data: # end of file sock.close() # next poll() will POLLNVAL, and thus clean up continue data = bytes_received.pop(sock, b'') + more_data if data.endswith(b'?'): bytes_to_send[sock] = zen_utils.get_answer(data) poll_object.modify(sock, select.POLLOUT) else: bytes_received[sock] = data # socket ready to send: keep sending until all bytes are delivered. elif event & select.POLLOUT: data = bytes_to_send.pop(sock) n = sock.send(data) if n < len(data): bytes_to_send[sock] = data[n:] else: poll_object.modify(sock, select.POLLIN)
def server(listener): sockets = {listener.fileno(): listener} address = {} bytes_recieved = {} bytes_to_send = {} poll_object = select.poll() poll_object.register(listener, select.POLLIN) for fd, event in all_events_forever(poll_object): sock = sockets[fd] if event & (select.POLLHUP | select.POLLERR | select.POLLNVAL): address = address.pop(sock) rb = bytes_recieved.pop(sock, b'') sb = bytes_to_send(sock, b'') if rb: print(f"client {address} sent {rb} but then closed") elif sb: print(f"client {address} closed before we sent {sb}") else: print(f"client {address} closed normally") poll_object.unregister(fd) del sockets[fd] elif sock is listener: sock, address = sock.accept() print(f"accept connection from: {address}") sock.setblocking(False) sockets[sock.fileno()] = sock poll_object.register(sock, select.PULLIN) elif event & select.POLLIN: more_data = sock.recv(4096) if not more_data: sock.close() continue data = bytes_recieved.pop(sock, b'') + more_data if data.endswith(b"?"): bytes_to_send[sock] = zen_utils.get_answer(data) poll_object.modify(sock, select.POLLOUT) else: bytes_recieved[sock] = data elif event & select.POLLOUT: data = bytes_to_send.pop(sock) n = sock.send(data) if n < len(data): bytes_to_send[sock] = data[n:] else: poll_object.modify(sock, select.POLLIN)
def serve(listener): sockets = {listener.fileno(): listener} addresses = {} bytes_received = {} bytes_to_send = {} poll_object = select.poll() poll_object.register(listener, select.POLLIN) for fd, event in all_events_forever(poll_object): sock = sockets[fd] if event & (select.POLLHUP | select.POLLERR | select.POLLNVAL): address = addresses.pop(sock) rb = bytes_received.pop(sock, b'') sb = bytes_to_send.pop(sock, b'') if rb: print('client {} send {} but then closed'.format(address, rb)) elif sb: print('client {} closed before we sent {}'.format(address, sb)) else: print('client {} closed socket normally'.format(address)) poll_object.unregister(fd) del sockets[fd] elif sock is listener: sock, address = sock.accept() print('accepted connection from {}'.format(address)) sock.setblocking(False) sockets[sock.fileno()] = sock addresses[sock] = address poll_object.register(sock, select.POLLIN) elif event & select.POLLIN: more_data = sock.recv(4096) if not more_data: sock.close() continue data = bytes_received.pop(sock, b'') + more_data if data.endswith(b'?'): bytes_to_send[sock] = zen_utils.get_answer(data) poll_object.modify(sock, select.POLLOUT) else: bytes_received[sock] = data elif event & select.POLLOUT: data = bytes_to_send.pop(sock) n = sock.send(data) if n < len(data): bytes_to_send[sock] = data[n:] else: poll_object.modify(sock, select.POLLIN)
async def handle_conversation(reader, writer): """负责一个连接套接字的会话""" address = writer.get_extra_info( 'peername') #获取writer对象的底层连接套接字的远端地址,即发出该次请求的客户端的地址 print('accepted connection from {}'.format(address)) while True: #持续【接收问题,发送答案】的循环,直到客户端关闭连接套接字为止 try: data = await reader.readuntil(b'?') #从接收缓冲区持续读取字节串,直到遇到【?】为止 except asyncio.IncompleteReadError: #如果遇到了EOF信号,即远端关闭了套接字,则退出协程函数 break answer = zen_utils.get_answer(data) writer.write(answer) #将答案写入发送缓冲区 await writer.drain() #控制write()方法写入的流量 print('close the connection') writer.close() #关闭writer底层的服务器连接套接字
def handle_conversation(reader, writer): address = writer.get_extra_info('peername') print("accepted connection from {}".format(address)) while True: data = b'' while not data.endswith(b"?"): more_data = yield from reader.read(4096) if not more_data: if data: print("client {} sent {!r} but then closed".format(address, data)) else: print("client {} closed socket normally".format(address)) return data += more_data answer = zen_utils.get_answer(data) writer.write(answer)
def handle_conversation(reader, writer): address = writer.get_extra_info('peername') print(f"accept connection from:{address}") while True: data = b'' while not data.endswith(b"?"): more_data = yield from reader.read(4096) if not more_data: if data: print(f"client :{address} sent {repr(data)} but closed") else: print(f"client:{address} closed socket normally") return data += more_data answer = zen_utils.get_answer(data) writer.write(answer)
def handle_conversation(reader, writer): address = writer.get_extra_info('peername') print('Accepted connection from {}'.format(address)) while True: data = b'' while not data.endswith(b'?'): more_data = yield from reader.read() if not more_data: if data: print('Client {} sent {!r} but then closed' .format(address, data)) else: print('Client {} closed socket normally'.format(address)) return data += more_data answer = zen_utils.get_answer(data) writer.write(answer)
def handle_conversation(reader, writer): address = writer.get_extra_info('peername') print('Accepted connection from {}'.format(address)) while True: data = b'' while not data.endswith(b'?'): more_data = yield from reader.read( 4096) # 通过yield from来进行中断,因为这里由于接受可能会产生中断 if not more_data: if data: print('Client {} sent {!r} but then closed'.format( address, data)) else: print('Client {} closed socket normally'.format(address)) return data += more_data answer = zen_utils.get_answer(data) writer.write(answer)
def data_received(self, data): self.data += data if self.data.endswith(b'?'): answer = zen_utils.get_answer(self.data) self.transport.write(answer) self.data = b''
def found_terminator(self): answer = zen_utils.get_answer(self.data + b'?') self.push(answer) self.initiate_send() self.data = b''
def server(listener): # 获取已经准备好进行后续通信的文件描述符,并放入字典中以便之后查询 sockets = {listener.fileno(): listener} # 获取监听套接字的文件描述符 addresses = {} # 用于保存每个与客户端连接的专用套接字 # 在等待某个请求完成时, 会将收到的数据存储在bytes_received字典中 bytes_received = {} # 在等待OS安排发送数据时,将要发送的字节存储在bytes_to_send字典中 bytes_to_send = {} poll_object = select.poll() # select.poll() 返回一个polling对象,支持registering和unregistering file # descriptors, 然后 polling them for I/O events. poll_object.register(listener, select.POLLIN) # (1)准备连接的客户端首先将它自身视作服务器监听套接字的一个事件,要始终将该事件 # 设为POLLIN(poll in)状态. 接下来见 elif sock is listener:行注释 for fd, event in all_events_forever(poll_object): sock = sockets[fd] # Socket closed: remove it from our data structures. if event & (select.POLLHUP | select.POLLERR | select.POLLNVAL): # (5) 如果客户端套接字返回了错误信息或者是关闭状态,就将该客户端套接字及其 # 发送缓冲区域接收缓冲区丢弃. 至此,我们至少已经完整地完成了众多可能同时 # 进行的会话中的一个 # POLLHUP: hung up 挂起 # POLLERR: Error condition of some sort 错误条件 # POLLNVAL: invalid request: descriptor not open 无效请求 address = addresses.pop(sock) rb = bytes_received.pop(sock, b'') sb = bytes_to_send.pop(sock, b'') if rb: print('Client {} sent {} but then closed'.format(address, rb)) elif sb: print('Client {} closed before we sent {}'.format(address, sb)) else: print('Client {} closed socket normally'.format(address)) poll_object.unregister(fd) # 移除文件描述符 del sockets[fd] # New socket: add it to our data structures. elif sock is listener: # (1) 响应此类事件的方法就是运行accept().将返回的套接字及其地址存储在字典内, # 并通过register()方法告知poll()对象,已经准备好从新返回的客户端套接字 # 接收数据了. sock, address = sock.accept() print('Accepted connection from {}'.format(address)) sock.setblocking(False) # force socket.timeout if we blunder sockets[sock.fileno()] = sock addresses[sock] = address # 将服务器分配的用于和客户端连接的套接字 # 关联起来并存储在字典中. poll_object.register(sock, select.POLLIN) # 准备好接收数据 # Incoming data: keep receiving until we see the suffix elif event & select.POLLIN: # (2)当套接字本身就是客户端套接字,并且时间类型为POLLIN时,就能使用recv() # 方法最多接收4KB数据了. more_data = sock.recv(4096) # 如果没有收到数据, 表示客户端发送的是 b'',客户端结束连接.那么服务器 # 也要关闭这个与相应客户端连接的套接字. 然后继续下次循环. if not more_data: # end-of-file sock.close() # next poll() will POLLNVAL , and thus clean up continue data = bytes_received.pop(sock, b'') + more_data # 收到了一个完整的问题,可以处理该客户端请求,并将结果保存到bytes_received # 字典中. 然后将套接字的模式从POLLIN 切换到POLLOUT. POLLIN模式表示要接收 # 更多的数据,而POLLOUT模式则表示在发送缓冲区空闲时立刻通知系统 . # POLLOUT mode, where you want to be notified as soon as the # outgoing buffers are free because you are now using the socket # to send instead of receive. if data.endswith(b'?'): bytes_to_send[sock] = zen_utils.get_answer(data) poll_object.modify(sock, select.POLLOUT) else: # 如果还没有收到表示帧尾的问号字符,那么就将数据保存到 bytes_received # 字典中, 并返回至循环顶部,进行下一个poll()调用. bytes_received[sock] = data # Socket ready to send: keep sending until all bytes are delivered. elif event & select.POLLOUT: # (3) The poll() call now notifies you immediately with POLLOUT # whenever the outging buffers on the client socket can accept # at least one byte, and you respond by attempting a send() of # everything you have left to transmit and by keeping only the # bytes that send() could not squeeze into the outgoing buffers. data = bytes_to_send.pop(sock) n = sock.send(data) if n < len(data): bytes_to_send[sock] = data[n:] else: # (4)如果套接字模式为POLLOUT, 并且send()完成了所有数据的发送, 那么 # 此时就完成了一个完整的请求-响应循环, 因此套接字将模式切换回POLLIN, # 用于下一个请求. poll_object.modify(sock, select.POLLIN)
def server(listener, certfile): #套接字列表,fileno()返回套接字的文件描述符(一个小整数) context = zen_utils.ssl_context(certfile, cafile=None) listener = context.wrap_socket(listener, server_side=True) sockets = {listener.fileno(): listener} addresses = {} #两个缓冲队列用于接收和发送 bytes_received = {} bytes_to_send = {} #返回一个轮询对象,该对象支持注册和注销文件描述符,然后对它们进行轮询以获取I / O事件 poll_object = select.poll() #向轮询对象注册文件描述符,然后用poll()函数检查文件描述符是否具有任何未决的I / O事件,下面是注册监听套接字文件描述符 poll_object.register(listener, select.POLLIN) for fd, event in all_events_forever(poll_object): sock = sockets[fd] #判断是不是客户端是不是关了或发生了错误或是无效请求 if event & (select.POLLHUP | select.POLLERR | select.POLLNVAL): address = addresses.pop(sock) rb = bytes_received.pop(sock, b'') sb = bytes_to_send.pop(sock, b'') if rb: print('客户端{}发送{}但服务器已关闭'.format(address, rb)) elif sb: print('服务器发送{}但客户端{}已关闭'.format(address, sb)) else: print('客户端{}套接字正常关闭'.format(address)) poll_object.unregister(fd) del sockets[fd] #如果取出的套接字是监听套接字 elif sock is listener: sock, address = sock.accept() print('接受客户端{}连接'.format(address)) # 在默认认的情况下,TCP套节字处于阻塞模式中。 # 换句话说,如果没有完成操作,就不把控制权交给程序。 # 很多情况下,你并不想让程序等待服务器响应或者有异常终止操作,所以设置非阻塞模式。 sock.setblocking(False) #把建立的服务器套接字放入套接字列表中 sockets[sock.fileno()] = sock #把接收到的客户端套接字地址放入地址列表中 addresses[sock] = address #注册该服务器套接字,以供poll()调用 poll_object.register(sock, select.POLLIN) #判断该套接字位掩码event是不是POLLIN elif event & select.POLLIN: more_data = sock.recv(1024) if not more_data: sock.close() continue data = bytes_received.pop(sock, b'') + more_data if data.endswith(b','): #如果信息传输完成,把数据保存在发送缓冲队列中,并把该套接字事件设为select.POLLOUT输出 bytes_to_send[sock] = zen_utils.get_answer(data) poll_object.modify(sock, select.POLLOUT) else: #如果只接收了部分数据,把该数据保存到接收缓冲队列中 bytes_received[sock] = data #判断该套接字位掩码event是不是POLLOUT elif event & select.POLLOUT: #把数据从发送缓冲队列中弹出并发送,并把事件设置为select.POLLIN输入 data = bytes_to_send.pop(sock) n = sock.send(data) if n < len(data): bytes_to_send[sock] = data[n:] else: poll_object.modify(sock, select.POLLIN)
#Asynchronous I/O inside "asyncio" callback methods. import asyncio, zen_utils class ZenServer(asyncio.Protocol): def connection_made(self, transport): self.transport = transport self.address = transport.get_extra_info('peername') self.data = b'' print('Accepted connection from {}'.format(self.address)) def data_received(self, data); self.data += data if self.data.endswith(b'?'): answer = zen_utils.get_answer(self.data) self.transport.write(answer) self.data = b'' def connection_lost(self, exc): if exc: print('Client {} error: {}'.format(self.address, exc)) elif self.data; print('Client {} sent {} but then closed' .format(self.address, self.data)) else: print('Client {} closed socket'.format(self.address)) if __name__ == '__main__': address = zen_utils.parse_command_line('asyncio server using callbacks') loop = asyncio.get_event_loop()