W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
你想實(shí)現(xiàn)一個(gè)基于UDP協(xié)議的服務(wù)器來(lái)與客戶端通信。
跟TCP一樣,UDP服務(wù)器也可以通過(guò)使用?<span class="pre" style="box-sizing: border-box;">socketserver</span>
?庫(kù)很容易的被創(chuàng)建。 例如,下面是一個(gè)簡(jiǎn)單的時(shí)間服務(wù)器:
from socketserver import BaseRequestHandler, UDPServer
import time
class TimeHandler(BaseRequestHandler):
def handle(self):
print('Got connection from', self.client_address)
# Get message and client socket
msg, sock = self.request
resp = time.ctime()
sock.sendto(resp.encode('ascii'), self.client_address)
if __name__ == '__main__':
serv = UDPServer(('', 20000), TimeHandler)
serv.serve_forever()
跟之前一樣,你先定義一個(gè)實(shí)現(xiàn)?<span class="pre" style="box-sizing: border-box;">handle()</span>
?特殊方法的類,為客戶端連接服務(wù)。 這個(gè)類的?<span class="pre" style="box-sizing: border-box;">request</span>
屬性是一個(gè)包含了數(shù)據(jù)報(bào)和底層socket對(duì)象的元組。<span class="pre" style="box-sizing: border-box;">client_address</span>
?包含了客戶端地址。
我們來(lái)測(cè)試下這個(gè)服務(wù)器,首先運(yùn)行它,然后打開(kāi)另外一個(gè)Python進(jìn)程向服務(wù)器發(fā)送消息:
>>> from socket import socket, AF_INET, SOCK_DGRAM
>>> s = socket(AF_INET, SOCK_DGRAM)
>>> s.sendto(b'', ('localhost', 20000))
0
>>> s.recvfrom(8192)
(b'Wed Aug 15 20:35:08 2012', ('127.0.0.1', 20000))
>>>
一個(gè)典型的UPD服務(wù)器接收到達(dá)的數(shù)據(jù)報(bào)(消息)和客戶端地址。如果服務(wù)器需要做應(yīng)答, 它要給客戶端回發(fā)一個(gè)數(shù)據(jù)報(bào)。對(duì)于數(shù)據(jù)報(bào)的傳送, 你應(yīng)該使用socket的?<span class="pre" style="box-sizing: border-box;">sendto()</span>
?和?<span class="pre" style="box-sizing: border-box;">recvfrom()</span>
?方法。 盡管傳統(tǒng)的?<span class="pre" style="box-sizing: border-box;">send()</span>
?和?<span class="pre" style="box-sizing: border-box;">recv()</span>
?也可以達(dá)到同樣的效果, 但是前面的兩個(gè)方法對(duì)于UDP連接而言更普遍。
由于沒(méi)有底層的連接,UPD服務(wù)器相對(duì)于TCP服務(wù)器來(lái)講實(shí)現(xiàn)起來(lái)更加簡(jiǎn)單。 不過(guò),UDP天生是不可靠的(因?yàn)橥ㄐ艣](méi)有建立連接,消息可能丟失)。 因此需要由你自己來(lái)決定該怎樣處理丟失消息的情況。這個(gè)已經(jīng)不在本書討論范圍內(nèi)了, 不過(guò)通常來(lái)說(shuō),如果可靠性對(duì)于你程序很重要,你需要借助于序列號(hào)、重試、超時(shí)以及一些其他方法來(lái)保證。 UDP通常被用在那些對(duì)于可靠傳輸要求不是很高的場(chǎng)合。例如,在實(shí)時(shí)應(yīng)用如多媒體流以及游戲領(lǐng)域, 無(wú)需返回恢復(fù)丟失的數(shù)據(jù)包(程序只需簡(jiǎn)單的忽略它并繼續(xù)向前運(yùn)行)。
<span class="pre" style="box-sizing: border-box;">UDPServer</span>
?類是單線程的,也就是說(shuō)一次只能為一個(gè)客戶端連接服務(wù)。 實(shí)際使用中,這個(gè)無(wú)論是對(duì)于UDP還是TCP都不是什么大問(wèn)題。 如果你想要并發(fā)操作,可以實(shí)例化一個(gè)?<span class="pre" style="box-sizing: border-box;">ForkingUDPServer</span>
?或<span class="pre" style="box-sizing: border-box;">ThreadingUDPServer</span>
?對(duì)象:
from socketserver import ThreadingUDPServer
if __name__ == '__main__':
serv = ThreadingUDPServer(('',20000), TimeHandler)
serv.serve_forever()
直接使用?<span class="pre" style="box-sizing: border-box;">socket</span>
?來(lái)是想一個(gè)UDP服務(wù)器也不難,下面是一個(gè)例子:
from socket import socket, AF_INET, SOCK_DGRAM
import time
def time_server(address):
sock = socket(AF_INET, SOCK_DGRAM)
sock.bind(address)
while True:
msg, addr = sock.recvfrom(8192)
print('Got message from', addr)
resp = time.ctime()
sock.sendto(resp.encode('ascii'), addr)
if __name__ == '__main__':
time_server(('', 20000))
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: