python 实现 TCPServer

2014-12-18 14:31:36 +08:00
 sbmzhcn
用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,有选择的发送数据。

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

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

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

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

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

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

目前如果按照我上面的代码,如何实现把每个连接放在一个列表里,并且可以随时操作其中一个连接。当前连接应该包含设备的id, ip, 等一些信息。
wog
2014-12-18 18:05:01 +08:00
没用python处理过这么底层的东西,其实做到这么底层了,如果不打算用python现成的三方库,建议直接用c吧,你说的这些用c实现比python复杂不了多少,使用epull模型,可以很方便的实现你要的功能,甚至用c处理链接,然后把数据给python处理也行
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
2014-12-18 18:26:51 +08:00
这个属于设计模式的范围了。
用个全局的字典存id和Handler的对应,每个Handler里有2个队列接收一个发送一个,然后一个死循做读写。。
对某个id发送数据只需要在全局字典里面找到Handler,然后往队列里面丢就行了。
pubby
2014-12-18 18:29:55 +08:00
一台搞不定也没必要死磕嘛,入口IP上做轮询转发到后端多个服务器即可
datou552211
2014-12-18 23:19:27 +08:00
感觉golang适合你的需求
bugeye
2014-12-19 09:28:33 +08:00
nodejs天生就是为了你这种情况而生的。
sbmzhcn
2014-12-20 21:58:22 +08:00
@mengzhuo 非常感谢你的代码,能具体再和我说说这段代码吗?

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

这段代码是不是必须会超时。我需要服务器一直不停的接收,不中断,但我测试你的代码,无论怎么样总会超时。
mengzhuo
2014-12-20 22:42:20 +08:00
@sbmzhcn
我主要是告诉你参考而已,不必照着用的。
有timeout,因为应用场景是smtp服务器,所以不能老是让client占用channel(因为邮件一般比较大,小则100K,大的有10M)
rcmerci
2014-12-21 22:11:23 +08:00
上erlang

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/154857

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX