day29 socketsever ftp知識點講解
阿新 • • 發佈:2018-11-27
1. socketsever
# 客戶端
import socketserver
class KnightSever(socketserver.BaseRequestHandler): # 固定寫法
def handle(self):
# self.request() 相當於conn通道
while 1:
from_client_msg = self.request.recv(1024) #接收客戶端資訊
print(from_client_msg.decode(' utf-8'))
sever_msg = input('服務端>>>')
self.request.send(sever_msg.encode('utf-8')) # 傳送服務端資訊
if __name__ == '__main__':
ip_port = ('127.0.0.1', 8001)
sever = socketserver.ThreadingTCPServer(ip_port, KnightSever)
sever.serve_forever() # 讓伺服器永久執行
# 客戶端
import socket
client = socket.socket()
client.connect(('127.0.0.1', 8001))
while 1:
client_data = input('別開車')
client.send(client_data.encode('utf-8'))
from_sever_msg = client.recv(1024)
print(from_sever_msg.decode('utf-8'))
client.close()
socketsever演示
模組的原始碼分析:
查詢屬性的順序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServer 例項化得到server,先找ThreadMinxIn中的__init__方法,發現沒有init方法,然後找類ThreadingTCPServer的__init__,在TCPServer中找到,在裡面建立了socket物件,進而執行server_bind(相當於bind),server_active(點進去看執行了listen) 找server下的serve_forever,在BaseServer中找到,進而執行self._handle_request_noblock(),該方法同樣是在BaseServer中 執行self._handle_request_noblock()進而執行request, client_address = self.get_request()(就是TCPServer中的self.socket.accept()),然後執行self.process_request(request, client_address) 在ThreadingMixIn中找到process_request,開啟多執行緒應對併發,進而執行process_request_thread,執行self.finish_request(request, client_address) 上述四部分完成了連結迴圈,本部分開始進入處理通訊部分,在BaseServer中找到finish_request,觸發我們自己定義的類的例項化,去找__init__方法,而我們自己定義的類沒有該方法,則去它的父類也就是BaseRequestHandler中找.... 原始碼分析總結: 基於tcp的socketserver我們自己定義的類中的 self.server即套接字物件 self.request即一個連結 self.client_address即客戶端地址
基於udp的socketserver我們自己定義的類中的 self.request是一個元組(第一個元素是客戶端發來的資料,第二部分是服務端的udp套接字物件),如(b'adsf', <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>) self.client_address即客戶端地址
2. 字串操作以及列印 —— 實現上傳下載的進度條功能
# 進度條列印 一、 import sys import time for i in range(50): sys.stdout.write('>') sys.stdout.flush() time.sleep(0.2) 二、 #總共接收到的大小和總檔案大小的比值: #all_size_len表示當前總共接受的多長的資料,是累計的 #file_size表示檔案的總大小 per_cent = round(all_size_len/file_size,2) #將比值做成兩位數的小數 #通過\r來實現同一行列印,每次列印都回到行首列印 print('\r'+ '%s%%'%(str(int(per_cent*100))) + '*'*(int(per_cent*100)),end='') #由於float型別的資料沒法通過%s來進行字串格式化,所以我在這裡通過int來轉換了一下,並用str轉換了一下,後面再拼接上*,這個*的數量根據現在計算出來的比值來確定,就能夠出來%3***這樣的效果。自行使用上面的sys.stdout來實現一下這個直接print的效果。