6.Twisted UDP Socket 編程示例
示例:客戶端每隔10秒向服務(wù)端報送設(shè)備使用情況,具體數(shù)據(jù)如下:
數(shù)據(jù) | 說明 | 值示例 |
CPUUsed | CPU占用情況 % | 35.5% |
MemTotal | 總內(nèi)存 MB | 2048M |
MemFree | 可用內(nèi)存 MB | 1024M |
MemUsed | 內(nèi)存占用情況 % | 50% |
數(shù)據(jù)以文本進行傳輸,傳輸格式:Key:Value,中間用冒號分隔。服務(wù)端只做數(shù)據(jù)的原樣顯示并回復(fù)”OK!”
由于 UDP 沒有連接的概念,所以大多數(shù)情況下,采用 UDP Socket 實現(xiàn)的應(yīng)用都是由設(shè)備采集數(shù)據(jù)上報到服務(wù)上來運行的。
6.1 UDP 服務(wù)端編程
雖然對于 UDP 來說沒有服務(wù)端和客戶端的概念,但在實際項目開發(fā)中,我們一般還是要區(qū)分服務(wù)端和客戶端的。對于 UDP 服務(wù)端來說,其實代碼很簡單,因為其主要任務(wù)就是接收數(shù)據(jù),然后對數(shù)據(jù)進行處理。
先來編寫代碼框架:
# coding: utf-8from twisted.internet import reactorfrom twisted.internet.protocol import DatagramProtocolclass Server(DatagramProtocol): def startProtocol(self): pass def datagramReceived(self, data, addr): pass def stopProtocol(self): passreactor.listenUDP(8085, Server())reactor.run()
代碼中,主要實現(xiàn)的是 datagramReceived 事件,一般在該事件的代碼中就是我們的業(yè)務(wù)邏輯,示例代碼如下:
def startProtocol(self): print(‘Server start.’) def datagramReceived(self, data, addr): print(“received data from %s:%s” % (addr, data)) self.transport.write(‘OK!’.encode(‘utf-8’), addr) def stopProtocol(self): print(‘Server stop.’)
6.2 UDP 客戶端編程
客戶端代碼相對比服務(wù)端要復(fù)雜一點,主要是客戶端需要執(zhí)行定時任務(wù),這樣的話,我們需要設(shè)計一個線程來執(zhí)行該定時任務(wù),由于線程中需要發(fā)送數(shù)據(jù)到服務(wù)端,所以,在線程中需要設(shè)計一個屬性指向客戶端的 Protocol。線程的框架代碼如下:
# coding: utf-8from twisted.internet import reactorfrom twisted.internet.protocol import DatagramProtocolfrom threading import Threadimport timeimport psutilclass DataThread(Thread): def __init__(self, protocol): self.protocol = protocol self.running = True super().__init__() def run(self): self.running = True pass def stop(self): self.running = False
客戶端框架代碼:
class Client(DatagramProtocol): def startProtocol(self): pass def datagramReceived(self, data, addr): pass def connectionRefused(self): pass def stopProtocol(self): passclient = Client()thread = DataThread(client)thread.start()reactor.listenUDP(0, client)reactor.run()thread.stop()
線程主要通過 Protocol 發(fā)送數(shù)據(jù),實現(xiàn)代碼如下:
def run(self): self.running = True while True: if not self.running: break time.sleep(10) data = psutil.virtual_memory() total = ‘MemTotal:%0.2f’ % (data.total / 1024) # 總內(nèi)存 print(total) if self.protocol is not None: self.protocol.transport.write(total.encode(‘utf-8’)) time.sleep(1) free = ‘MemFree:%0.2f’ % (data.available / 1024) # 可用內(nèi)存 print(free) if self.protocol is not None: self.protocol.transport.write(free.encode(‘utf-8’)) time.sleep(1) memory = “MemUsed:%d” % (int(round(data.percent))) + “%” # 內(nèi)存占用情況 print(memory) if self.protocol is not None: self.protocol.transport.write(memory.encode(‘utf-8’)) time.sleep(1) cpu = “CPUUsed:%0.2f” % psutil.cpu_percent(interval=1) + “%” # CPU占用情況 print(cpu) if self.protocol is not None: self.protocol.transport.write(cpu.encode(‘utf-8’))
客戶端 Protocol 代碼實現(xiàn)如下:
def startProtocol(self): host = “127.0.0.1” port = 8085 print(‘Connect to %s:%s’ % (host, port)) self.transport.connect(host, port) def datagramReceived(self, data, addr): print(“received data from %s:%s” % (addr, data)) def connectionRefused(self): print(“No one listening”) def stopProtocol(self): print(‘Stop’)
在 Protocol 啟動時連接到服務(wù)器,這樣就可以形成 Connected UDP,相對于 UDP 來說,數(shù)據(jù)的傳輸可靠性有所提高,同時,在代碼中發(fā)送數(shù)據(jù)也不需要寫服務(wù)端的地址。
6.3 運行效果
服務(wù)端:
Server start.received data from (‘127.0.0.1’, 56768):b’MemTotal:20880432.00’received data from (‘127.0.0.1’, 56768):b’MemFree:13308280.00’received data from (‘127.0.0.1’, 64355):b’MemTotal:20880432.00’received data from (‘127.0.0.1’, 64355):b’MemFree:13315952.00’received data from (‘127.0.0.1’, 64355):b’MemUsed:36%’received data from (‘127.0.0.1’, 64355):b’CPUUsed:1.20%’Server stop.
客戶端:
Connect to 127.0.0.1:8085MemTotal:20880432.00received data from (‘127.0.0.1’, 8085):b’OK!’MemFree:13315952.00received data from (‘127.0.0.1’, 8085):b’OK!’MemUsed:36%received data from (‘127.0.0.1’, 8085):b’OK!’CPUUsed:1.20%received data from (‘127.0.0.1’, 8085):b’OK!’MemTotal:20880432.00