簡體   English   中英

使用帶有數據庫插入的Twisted AMP

[英]Using Twisted AMP with Database insertion

我正在學習如何使用Twisted AMP。 我正在開發一個程序,將數據從客戶端發送到服務器並將數據插入SQLite3數據庫。 然后服務器將結果發送回客戶端,指示成功或錯誤(嘗試和除了可能不是最好的方法,但它只是一個臨時的解決方案,而我解決了主要問題)。 為了做到這一點,我修改了一個例子,我發現最初做了一個總和並返回了結果,所以我意識到這可能不是我做的事情最有效的方法。 特別是我試圖在多次插入時做一些計時(即多次將數據發送到服務器進行多次插入),並且我已經包含了我編寫的代碼。 它工作但很明顯它不是一個發送多個數據插入的好方法,因為我在運行reactor之前執行多個連接。

我已經嘗試了幾種方法來解決這個問題,包括將ClientCreator傳遞給reactor.callWhenRunning(),但是你不能用延遲來做。

任何建議,建議或如何做到這一點的幫助將不勝感激。 這是代碼。

服務器:

from twisted.protocols import amp
from twisted.internet import reactor
from twisted.internet.protocol import Factory
import sqlite3, time

class Insert(amp.Command):
    arguments = [('data', amp.Integer())]
    response = [('insert_result', amp.Integer())]

class Protocol(amp.AMP):
    def __init__(self):     
       self.conn = sqlite3.connect('biomed1.db')
       self.c =self.conn.cursor()
       self.res=None

    @Insert.responder
    def dbInsert(self, data):
        self.InsertDB(data) #call the DB inserter
        result=self.res     # send back the result of the insertion
        return {'insert_result': result}

    def InsertDB(self,data):
      tm=time.time()
      print "insert time:",tm
      chx=data
      PID=2
      device_ID=5
      try:
        self.c.execute("INSERT INTO btdata4(co2_data, patient_Id, sensor_Id) VALUES ('%s','%s','%s')" % (chx, PID, device_ID))    
      except Exception, err:
             print err
             self.res=0
      else:
             self.res=1

      self.conn.commit()


pf = Factory()
pf.protocol = Protocol
reactor.listenTCP(1234, pf) 
reactor.run()

客戶:

from twisted.internet import reactor
from twisted.internet.protocol import ClientCreator
from twisted.protocols import amp
import time

class Insert(amp.Command):
    arguments = [('data', amp.Integer())]
    response = [('insert_result', amp.Integer())]

def connected(protocol):
    return protocol.callRemote(Insert, data=5555).addCallback(gotResult)

def gotResult(result):
    print 'insert_result:', result['insert_result']
    tm=time.time()
    print "stop", tm    

def error(reason):
    print "error", reason

tm=time.time()
print "start",tm
for i in range (10): #send data over ten times
  ClientCreator(reactor, amp.AMP).connectTCP(
     '127.0.0.1', 1234).addCallback(connected).addErrback(error)

reactor.run()

代碼結束。

謝謝。

幾乎沒有什么能改善您的服務器代碼。

首要的是:不鼓勵使用直接數據庫訪問功能,因為它們通常會導致阻塞。 Twisted為數據庫訪問提供了很好的抽象,它為數據庫連接提供了扭曲的方法 - twisted.adbapi

現在開始重用數據庫連接:如果你想在多個協議實例中重用某些資產(比如數據庫連接),你應該在工廠的構造函數中初始化那些,或者你不想在啟動時啟動這些東西,創建一個資源訪問方法,它將在第一次方法調用時啟動資源,然后將其分配給類變量並在后續調用時返回該變量。

當Factory創建特定的Protocol intance時,它將在協議內添加對自身的引用,參見twisted.internet.protocol的第97行。

然后在您的Protocol實例中,您可以訪問共享數據庫連接實例,如:

self.factory.whatever_name_for_db_connection.doSomething() 

重做的服務器代碼(我沒有python,扭曲甚至可靠的IDE,所以這幾乎沒有測試,有些錯誤是預期的)

from twisted.protocols import amp
from twisted.internet import reactor
from twisted.internet.protocol import Factory
import time

class AMPDBAccessProtocolFactory(Factory):
    def getDBConnection(self):
        if 'dbConnection' in dir(self):
            return self.dbConnection
        else:
            self.dbConnection = SQLLiteTestConnection(self.dbURL)
            return self.dbConnection

class SQLLiteTestConnection(object):
    """
    Provides abstraction for database access and some business functions.
    """
    def __init__(self,dbURL):
        self.dbPool =  adbapi.ConnectionPool("sqlite3" , dbURL,  check_same_thread=False)

    def insertBTData4(self,data):
        query = "INSERT INTO btdata4(co2_data, patient_Id, sensor_Id) VALUES (%s,%s,%s)" 
        tm=time.time()
        print "insert time:",tm
        chx=data
        PID=2
        device_ID=5
        dF = self.dbPool.runQuery(query,(chx, PID, device_ID)) 
        dF.addCallback(self.onQuerySuccess,insert_data=data)
        return dF
    def onQuerySuccess(self,insert_data,*r):
        """
        Here you can inspect query results or add any other valuable information to be parsed at client.
        For the test sake we will just return True to a customer if query was a success.
        original data available at kw argument insert_data
        """
        return True


class Insert(amp.Command):
    arguments = [('data', amp.Integer())]
    response = [('insert_result', amp.Integer())]

class MyAMPProtocol(amp.AMP):

    @Insert.responder
    def dbInsert(self, data):
        db = self.factory.getDBConnection()
        dF = db.insertBTData4(data)
        dF.addErrback(self.onInsertError,data)
        return dF

    def onInsertError(self, error, data):
        """
        Here you could do some additional error checking or inspect data 
        which was handed for insert here. For now we will just throw the same exception again
        so that the client gets notified
        """
        raise error

if __name__=='__main__':
    pf = AMPDBAccessProtocolFactory()
    pf.protocol = MyAMPProtocol
    pf.dbURL='biomed1.db'
    reactor.listenTCP(1234, pf) 
    reactor.run()

現在轉到客戶端。 如果AMP遵循整個RPC邏輯(當前無法測試),它應該能夠在多個調用中仔細閱讀相同的連接。 所以我創建了一個ServerProxy類,它將保存該perusable協議實例並為調用提供抽象:

from twisted.internet import reactor
from twisted.internet.protocol import ClientCreator
from twisted.protocols import amp
import time

class Insert(amp.Command):
    arguments = [('data', amp.Integer())]
    response = [('insert_result', amp.Integer())]

class ServerProxy(object):
    def connected(self,protocol):
        self.serverProxy = protocol # assign protocol as instance variable
        reactor.callLater(5,self.startMultipleInsert) #after five seconds start multiple insert procedure

    def remote_insert(self,data):
        return self.serverProxy.callRemote(Insert, data)

    def startMultipleInsert(self):
        for i in range (10): #send data over ten times
            dF = self.remote_insert(i)
            dF.addCallback(self.gotInsertResult)
            dF.addErrback(error)

    def gotInsertResult(self,result):
        print 'insert_result:', str(result)
        tm=time.time()
        print "stop", tm    

def error(reason):
    print "error", reason


def main():
    tm=time.time()
    print "start",tm
    serverProxy = ServerProxy()
    ClientCreator(reactor, amp.AMP).connectTCP('127.0.0.1', 1234).addCallback(serverProxy.connected).addErrback(error)
    reactor.run()    

if __name__=='__main__':
    main()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM