在开发一个 HTTP 代理时,我遇到了一个问题:当服务器连接断开时,HTTP 通道的 Channel 属性会被意外地设置为 None,导致后续的操作引发错误。在深入调查后,我发现这是因为在调用 loseConnection() 方法关闭连接之前,Channel 属性就被设置为了 None。这导致了代码中对 Channel 属性的访问报错,提示 None 对象没有 transport 属性。
下面是异常信息:
Traceback (most recent call last):
File "C:\Program Files\Python 2.6.2\lib\site-packages\wx-2.8-msw-unicode\wx_core.py", line 7303, in MainLoop
return _core_.PyApp_MainLoop(*args, **kwargs)
File "C:\Program Files\Python 2.6.2\lib\site-packages\wx-2.8-msw-unicode\wx_core.py", line 14640, in <lambda>
lambda event: event.callable(*event.args, **event.kw) )
File "C:\Program Files\Python 2.6.2\lib\site-packages\twisted\internet_threadedselect.py", line 243, in _interleave
getattr(self, '_process_' + msg)(*args)
File "C:\Program Files\Python 2.6.2\lib\site-packages\twisted\internet_threadedselect.py", line 209, in _process_Notify
_logrun(selectable, _drdw, selectable, method, dct)
--- <exception caught here> ---
File "C:\Program Files\Python 2.6.2\lib\site-packages\twisted\python\log.py", line 84, in callWithLogger
return callWithContext({"system": lp}, func, *args, **kw)
File "C:\Program Files\Python 2.6.2\lib\site-packages\twisted\python\log.py", line 69, in callWithContext
return context.call({ILogContext: newCtx}, func, *args, **kw)
File "C:\Program Files\Python 2.6.2\lib\site-packages\twisted\python\context.py", line 59, in callWithContext
return self.currentContext().callWithContext(ctx, func, *args, **kw)
File "C:\Program Files\Python 2.6.2\lib\site-packages\twisted\python\context.py", line 37, in callWithContext
return func(*args,**kw)
File "C:\Program Files\Python 2.6.2\lib\site-packages\twisted\internet_threadedselect.py", line 303, in _doReadOrWrite
self._disconnectSelectable(selectable, why, method == "doRead")
File "C:\Program Files\Python 2.6.2\lib\site-packages\twisted\internet\posixbase.py", line 253, in _disconnectSelectable
selectable.connectionLost(f)
File "C:\Program Files\Python 2.6.2\lib\site-packages\twisted\internet\tcp.py", line 677, in connectionLost
Connection.connectionLost(self, reason)
File "C:\Program Files\Python 2.6.2\lib\site-packages\twisted\internet\tcp.py", line 519, in connectionLost
protocol.connectionLost(reason)
File "C:\Program Files\Python 2.6.2\lib\site-packages\twisted\web\http.py", line 489, in connectionLost
self.handleResponseEnd()
File "C:\Documents and Settings\Admin\My Documents\Mercurial\sharky\ProxyServer.py", line 103, in handleResponseEnd
p.channel.transport.loseConnection()
exceptions.AttributeError: 'NoneType' object has no attribute 'transport'
2、解决方案
要解决这个问题,我们需要在调用 loseConnection() 方法关闭连接之前,先检查 Channel 属性是否为 None。如果为 None,则无需再次调用 loseConnection() 方法,因为连接已经断开。
经过分析,我发现问题出在以下代码中:
for p in self.producers:
p.channel.transport.loseConnection()
在循环中,我尝试关闭所有生产者 (producer) 的连接。然而,在某些情况下,p.channel 可能已经被设置为 None 了,导致 p.channel.transport.loseConnection() 调用失败。
为了解决这个问题,我修改了代码,增加了对 p.channel 的检查:
for p in self.producers:
if p.channel:
p.channel.transport.loseConnection()
现在,只有当 p.channel 不为 None 时,才会调用 loseConnection() 方法关闭连接。这样可以确保不会在连接已经断开的情况下再次调用 loseConnection() 方法,从而避免了错误的发生。
修正后的代码如下:
self.connectionDone = True
print self.producers
for p in self.producers:
print p
print p.channel
print dir(p)
if p.channel:
p.channel.transport.loseConnection()
self.transport.loseConnection()
经过修改后,程序能够正确关闭所有连接,不再出现错误。