Twisted 服务器一天后崩溃

Twisted server crashes after one day

我写了一个 Udp twisted 服务器 运行 它使用以下命令:

nohup python Udpserver2.py &

一开始还不错,1天后就报错崩溃了。 nohup.out 中的错误信息是:

Unhandled Error
Traceback (most recent call last):
  File "/usr/lib64/python2.7/site-packages/Twisted-15.4.0-py2.7-linux-x86_64.egg/twisted/python/log.py", line 84, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/Twisted-15.4.0-py2.7-linux-x86_64.egg/twisted/python/context.py", line 118, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/Twisted-15.4.0-py2.7-linux-x86_64.egg/twisted/python/context.py", line 81, in callWithContext
    return func(*args,**kw)
  File "/usr/lib64/python2.7/site-packages/Twisted-15.4.0-py2.7-linux-x86_64.egg/twisted/internet/posixbase.py", line 597, in _doReadOrWrite
    why = selectable.doRead()
--- <exception caught here> ---
  File "/usr/lib64/python2.7/site-packages/Twisted-15.4.0-py2.7-linux-x86_64.egg/twisted/internet/udp.py", line 248, in doRead
    self.protocol.datagramReceived(data, addr)
  File "UdpServer2.py", line 91, in datagramReceived
    self.device_echo(data, str(host), int(port))
  File "UdpServer2.py", line 19, in device_echo
    cur.execute(sql)
  File "/usr/lib64/python2.7/site-packages/MySQLdb/cursors.py", line 174, in execute
    self.errorhandler(self, exc, value)
  File "/usr/lib64/python2.7/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
_mysql_exceptions.OperationalError: (2006, 'MySQL server has gone away')

我的 python 代码 UdpServer2.py 的结构如下:

from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
import MySQLdb as mdb

conn = mdb.connect(host='localhost', user='root', passwd='123456', db='kj')

class KjEcho(DatagramProtocol):
    def device_echo(self, msg, host, port):
        device_no = msg[1:7]
        sql = "select did from device where device_no='%s'" % (device_no)

        cur = conn.cursor(mdb.cursors.DictCursor)
        cur.execute(sql)                                      #line 19 here

        if 0 == cur.rowcount:
           ...
        else:
           ...
        cur.close()

    def startProtocol(self):
        print 'kj_udp_server starting...'

    def datagramReceived(self, data, (host, port)):
        print "receive msg"
        if(18 != len(data)):
            print 'len err'
            return
        if('0x86' != hex(ord(data[0]))):
            print '0x86 err'
            return
        if(0 == ord(data[15])):
            print 'from device'
            self.device_echo(data, str(host), int(port))      #line 91 here
        else:
            print 'from mobile'
            self.mobile_echo(data, str(host), int(port))

reactor.listenUDP(6000, KjEcho())
reactor.run()

第91行和第19行是上面指出的原因,如何解决,谢谢。

注意:有很多机器,每台机器每20秒向服务器发送一条消息

您不能中继 mysql 连接(或与此相关的任何套接字)在未指定的时间段内保持活动状态,尤其是在没有数据流经它的情况下。因此,不要只使用一个连接来重新获取游标,而是关闭与游标的连接,然后在需要时再次打开它。

所以本质上你想为这一行添加前缀

    cur = conn.cursor(mdb.cursors.DictCursor)

设置 conn 然后追加以下

    cur.close()

关闭 conn,最有可能 conn.close()

非常感谢 Mai 和 Tymoteusz Paul

class KjEcho(DatagramProtocol):
    def device_echo(self, msg, host, port):
        device_no = msg[1:7]
        sql = "select did from device where device_no='%s'" % (device_no)

        conn = mdb.connect(host='localhost', user='root', passwd='123456', db='kj')
        cur = conn.cursor(mdb.cursors.DictCursor)
        cur.execute(sql)

        if 0 == cur.rowcount:
           ...
        else:
           ...
        cur.close()
        conn.close()

我觉得应该可以,但是对于连接,经常打开关闭,是不是用连接池比较好?