python 实现 TCPServer - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
sbmzhcn
V2EX    Python

python 实现 TCPServer

  •  
  •   sbmzhcn 2014-12-18 14:31:36 +08:00 9858 次点击
    这是一个创建于 4028 天前的主题,其中的信息可能已经有所发展或是发生改变。
    用Python写了一个简单的TCPServer,放到一台Linux服务器上,目前可以从设备通过TCP连接接收十六进制消息.
    我的最终目的是使得TCPServer能够接收上万台设备发来的十六进制消息,然后解析并存到数据库里。
    当然目前仅仅需要接收几台设备的信息,但现在遇到了一些问题:
    (设备都用DTU代替,放在服务器上的脚本用DSC代替)
    1、 当多个DTU向DSC建立链接并发送数据包时,需要把当前连接保存起来,并最好有一个序号,保存到dtu_list中。当该连接断开时可以从dtu_list中根据序号删除。
    2、 这是一个基本的示例 https://docs.python.org/2/library/socketserver.html#SocketServer.BaseServer.RequestHandlerClass
    ,但实际情形比这复杂多。 在ThreadedTCPServer中能不能根据当前连接的ID,有选择的发送数据。

    大家如果有这方面的编程例子,感谢能提供一个链接或者参考。
    29 条回复    2014-12-30 13:25:53 +08:00
    mengskysama
        1
    mengskysama  
       2014-12-18 14:59:47 +08:00
    你用ThreadedTCPServer这种线程模型上万台设备肯定不行,现在你几台OK,随着设备数量增多线程将会变多,整个程序效率就会更低,线程模型如果有大量的锁,这个问题变得更复杂,这就是现在基本上没有高并发Server会使用这种模型的原因。

    python线程数量是有限制的,在win下面甚至不能超过1K,考虑最坏的情况如果有1K个设备同时建立连接,更多的设备心跳就接收不到。
    EPr2hh6LADQWqRVH
        2
    EPr2hh6LADQWqRVH  
       2014-12-18 15:06:53 +08:00
    官方文档的参考还不够吗?
    官方的smtpd代码可以看一下,就是实例之一。
    nbndco
        3
    nbndco  
       2014-12-18 15:07:25 +08:00
    zeromq?
    mengskysama
        4
    mengskysama  
       2014-12-18 15:10:43 +08:00
    别用这货了,现在成熟的异步框架多了去了tornodo twisted之类的...
    mengzhuo
        5
    mengzhuo  
       2014-12-18 15:31:48 +08:00
    同楼上smtpd,可以理解基本思路
    如果上异步的话可以试试我写的gsmtpd

    https://github.com/34nm/gsmtpd

    C10K 下 最多7000RPS 一个进程 楼主想更高的话只能上multiprocess了,更高的话找LVS HAPROXY之类的吧
    myrual
        6
    myrual  
       2014-12-18 15:37:08 +08:00
    如果你的业务逻辑就是建立设备连接的时候开始创建一个记录,然后不断把设备上发的数据存起来,然后链接断开的时候把它删除掉,我建议你直接用twisted就可以。自带的例程就可以帮助你搞定这件事情。

    记住打开epoll模式,可以把性能提升很多。
    但是twisted里面不要想当然的呼叫引发阻塞的操作,比如数据库写,sleep,io等等,因为如果你需要一个这样的操作,需要查手册里面对于这种需求的对应方案。

    如果你不习惯这种编程模式,我建议你使用go 写一个,学习难度和你学twisted 差不多,但是至少你可以用线性的思维写一个性能不错的tcp 服务器。
    myrual
        7
    myrual  
       2014-12-18 15:39:45 +08:00
    还有一个能用的东西叫做 gevent,也不错。
    20150517
        8
    20150517  
       2014-12-18 15:54:48 +08:00 via Android
    上万台设备,你得用cassandra,否则怎么撑的住?
    mengskysama
        9
    mengskysama  
       2014-12-18 16:17:08 +08:00
    @myrual
    其实有很多一部实现已经是别人造好的了
    https://github.com/hybridlogic/txMySQL
    Go的实现类似gevent?
    zaxaca
        10
    zaxaca  
       2014-12-18 16:48:34 +08:00
    用twisted吧,用起来相当不错,性能也够用!
    sbmzhcn
        11
    sbmzhcn  
    OP
       2014-12-18 17:22:55 +08:00
    非常感谢大家的回复, 看到大家的回复都比较专业,看来这样的应用还是应该花钱让公司找人去做,目前并不太可能有超过上百个设备的,那是以后的事了,现在这个问题还没有很好的解决,实现的过程很简陋,虽然也能接收数据,发送数据但感觉不太优雅。

    目前如果按照我上面的代码,如何实现把每个连接放在一个列表里,并且可以随时操作其中一个连接。当前连接应该包含设备的id, ip, 等一些信息。
    wog
        12
    wog  
       2014-12-18 18:05:01 +08:00
    没用python处理过这么底层的东西,其实做到这么底层了,如果不打算用python现成的三方库,建议直接用c吧,你说的这些用c实现比python复杂不了多少,使用epull模型,可以很方便的实现你要的功能,甚至用c处理链接,然后把数据给python处理也行
    leyle
        13
    leyle  
       2014-12-18 18:25:14 +08:00
    select() 一般不超过 1024 个文件描述符,先天限制了不可能支持大并发。

    想要支持成千上万个客户端,你是在 linux 上写的程序,这个时候,你需要 epoll 来处理 I/O 多路复用的问题,然后你再考虑用多线程或者多进程来处理你的业务逻辑。

    你可以参考这个

    [[翻译]python调用linux epoll编程指南 - 遗落岛]
    http://www.leyle.com/archives/how_to_use_linux_epoll_with_python.html
    mengskysama
        14
    mengskysama  
       2014-12-18 18:26:51 +08:00
    这个属于设计模式的范围了。
    用个全局的字典存id和Handler的对应,每个Handler里有2个队列接收一个发送一个,然后一个死循做读写。。
    对某个id发送数据只需要在全局字典里面找到Handler,然后往队列里面丢就行了。
    pubby
        15
    pubby  
       2014-12-18 18:29:55 +08:00
    一台搞不定也没必要死磕嘛,入口IP上做轮询转发到后端多个服务器即可
    datou552211
        16
    datou552211  
       2014-12-18 23:19:27 +08:00 via iPhone
    感觉golang适合你的需求
    bugeye
        17
    bugeye  
       2014-12-19 09:28:33 +08:00
    nodejs天生就是为了你这种情况而生的。
    sbmzhcn
        18
    sbmzhcn  
    OP
       2014-12-20 21:58:22 +08:00
    @mengzhuo 非常感谢你的代码,能具体再和我说说这段代码吗?

    with Timeout(self.timeout, ConnectionTimeout):
    sc = DSCChannel(self, sock, addr, self.data_size_limit)

    这段代码是不是必须会超时。我需要服务器一直不停的接收,不中断,但我测试你的代码,无论怎么样总会超时。
    mengzhuo
        19
    mengzhuo  
       2014-12-20 22:42:20 +08:00   1
    @sbmzhcn
    我主要是告诉你参考而已,不必照着用的。
    有timeout,因为应用场景是smtp服务器,所以不能老是让client占用channel(因为邮件一般比较大,小则100K,大的有10M)
    rcmerci
        20
    rcmerci  
       2014-12-21 22:11:23 +08:00
    上erlang
    sbmzhcn
        21
    sbmzhcn  
    OP
       2014-12-22 22:14:07 +08:00
    @mengzhuo 再次提问,不好意思。在示例process_message 中的 process_message, 我如果直接把数据写入mysql会不会出现问题,比如性能问题?
    sbmzhcn
        22
    sbmzhcn  
    OP
       2014-12-22 22:16:37 +08:00
    class DebuggingServer(SMTPServer):
    # Do something with the gathered message
    def process_message(self, peer, mailfrom, rcpttos, data):
    inheaders = 1
    lines = data.split('\n')
    print '---------- MESSAGE FOLLOWS ----------'
    for line in lines:
    # headers first
    if inheaders and not line:
    print 'X-Peer:', peer[0]
    inheaders = 0
    print line
    print '------------ END MESSAGE ------------'

    指以上代码中。
    mengzhuo
        23
    mengzhuo  
       2014-12-22 22:41:13 +08:00   1
    @sbmzhcn 看你用什么Mysql驱动了
    如果是gevent patch之后的话 某些Mysql驱动应该会实现移步了

    性能问题是很多方面的,你先做一个能跑的版本,再慢慢调优吧
    sbmzhcn
        24
    sbmzhcn  
    OP
       2014-12-22 23:54:39 +08:00 via iPhone
    @mengzhuo 现在已经能跑了,各方面都测试没问题,就差最后的存储数据了。python操作mysql还不清楚哪个好,想用上面有人推荐的txmysql,不知道怎么和你这结合。你有什么推荐的吗?
    sbmzhcn
        25
    sbmzhcn  
    OP
       2014-12-24 09:10:47 +08:00
    @mengzhuo 能帮我回答下上面的问题吗,再次感谢!
    mengzhuo
        26
    mengzhuo  
       2014-12-24 09:31:56 +08:00
    @sbmzhcn

    我不用Mysql。。。。所以不知道
    sbmzhcn
        27
    sbmzhcn  
    OP
       2014-12-24 12:49:18 +08:00
    @mengzhuo 谢谢了,无论什么数据库都行的,就是存储这块。
    sbmzhcn
        28
    sbmzhcn  
    OP
       2014-12-24 14:02:27 +08:00
    @mengskysama 有这方面的代码没?
    wuyadong
        29
    wuyadong  
       2014-12-30 13:25:53 +08:00
    存手工写异步的tcpserver,好麻烦的说...找到一个非阻塞的TCPServer的DEMO
    https://github.com/JobsDong/SimpleServer
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5530 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 44ms UTC 01:48 PVG 09:48 LAX 17:48 JFK 20:48
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86