Twisted TCP Server无法回送数据

求熟悉Twisted底层的大神帮助。

我的TCP端口服务器一直服务正常,可是一旦加入Redis之后,却不再返回数据了?

class PlainTCP(protocol.Protocol):
    def __init__(self, factory):
        pass
        
    def connectionMade(self):
        self.factory.numConnections += 1
        print "Nr. of connections: %d\n" %(self.factory.numConnections)
        self.transport.write("Hello remote\r\n")

    def connectionLost(self, reason):
        self.factory.numConnections -= 1
        print "Nr. of connections: %d\n" %(self.factory.numConnections)

    def dataReceived(self, data):
        (self.snrCode,rDat,pDat) = getDataParsed(data)    
        self.transport.write(data)

以上代码在远程客户端可以立即获得复制的数据

而增加了SQL/Redis数据保存后,事情变得奇怪了。

#!/usr/bin/env python
import time
import binascii
import txredisapi

from twisted.internet import defer
from twisted.internet import protocol, reactor
from twisted.internet.protocol import Factory
from twisted.enterprise import adbapi
from twisted.python import log

from dmpack import Dmpack
from dmdb import Dmdb
from dmconfig import DmConf

dm = Dmpack()
conf = DmConf().loadConf()
rcs = txredisapi.lazyConnection(password=conf['RedisPassword'])
dbpool = adbapi.ConnectionPool("MySQLdb",db=conf['DbName'],user=conf['DbAccount'],\
        passwd=conf['DbPassword'],host=conf['DbHost'],\
        use_unicode=True,charset=conf['DbCharset'])

def getDataParsed(data):
    realtime = None
    period = None
    snrCode = dm.snrToAscii(data[2:7])    
    realtime = data[7:167]
    perid = data[167:-2]

    return (snrCode, realtime, period)

class PlainTCP(protocol.Protocol):
    def __init__(self, factory):
        self.factory = factory
        self.factory.numConnections = 0
        self.snrCode = None 
        self.rData = None
        self.pData = None
        self.err = None

    def connectionMade(self):
        self.factory.numConnections += 1
        print "Nr. of connections: %d\n" %(self.factory.numConnections)
        self.transport.write("Hello remote\r\n") ##这里也不返回数据了

    def connectionLost(self, reason):
        self.factory.numConnections -= 1
        print "Nr. of connections: %d\n" %(self.factory.numConnections)

    @defer.inlineCallbacks
    def dataReceived(self, data):
        global dbpool, rcs
        (self.snrCode,rDat,pDat) = getDataParsed(data)

        if self.snrCode == None or rDat == None or pDat == None:
            err = "Bad format"
        else:
            err = "OK"
        print "err:%s"%(err) ### 这里可以在终端打印数据
        self.err = err

        self.transport.write(self.snrCode) ### 没有数据返回
        self.transport.write(self.err)
        self.transport.write(rDat)
        self.transport.write(pDat) 
        self.transport.loseConnection()

        if self.snrCode != None and rDat != None and pDat != None:    
            res = yield self.saveRealTimeData(rcs, rDat)        
            res = yield self.savePeriodData(dbpool, pDat, conf)

        print "err2:%s"%(err) ### 终端有打印

    @defer.inlineCallbacks
    def saveRealTimeData(self, rc, dat):
        yield rc.set(key,val) ### 自己脑补Key、Val
        yield rc.expire(key,30) ### 可以保存,已经确认

    @defer.inlineCallbacks
    def savePeriodData(self,rc,dat,conf):
        query = "insert....." ### 自己脑补SQL
        yield rc.runQuery(query) ### 可以保存,已经确认

class PlainTCPFactory(protocol.Factory):
    def buildProtocol(self, addr):
        return PlainTCP(self)

def main():
    dmdb = Dmdb()
    if not dmdb.detectDb():
        print "Please run MySQL RDBS first."
        sys.exit()

    log.startLogging(sys.stdout)

    reactor.listenTCP(8080, PlainTCPFactory())
    reactor.run()

if __name__ == "__main__":
    main()

现象是一旦加入了异步库之后,socket就不在回传了。原始Demo中self.transport.write()没有任何修饰符,所以这应该是同步的。搞不懂异步数据库加入后,为何连connectionMade()这个不相关的句柄中的write()也被失效了。而同时print却是有效的?

阅读 5.2k
2 个回答

谢谢大哥关注这个问题。这个是2015年的问题,所以我花了一番力气才看懂我自己的问题,慢慢回想起来。

因为当时我根本没有找到答案,所以只有一步步地反复调整。最后结论是调用异步方式本身不需要yield。因为一旦调用者yield,就调用者也成了生成器了。所以内嵌print也就不执行了。

    @defer.inlineCallbacks # 这里不需要@defer.inlineCallbacks
    def dataReceived(self, data):
         res = yield self.saveRealTimeData(rcs, rDat) # 这里不需要yield
         
    @defer.inlineCallbacks
    def saveRealTimeData(self, rc, dat, conf):
        yield rc.set(key,val)   # 这里需要保留yield
        yield rc.expire(key,conf['RedisDataTTL'])    

宗旨:

@defer.inlineCallback修饰的函数里必然有yield; 异步函数方法调用者不要再使用异步。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题