前面的內(nèi)容中已經(jīng)介紹了TCP編程和UDP編程實(shí)現(xiàn)網(wǎng)絡(luò)數(shù)據(jù)的通信和共享
我們可以看到客戶端程序的編寫相對(duì)容易灵汪,主需要連接服務(wù)端然后跟服務(wù)端進(jìn)行數(shù)據(jù)交互就OK了檀训。但是服務(wù)端的程序編寫較為復(fù)雜,如果考慮到數(shù)據(jù)的并發(fā)處理等各種問題识虚,就更加復(fù)雜難以操作了肢扯。
python提供了一個(gè)socketserver模塊,可以用于更加快捷的構(gòu)建我們需要的服務(wù)端環(huán)境
本節(jié)內(nèi)容
- socketserver模塊簡(jiǎn)介
- 常規(guī)模式服務(wù)端編程
- 并發(fā)模式服務(wù)端編程
1. socketserver模塊簡(jiǎn)介
socketserver是什么担锤?
socketserver模塊時(shí)python提供的內(nèi)置的用于快捷開發(fā)服務(wù)端程序的一個(gè)服務(wù)器框架蔚晨,通過封裝大量實(shí)現(xiàn)的方式減少開發(fā)人員工作量的同時(shí)能快捷開發(fā)出具有較高質(zhì)量的服務(wù)端程序。socketserver中提供了什么肛循?
socketserver模塊主要包含的服務(wù)器類:TCPserver铭腕、UCPserver、ThreadingTCPserver多糠、ThreadingUDPserver累舷、ForkingTCPserver、ForkingUDPserver
注意:上述TCP表示TCP服務(wù)端編程需要的服務(wù)類夹孔,UDP表示UDP編程需要的服務(wù)類被盈,包含Threading的表示多線程并發(fā)需要的服務(wù)類;包含F(xiàn)orking的表示多進(jìn)程并發(fā)需要的服務(wù)類
關(guān)于多線程和多進(jìn)程搭伤,后面的章節(jié)中會(huì)詳細(xì)介紹socketserver核心操作只怎?
socketserver框架中,服務(wù)端的處理類主要有StreamRequestHandler(基于TCP協(xié)議的)怜俐、DatagramRequestHandler(基于UDP協(xié)議的)身堡,處理類中非常重要的一個(gè)方法headler()
用來執(zhí)行服務(wù)端程序中的核心操作
class mytcpserver(socketserver.StreamRequestHandler):
def handle(self):
# 服務(wù)器中的核心操作代碼
- socketserver中的結(jié)構(gòu)?
socketserver中主要包含兩部分:服務(wù)器和處理類
服務(wù)類就是socketserver提供了內(nèi)置服務(wù)類拍鲤,如TCPserver贴谎、UDPserver
等等
處理類就是我們自定義的處理類,處理類中會(huì)包含handle()方法用于業(yè)務(wù)處理
2. 服務(wù)端編程
2.1. TCP服務(wù)端編程
使用socketserver編寫服務(wù)端程序如下:
import socketserver
# 自定義處理類
class myTcp(socketserver.StreamRequestHandler):
# 定義處理方法
def handle(self):
# 通過client_address屬性查看連接進(jìn)來的服務(wù)器
print("連接上的服務(wù)器:%s" % str(self.client_address))
while True:
# 接收客戶端發(fā)送的數(shù)據(jù)
msg = self.request.recv(1024)
if not msg:
break;
print("客戶端發(fā)過來消息:%s" % msg.decode("UTF-8"))
# 給客戶端返回接收信息
self.request.sendall("已經(jīng)成功接收您發(fā)送的消息".encode("UTF-8"))
# 程序從主線程直接運(yùn)行
if __name__ == "__main__":
# 創(chuàng)建服務(wù)端對(duì)象季稳,指定處理類擅这,并監(jiān)聽8888端口
server = socketserver.TCPServer(('', 8888), myTcp)
# 啟動(dòng)服務(wù)端程序
server.serve_forever()
此時(shí),我們使用常規(guī)模式開發(fā)客戶端程序如下:
import socket
sc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sc.connect(("192.168.10.108", 8888))
while True:
msg = input("請(qǐng)輸入要發(fā)送的內(nèi)容:")
if not msg or msg == "exit":
break
sc.sendall(msg.encode("UTF-8"))
msg = sc.recv(1024)
print("服務(wù)器回應(yīng):" + msg.decode("UTF-8"))
sc.close()
運(yùn)行上述程序景鼠,就可以和之前一樣蕾哟,實(shí)現(xiàn)客戶端和服務(wù)端之間的數(shù)據(jù)通信了;
和以前不一樣的時(shí)莲蜘,此時(shí)我們?nèi)绻P(guān)閉了客戶端,服務(wù)端程序還是在運(yùn)行的帘营,如果重新啟動(dòng)客戶端票渠,客戶端又會(huì)接入服務(wù)端,重新建立連接并通信芬迄。
2.2. UDP服務(wù)端編程
使用socketserver的UDPServer服務(wù)類和DatagramRequestHandler處理類進(jìn)行服務(wù)端的編程處理如下:
import socketserver
# 創(chuàng)建自定義處理類
class myUdp(socketserver.DatagramRequestHandler):
# 創(chuàng)建自定義處理方法
def handle(self):
# 打印連接進(jìn)來的客戶端信息
print("連接到服務(wù)器的主機(jī):" + str(self.client_address))
# 收發(fā)消息
while True:
# 接收客戶端發(fā)送的消息
# msg = self.request.recv()
msg = self.rfile.readline()
if not msg:
break
print("接受到客戶端發(fā)送的消息:%s" % msg.decode("UTF-8"))
# 發(fā)送消息
self.wfile.write("接收到您發(fā)送的消息".encode("UTF-8"))
# 主模塊線程中運(yùn)行程序
if __name__ == "__main__":
# 創(chuàng)建UDP服務(wù)器對(duì)象
server = socketserver.UDPServer(("", 8989), myUdp)
# 啟動(dòng)UDP服務(wù)器
server.serve_forever()
使用常規(guī)的方式開發(fā)UDP客戶端代碼如下:
import socket
sc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
data = input("請(qǐng)輸入要發(fā)送的消息:")
if not data or data == "exit":
break
sc.sendto(data.encode("UTF-8"), ("192.168.10.108", 8989))
data,recv = sc.recvfrom(1024)
if not data:
break
print("服務(wù)器返回消息:" + data.decode("UTF-8"))
sc.close()
此時(shí)啟動(dòng)服務(wù)端程序问顷,啟動(dòng)客戶端程序,就可以實(shí)現(xiàn)服務(wù)端和客戶端時(shí)間的數(shù)據(jù)通信了。
另外:你可以試試啟動(dòng)多個(gè)客戶端程序看看杜窄,有彩蛋哦肠骆。
3. 服務(wù)端并發(fā)
關(guān)于使用多線程或者多進(jìn)程并發(fā)的方式也是比較簡(jiǎn)單的,參考代碼如下塞耕,如果有興趣的話蚀腿,等學(xué)習(xí)完并發(fā)編程之后,可以再回過頭看看ThreadingTCPServer和ForkingTCPServer這樣多線程和多進(jìn)程并發(fā)的操作哦
服務(wù)端參考代碼:
import socketserver
class myTcp(socketserver.StreamRequestHandler):
def handle(self):
while True:
data = self.request.recv(1024)
print("接收到數(shù)據(jù):" + data.decode("UTF-8"))
self.request.sendall("數(shù)據(jù)已經(jīng)接收成功".encode("UTF-8"))
if __name__ == "__main__":
server = socketserver.ThreadingTCPServer(("", 9000), myTcp)
server.serve_forever()
客戶端還是常規(guī)的客戶端
import socket
sc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sc.connect(("192.168.10.108", 9000))
while True:
msg = input("請(qǐng)輸入要發(fā)送的內(nèi)容:")
if not msg or msg == "exit":
break
sc.sendall(msg.encode("UTF-8"))
msg = sc.recv(1024)
print("服務(wù)器回應(yīng):" + msg.decode("UTF-8"))
sc.close()