2010-09-22 70 views
5

我目前正致力於通過網絡從遺留系統公開數據。我有一個(傳統)服務器應用程序,通過UDP發送和接收數據。 該軟件使用UDP在(接近)實時(每隔5-10毫秒更新一次)發送連續更新到一組給定的變量。因此,我不需要捕獲所有UDP數據 - 檢索最新更新就足夠了。如何在Python中通過HTTP在UDP流中提供數據?

爲了通過網絡公開這些數據,我正在考慮構建一個輕量級的Web服務器來讀取/寫入UDP數據並通過HTTP公開這些數據。

由於我對Python有經驗,我正在考慮使用它。

問題是以下幾點:我該如何(連續地)從UDP讀取數據,並通過TCP/HTTP使用Python按需發送快照?所以基本上,我試圖建立一種「UDP2HTTP」適配器來與傳統應用程序接口,以便我不需要觸摸遺留代碼。

符合WSGI標準的解決方案將是首選。當然,任何提示都非常受歡迎,非常感謝!

+3

HTTP中沒有「連續的」。根據定義。不可能有。你在問什麼? HTTP協議的奇蹟版本,它不會遵循HTTP規則,而是像UDP一樣行事? – 2010-09-22 10:15:26

+0

謝謝你的關心。我知道這樣的事情不存在。澄清:我的問題是試圖通過HTTP讀取UDP數據的快照。我並沒有試圖讓HTTP「連續」(問題也被編輯過) – jsalonen 2010-09-22 10:47:54

+0

一個好的結構可以使某種webapp中的某些變量模型以某種方式實現。 UDP數據更新那個模型(即,webapp監聽它),但不告訴任何HTTP要更新的東西。 HTTP的任何提取只是從這些變量中讀取當前狀態的快照(並記住禁用所生成頁面的緩存)。 – 2010-09-22 11:23:18

回答

3

該軟件使用UDP在(接近)實時(每隔5-10毫秒更新一次)向一組給定變量發送連續更新。因此,我不需要捕獲所有的UDP數據 - 檢索最新更新就足夠了

你必須做的是這樣的。

步驟1.

構建一個Python應用程序收集的UDP數據,並將其緩存到一個文件中。使用XML,CSV或JSON表示法創建文件。

它作爲某種守護進程獨立運行。這是你的聽衆或收藏家。

將文件寫入一個目錄,可以通過Apache或其他Web服務器輕鬆下載該目錄。明智地選擇名稱和目錄路徑,你就完成了。

完成。

如果你想要更好的結果,你可以做更多。你不需要,因爲你已經完成了。

步驟2.

構建一個Web應用程序,允許某人請求此數據由UDP偵聽或集電極進行累計。

爲此,使用像Django這樣的Web框架。儘可能少寫。 Django可以提供由監聽器創建的平面文件。

你完成了。再次。

有些人認爲關係數據庫很重要。如果是這樣,你可以做到這一點。即使你已經完成了。

步驟3.

修改您的數據收集創建Django的ORM可以查詢數據庫。這需要一些學習和一些調整才能得到一個整潔,簡單的ORM模型。

然後編寫您的最終Django應用程序來爲您的偵聽器收集並加載到您的Django數據庫中的UDP數據提供服務。

+0

感謝您提供詳盡的答案。但不需要粗魯,交配。我非常清楚我正在處理一個複雜的問題,謝謝。我同意你的觀點,即在更長的時間內持久性,緩存等成爲問題。但是,現在我只需要一個概念驗證。在這一點上,任何工作 - 甚至是醜陋的和駭人的代碼 - 都證明了我如何讀取UDP數據的快照並通過HTTP發送它們就足夠了。 – jsalonen 2010-09-22 10:44:54

+0

請注意,我編輯我的問題更具體! – jsalonen 2010-09-22 10:54:38

+0

對不起,它顯得粗魯。這個問題 - 正如最初所提出的 - 太模糊,太多漏洞要在表面上認真對待。沒有**細節**和**細節**隱含的方法不可能工作。請避免含有**或**具體**的模糊問題**。 – 2010-09-22 12:19:39

6

Twisted在這裏會非常適合。它支持許多協議(UDP,HTTP),並且它的異步特性使得可以直接將UDP數據流傳輸到HTTP,而無需使用(阻塞)線程代碼在腳下進行拍攝。它也支持wsgi。

5

這是一個使用扭曲框架的快速「概念驗證」應用程序。這假設傳統的UDP服務正在監聽localhost:8000,並將開始發送UDP數據以響應包含「發送數據」的數據報。數據是3 32位整數。此外,將一個 「HTTP GET /」 端口響應2080

您可以用twistd -noy example.py開始這樣的:

example.py

from twisted.internet import protocol, defer 
from twisted.application import service 
from twisted.python import log 
from twisted.web import resource, server as webserver 

import struct 

class legacyProtocol(protocol.DatagramProtocol): 
    def startProtocol(self): 
     self.transport.connect(self.service.legacyHost,self.service.legacyPort) 
     self.sendMessage("Send me data") 
    def stopProtocol(self): 
     # Assume the transport is closed, do any tidying that you need to. 
     return 
    def datagramReceived(self,datagram,addr): 
     # Inspect the datagram payload, do sanity checking. 
     try: 
      val1, val2, val3 = struct.unpack("!iii",datagram) 
     except struct.error, err: 
      # Problem unpacking data log and ignore 
      log.err() 
      return 
     self.service.update_data(val1,val2,val3) 
    def sendMessage(self,message): 
     self.transport.write(message) 

class legacyValues(resource.Resource): 
    def __init__(self,service): 
     resource.Resource.__init__(self) 
     self.service=service 
     self.putChild("",self) 
    def render_GET(self,request): 
     data = "\n".join(["<li>%s</li>" % x for x in self.service.get_data()]) 
     return """<html><head><title>Legacy Data</title> 
      <body><h1>Data</h1><ul> 
      %s 
      </ul></body></html>""" % (data,) 

class protocolGatewayService(service.Service): 
    def __init__(self,legacyHost,legacyPort): 
     self.legacyHost = legacyHost # 
     self.legacyPort = legacyPort 
     self.udpListeningPort = None 
     self.httpListeningPort = None 
     self.lproto = None 
     self.reactor = None 
     self.data = [1,2,3] 
    def startService(self): 
     # called by application handling 
     if not self.reactor: 
      from twisted.internet import reactor 
      self.reactor = reactor 
     self.reactor.callWhenRunning(self.startStuff) 
    def stopService(self): 
     # called by application handling 
     defers = [] 
     if self.udpListeningPort: 
      defers.append(defer.maybeDeferred(self.udpListeningPort.loseConnection)) 
     if self.httpListeningPort: 
      defers.append(defer.maybeDeferred(self.httpListeningPort.stopListening)) 
     return defer.DeferredList(defers) 
    def startStuff(self): 
     # UDP legacy stuff 
     proto = legacyProtocol() 
     proto.service = self 
     self.udpListeningPort = self.reactor.listenUDP(0,proto) 
     # Website 
     factory = webserver.Site(legacyValues(self)) 
     self.httpListeningPort = self.reactor.listenTCP(2080,factory) 
    def update_data(self,*args): 
     self.data[:] = args 
    def get_data(self): 
     return self.data 

application = service.Application('LegacyGateway') 
services = service.IServiceCollection(application) 
s = protocolGatewayService('127.0.0.1',8000) 
s.setServiceParent(services) 

有感

這不是一個WSGI設計。這個想法可以用來運行這個守護程序,並使其在本地IP和Apache上的http端口或類似的代理請求。它可以重構爲WSGI。這種方式更快,更容易調試。

+0

非常感謝你用實際的代碼來回答。我已經無意識地扭曲了很多次,卻不知道它有多難使用。此代碼提供了一個概念驗證代碼,我可以將其作爲一個起點進行傳播和使用。 – jsalonen 2010-09-23 09:09:43

+0

非常歡迎。我認爲扭曲的一個缺點是學習曲線陡峭,在你有足夠的工作概念開始迭代改進之前,可能會有很大的努力障礙。 – MattH 2010-09-23 09:23:04

相關問題