tornado的IOLoop用于tcp通信

news/2024/7/9 16:18:56 标签: 网络, epoll, python

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

之前的是使用原始的socket然后add_handler加入fd到ioloop监听, 其实tornado提供了更高级的抽象, TCPServer和IOStream

服务器代码

python">#! /usr/bin/env python
#coding=utf-8
  
from tornado.tcpserver import TCPServer  
from tornado.ioloop  import IOLoop  
  
class Connection(object):  
    clients = set()  
    def __init__(self, stream, address): 
        Connection.clients.add(self) 
        self._stream = stream  
        self._address = address  
        self._stream.set_close_callback(self.on_close)  
        self.read_message()  
        print "A new user has entered the chat room.", address 
      
    def read_message(self):  
        self._stream.read_until('\n', self.broadcast_messages)  
  
    def broadcast_messages(self, data):  
        print "User said:", data[:-1], self._address
        for conn in Connection.clients:  
            conn.send_message(data)  
        self.read_message()  
      
    def send_message(self, data):  
        self._stream.write(data) 
          
    def on_close(self):  
        print "A user has left the chat room.", self._address
        Connection.clients.remove(self)  
  
class ChatServer(TCPServer):  
    def handle_stream(self, stream, address): 
        """当连接到来时,这个函数被调用,传入stream(IOStream对象, 而不是原始的fd)和address,
        之后就可以用IOStream对象方法收发消息了
        """
        print "New connection :", address, stream 
        Connection(stream, address) 
        print "connection num is:", len(Connection.clients)
  
if __name__ == '__main__':  
    print "Server start ......"  
    server = ChatServer()  
    server.listen(8000)  
    IOLoop.instance().start()

------------------------------2014-4-12整理在上面-----------------------------

据说tornado的IOLoop用于tcp服务性能要比twisted还高
参照 ioloop.py

监听的epoll events

python"># Our events map exactly to the epoll events <IOLoop.XXXX>)
NONE = 0
READ = _EPOLLIN
WRITE = _EPOLLOUT
ERROR = _EPOLLERR | _EPOLLHUP

三个用于tcp网络编程的接口

python">def add_handler(self, fd, handler, events):
    """Registers the given handler to receive the given events for fd.

    The ``events`` argument is a bitwise or of the constants
    ``IOLoop.READ``, ``IOLoop.WRITE``, and ``IOLoop.ERROR``.

    When an event occurs, ``handler(fd, events)`` will be run.
    """
    raise NotImplementedError()

def update_handler(self, fd, events):
    """Changes the events we listen for fd."""
    raise NotImplementedError()

def remove_handler(self, fd):
    """Stop listening for events on fd."""
    raise NotImplementedError()


下面是一个echo server

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

import Queue
import socket

from functools import partial
from tornado.ioloop import IOLoop

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 关闭程序释放端口
sock.setblocking(0)              # 将socket设置为非阻塞

server_address = ("127.0.0.1", 9999)

sock.bind(server_address)
sock.listen(20)

fd_map = {}              # 文件描述符到socket的映射
message_queue_map = {}   # socket到消息队列的映射

fd = sock.fileno()
fd_map[fd] = sock

ioloop = IOLoop.instance()

def handle_client(fd, event, cli_addr):
    s = fd_map[fd]
    if event & IOLoop.READ:
        data = s.recv(1024)
        if data:
            print "Received %r from %s" % (data, cli_addr)
            # 接收到消息更改事件为写, 用于发送数据到对端
            ioloop.update_handler(fd, IOLoop.WRITE)
            message_queue_map[s].put(data)
        else:
            print "Closing %s" % cli_addr
            ioloop.remove_handler(fd)
            s.close()
            del message_queue_map[s]

    if event & IOLoop.WRITE:
        try:
            next_msg = message_queue_map[s].get_nowait()
        except Queue.Empty:
            print "%s queue empty" % cli_addr
            ioloop.update_handler(fd, IOLoop.READ)
        else:
            print "Sending %s to %s" % (next_msg, cli_addr)
            s.send(next_msg)

    if event & IOLoop.ERROR:
        print "Exception on %s" % cli_addr
        ioloop.remove_handler(fd)
        s.close()
        del message_queue_map[s]

"""把socket加入ioloop循环监听是否有READ(可读即有连接)事件到来,如果有则接受连接"""
def handle_server(fd, event):
    s = fd_map[fd]
    if event & IOLoop.READ:
        conn, cli_addr = s.accept()
        conn.setblocking(0)
        conn_fd = conn.fileno()
        fd_map[conn_fd] = conn
        handle = partial(handle_client, cli_addr="%s:%d" % (cli_addr))   # 将cli_addr作为默认参数
        # 将连接和handle注册为读事件加入到 tornado ioloop
        ioloop.add_handler(conn_fd, handle, IOLoop.READ)
        message_queue_map[conn] = Queue.Queue()   # 创建对应的消息队列


ioloop.add_handler(fd, handle_server, IOLoop.READ)

ioloop.start()


转载于:https://my.oschina.net/1123581321/blog/170682


http://www.niftyadmin.cn/n/853311.html

相关文章

在mips平台编译bazel源码

在mips平台编译bazel源码 描述&#xff1a;在mips上使用tensorflow&#xff0c;面临必须编译源码&#xff0c;编译之前不得不编译tensorflow依赖的编译器bazel.本人试过cmake编译bazel(但由于最终会用docker编译&#xff0c;无疑这方法行不通)&#xff0c;无赖之下只能执行 co…

互联网公司面试必问的MySQL题目(下)

什么是数据库索引&#xff1f;索引有哪几种类型&#xff1f;什么是最左前缀原则&#xff1f;索引算法有哪些&#xff1f;有什么区别&#xff1f; 索引是对数据库表中一列或多列的值进行排序的一种结构。一个非常恰当的比喻就是书的目录页与书的正文内容之间的关系&#xff0c;为…

c语言实现快速排序

C语言下的快速排序 快速排序是一种优雅的算法&#xff0c;在最坏情况下&#xff0c;Quicksort可能需要 n^2 的时间来对数组元素进行排序。而在最优的情况下&#xff0c;它将选择中值作为划分元素&#xff0c;因此只需 nlgn 次的比较就可以完成数组的配需。 快速排序的基本思想是…

《剑指offer》-- 字符串

题目描述 请实现一个函数&#xff0c;将一个字符串中的空格替换成“%20”。 例如&#xff0c;当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 分析 将长度为1的空格替换为长度为3的“%20”&#xff0c;字符串的长度变长。 如果允许我们开辟一个新的数…

TensorFlow里面mnist导入手写数据代码分析

TensorFlow里面mnist导入手写数据代码分析 本文主要介绍了Tensorflow(TF)手写识别&#xff0c;导入数据源码分析 在 tensorflow/tensorflow/examples/tutorials/mnist 目录下&#xff0c;文件树如下&#xff1a; [xzylocalhost mnist]$ tree . ├── BUILD ├── fully_…

VC++基础 判断键盘消息

头文件变量声明&#xff1a; 1 BOOL bShiftdown,bShiftup,bShiftB; 消息事件声明&#xff1a; 1 afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); 2 afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags); 3 afx_msg void OnChar(UINT nCha…

线控的原理

先前的改装文章在此http://bbs.xiaomi.com/thread-1372419-1-1.html说明线控的原理&#xff1a;接听键就是短路mic&#xff0c;很简单&#xff0c;大多数耳机都是这样做的&#xff0c;那么线控呢&#xff1f;拆开htc原装耳机后发现&#xff0c;选曲键利用了不同的电阻短接mic线…

《剑指Offer》反转链表 Python实现

一、题目描述 输入一个链表&#xff0c;反转链表后&#xff0c;输出新链表的表头。 二、解题思路 把listNode中的next改为null可以&#xff0c;但是想把listnodenull就麻烦了。因为你自己定义的listnodehead的话&#xff0c;listnodenull时head并不是空。这个也是清理对象时…