使用asyncore的总结

因为引擎的原因,逼得我用aysncore这个module 写了一个 proxyserver.  用于中转与billing服务器的数据收发. 话说一不小心,断断续续 大大小小 竟然改了大半年. 闲下来的时候,我觉得还是有必要梳理一下,免得日久遗忘了.
对比第一版和目前的版本, 我想有几个点是很重要的.

0.尽早测试,边界测试也很必要.没有环境的话,可以写测试函数,模拟调用. 不能等,等真的上了实际运行环境,你会发现测试起来会更麻烦,更困难.  貌似这是新人经常有的心理, 总以为等到后面就会容易了.

1. 要相信一些既定的现实.  asyncore 这个模块是可以用的. 但是要用对了. 不能在继承了asyncore.dispatcher 之后 不调用 它的函数.那样会遗漏一些处理.导致不确定的问题. 具体些.

myDispatcher(asyncore.dispatcher):
def   close(self):

asyncore.dispatcher.close()  #must call it.

#some code your wirttern
2. 要怀疑一些既定的现实:  也许你想不到asyncore 的模块2.2 时是好用的 但是后来2.5 到2.6 都有一些或多或少的bug.   这一点可以从google查询得知.  所以我们需要做一些修改.  比如:默认 超时时间是30S 实际上需要我们自己调整为一个合理的数值, 我最后用的是 0.1    asyncore.loop(0.1, use_poll, self.socketMap) .  不然会有响应延迟的情况.  还有一些判定socket 状态的部分.  所以我拿了python2.7 的这个asyncore 模块然后 merge了一些有用的修改.

下面列举一些遇到的一些错误和解决的方法.
1. 9  Bad File Descriptor .

这个错误实际上是没有正确关闭socket channel导致的. 而正确关闭的方法就是必须要call  asyncore.dispatcher.close()  .  你可以追踪一下代码,发现这个函数会从 socketMap 里删除当前的socket 的handle.  如果遗漏了close 的调用. 或者不正确调用close 都有可能导致这个错误的抛出.
2. Threaded aysncore loop .

asyncore 的 loop 函数不是线程的. 所以如果要独立使用这个函数, 需要自己开一个线程. 而不是直接调用,否则会阻塞主线程.  第一版我在每个进程里是共用asyncore的sockmap的. 第二版我把这些分开了,各自负责各自的,这样就不会互相影响了. 不然某个socket有问题都会触发异常.. (最后的结果其实还不是这个问题,是close没有处理好 就是没有管理好socketmap)

比如:
asyn_thread = Thread(target=self._async_loop,
args=(),
name=’%s asyncore thread’ % “proxy slave”)
#if disable mode, ignore create thread realy
asyn_thread.start()      这样就ok 了.   async_loop 函数就是用老套的loop

要注意的一点是: 这需要自己管理socketmap,  这样的话开多少个线程都没关系..  不然都用 aysncore.loop  会互相影响..
我的第一个版本就是用一个 asyncore.loop 然后当某个socket关闭的时候 会导致异常, 抛出那个  error  9  bad file descriptor . 而的糟糕是, 第一个版本里, 在proxy 没有建立好连接的时候, 会关掉所有请求的client连接. 结果就是恶性循环, 抛出异常后, 就关闭所有的  asyncore.close_all() ..  实际上需要解决的是保证 close() 被正确调用.. 然后从 asyncore.socketMap 里移除.

3. 谨慎处理一些容易抛出异常的函数.  比如: try connect 异常时要重新设置逻辑连接状态为 False..   不能再等handle_except 处理. 一般不需要自己处理这个.  默认实际上是调用 handle_close的

我在上面提到的线程函数 asyn_loop 有加上重连机制. 以便在连接中断后能处理. 恢复连接.

def _async_loop(self):
print ‘create asynloop for ‘,self
while True:
#step 1. try to ensure wasConnected
obj = self
while not obj._wasConnected:
try:
self.tryconnect()
obj._wasConnected = True
time.sleep(3)
except Exception,e:
self.close()
obj._wasConnected = False
print ‘during reconnect occur’,e
while obj._wasConnected:
use_poll = False
if hasattr(select, ‘poll’):
use_poll = True
try:
#use_poll = False #hard code . for windows select mode has been test 2011-10-21
print self._asyn,’Asyn Monitor loop is running use poll? %s’%use_poll,self.socketMap
asyncore.loop(0.1, use_poll, self.socketMap)#,count=1)
except select.error,args:
#if select.error.
from errno import EINTR
if args[0] == EINTR:
print(‘Shutdown not completely clean…’)
else:
pass
#server mode
if not self.connected:
if self.accepting:
if len(self.socketMap) ==1:
print ‘only server is running no client’,self._wasConnected
self._wasConnected = True
else:
obj._wasConnected = False
else:
obj._wasConnected = False
#ignore.

#to trigger connected = False.. 2.7 seems connected will wait handle_connect function. support logic connect state.
#which close socket should be handled by dispatcher self.
#should asyncore.close_all() ?
#self.close()
self._wasConnected = False
print  self._asyn,’Asyn Monitor Disconnect’,self.socketMap,obj.connected

总的来说,用asyncore 模块就是异步的方式,可以充分利用系统的处理能力,应该说效率还是蛮高的, 在linux上实际上是用epoll 模块. 可以支持很大的吞吐.开销也小. 就像windows上的完成端口..

Leave a comment

0 Comments.

Leave a Reply


[ Ctrl + Enter ]

click to change验证码

无觅相关文章插件