2019-07-22 13:57:04 3348瀏覽
今天千鋒扣丁學堂Python培訓老師為大家分享一篇python中基于tcp協(xié)議的通信(數(shù)據(jù)傳輸)實例講解,下面我們一起來看一下吧。
服務端: from socket import * # 確定服務端傳輸協(xié)議↓↓↓↓↓↓↓ server = socket(AF_INET, SOCK_STREAM) # 這里的SOCK_STREAM代表的就是流式協(xié)議TCP,如果是SOCK_DGRAM就代表UDP協(xié)議 # 固定服務端IP和PORT,讓客戶端能夠通過IP和端口訪問服務端↓↓↓↓↓↓↓ server.bind(('127.0.0.1', 8080)) # ('127.0.0.1', 8080)這里必須用元組形式傳入IP和PORT,本地訪問本地IP默認為'127.0.0.1' # 設置半連接池數(shù)量(一般為5) server.listen(5) # 半連接池:客戶端連接請求個數(shù)的容器,當前已連接的客戶端信息收發(fā)未完成前,會有最大5個客戶端連接請求進入排隊狀態(tài), # 等待上一個通信完畢后,就可以連接進入開始通信。 # 雙向通道建立成功,可以進行下一步數(shù)據(jù)的通信了↓↓↓↓↓↓↓ conn, client_addr = server.accept() # 進行一次信息的收與發(fā) data = conn.recv(1024) # 每次最大接收1024字節(jié),收到的數(shù)據(jù)為二進制Bytes類型 conn.send(data.upper()) # 將收到的數(shù)據(jù)進行處理,返回新的數(shù)據(jù),反饋給客戶端(給客戶端發(fā)數(shù)據(jù)),發(fā)的數(shù)據(jù)類型也必須是Bytes類型 # 一輪信息收發(fā)完畢,關(guān)閉已經(jīng)建立的雙向通道 conn.close() 客戶端: from socket import * # 確定客戶端傳輸協(xié)議↓↓↓↓↓↓↓(服務端和客戶端服務協(xié)議一樣才能進行有效的通信) client = socket(AF_INET, SOCK_STREAM) # 這里的SOCK_STREAM代表的就是流式協(xié)議TCP,如果是SOCK_DGRAM就代表UDP協(xié)議 # 開始連接服務端IP和PORT,建立雙向鏈接 client.connect(('127.0.0.1', 8080)) # 通過服務端IP和PORT進行連接 # 走到這一步就已經(jīng)建立連接完畢,接下來開始數(shù)據(jù)通信: client.send('hello,server'.encode('utf-8')) # 將發(fā)送的信息轉(zhuǎn)碼成Bytes類型數(shù)據(jù) data = client.recv(1024) # 每次最大收數(shù)據(jù)大小為1024字節(jié)(1kb) print(data.decode('utf-8')) # 將b類型數(shù)據(jù)轉(zhuǎn)換成字符串格式 # 一次傳輸完畢 client.close() # 關(guān)閉客戶端連接 啟動服務端(服務端開始監(jiān)聽客戶端的連接請求) 啟動客戶端(客戶端給服務端發(fā)送連接請求) 建立雙向鏈接完成 客戶端給服務端發(fā)送信息 hello,server 服務端收到hello,server,將其轉(zhuǎn)換成大寫,返回給客戶端(此時服務端一輪通信完畢) 客戶端收到服務端的反饋信息,打印出HELLO,SERVER(此時客戶端一輪通信完畢)
這個問題的更形象過程可以見下圖:
服務端: import socket import struct server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(5) while True: conn, client_addr = server.accept() print('客戶端已連接') while True: try: head = conn.recv(4) size = struct.unpack('i', head)[0] data = conn.recv(size) print('已收到客戶端信息:', data.decode('utf-8')) except ConnectionResetError: print('客戶端已中斷連接') conn.close() break 客戶端: import socket import struct while True: try: client = socket.socket() client.connect(('127.0.0.1', 8080)) print('已連接到服務端') while True: try: msg = 'abcdefghijklmnopqrstuvwxyz1234567890'.encode('utf-8') head = struct.pack('i', len(msg)) client.send(head) client.send(msg) except ConnectionResetError: print('服務端已中斷連接') client.close() break except ConnectionRefusedError: print('無法連接到服務器')
下載服務端: import socket import time import struct import json # 計算當前文件夾下文件的md5值、大小 import os, hashlib def get_info(file_name): file_info = {} base_dir = os.path.dirname(__file__) file_dir = os.path.join(base_dir, file_name) if os.path.exists(file_dir): # md5計算時文件數(shù)據(jù)是放在內(nèi)存中的,當我們計算一個大文件時,可以用update方法進行分步計算, # 每次添加部分文件數(shù)據(jù)進行計算,減少內(nèi)存占用。 with open(file_dir, 'rb') as f: le = 0 d5 = hashlib.md5() for line in f: le += len(line) d5.update(line) file_info['lenth'] = le # 將文件長度加入報頭字典 file_md5 = d5.hexdigest() file_info['md5'] = file_md5 # 將文件md5加入報頭字典 file_size = os.path.getsize(file_dir) / float(1024 * 1024) file_info['size(MB)'] = round(file_size, 2) # 將文件大小加入報頭字典 return file_info else: return file_info server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(5) while True: conn, client_addr = server.accept() print('%s >:客戶端(%s)已連接' % (time.strftime('%Y-%m-%d %H:%M:%S'), client_addr)) while True: try: download_filename = conn.recv(1024).decode('utf-8') download_file_info_dic = get_info(download_filename) j_head = json.dumps(download_file_info_dic) # 將文件信息字典轉(zhuǎn)成json字符串格式 head = struct.pack('i', len(j_head)) conn.send(head) conn.send(j_head.encode('utf-8')) if not download_file_info_dic: continue with open(download_filename, 'rb') as f: while True: data=f.read(1024) conn.send(data) # for line in f: # conn.send(line) except ConnectionResetError: print('%s >:客戶端(%s)已斷開' % (time.strftime('%Y-%m-%d %H:%M:%S'), client_addr)) conn.close() break
下載客戶端: import socket import time import struct import json # 進度條顯示 def progress(percent,width=30): text=('\r[%%-%ds]'%width)%('x'*int(percent*width)) text=text+'%3s%%' text=text%(round(percent*100)) print(text,end='') while True: try: client = socket.socket() client.connect(('127.0.0.1', 8080)) print('%s >:已連接到服務端' % time.strftime('%Y-%m-%d %H:%M:%S')) while True: try: file_name = input('請輸入下載文件名稱:') client.send(file_name.encode('utf-8')) head = client.recv(4) # 收報頭 j_dic_lenth = struct.unpack('i', head)[0] # 解壓報頭,獲取json格式的文件信息字典的長度 j_head = client.recv(j_dic_lenth) # 收json格式的信息字典 file_info_dic = json.loads(j_head) # 反序列化json字典,得到文件信息字典 if not file_info_dic: print('文件不存在') continue file_lenth = file_info_dic.get('lenth') file_size = file_info_dic.get('size(MB)') file_md5 = file_info_dic.get('md5') rec_len = 0 with open('cpoy_'+file_name, 'wb') as f: while rec_len < file_lenth: data = client.recv(1024) f.write(data) rec_len += len(data) per=rec_len/file_lenth progress(per) print() # print('下載比例:%6s %%'%) if not rec_len: print('文件不存在') else: print('文件[%s]下載成功: 大?。?s MB|md5值:[%s]' % (file_name, file_size, file_md5)) except ConnectionResetError: print('%s >:服務端已終止' % time.strftime('%Y-%m-%d %H:%M:%S')) client.close() break except ConnectionRefusedError: print('%s >:無法連接到服務器' % time.strftime('%Y-%m-%d %H:%M:%S'))
服務端: import socketserver import time class MyTcpHandler(socketserver.BaseRequestHandler): # 到這里表示服務端已監(jiān)聽到一個客戶端的連接請求,將通信交給一個handle方法實現(xiàn),自己再去監(jiān)聽客戶連接請求 def handle(self): # 建立雙向通道,進行通信 print('%s|客戶端%s已連接' % (time.strftime('%Y-%m-%d %H:%M:%S'), self.client_address)) while True: try: data = self.request.recv(1024) msg = '我已收到您的請求[%s],感謝您的關(guān)注!' % data.decode('utf-8') self.request.send(msg.encode('utf-8')) except ConnectionResetError: print('%s|客戶端%s已斷開連接' % (time.strftime('%Y-%m-%d %H:%M:%S'), self.client_address)) break if __name__ == '__main__': server = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyTcpHandler) # 綁定服務端IP和PORT,并產(chǎn)生并發(fā)方法對象 print('等待連接請求中...') server.serve_forever() # 服務端一直開啟
客戶端: from socket import * import time server_addr = ('127.0.0.1', 8080) count = 1 while True: if count > 10: time.sleep(1) print('%s|連接%s超時' % (time.strftime('%Y-%m-%d %H:%M:%S'), server_addr)) break try: client = socket(AF_INET, SOCK_STREAM) client.connect(('127.0.0.1', 8080)) count = 1 print('%s|服務端%s連接成功' % (time.strftime('%Y-%m-%d %H:%M:%S'), server_addr)) while True: try: client.send('北鼻'.encode('utf-8')) data = client.recv(1024) print(data.decode('utf-8')) time.sleep(0.5) except ConnectionResetError: print('%s|服務端%s已中斷' % (time.strftime('%Y-%m-%d %H:%M:%S'), server_addr)) client.close() break except ConnectionRefusedError: print('無法連接到服務端') count += 1
服務端 import socketserver import struct import subprocess class MyTcpHandler(socketserver.BaseRequestHandler): def handle(self): while True: print('客戶端<%s,%s>已連接' % self.client_address) try: cmd = self.request.recv(1024).decode('utf-8') res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = res.stdout.read() stderr = res.stderr.read() head = struct.pack('i', len(stdout + stderr)) self.request.send(head) self.request.send(stdout) self.request.send(stderr) except ConnectionResetError: print('客戶端<%s,%s>已中斷連接' % self.client_address) self.request.close() break if __name__ == '__main__': server = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyTcpHandler) server.serve_forever()
客戶端 from socket import * import struct while True: try: client = socket(AF_INET,SOCK_STREAM) client.connect(('127.0.0.1', 8080)) while True: try: cmd = input('>>>>>>>:').strip().encode('utf-8') client.send(cmd) head = client.recv(4) size = struct.unpack('i', head)[0] cur_size = 0 result = b'' while cur_size < size: data = client.recv(1024) cur_size += len(data) result += data print(result.decode('gbk')) # windows系統(tǒng)默認編碼是gbk,解碼肯定也要用gbk except ConnectionResetError: print('服務端已中斷') client.close() break except ConnectionRefusedError: print('無法連接服務端')
【關(guān)注微信公眾號獲取更多學習資料】 【掃碼進入Python全棧開發(fā)免費公開課】
查看更多關(guān)于"Python開發(fā)資訊"的相關(guān)文章>