【python自动化第八篇:网络编程】
一、拾遺
動(dòng)態(tài)導(dǎo)入模塊
目的是為了在導(dǎo)入模塊的過程中將模塊以字符的格式導(dǎo)入。?
#!/usr/bin/env python # -*- coding:utf-8 -*- #Author:wanghui lib = __import__("lib.aa") #傳統(tǒng)方法 lib.aa import importlib aa = importlib.import_module("lib.aa") #官方做法 print(aa.C().name)?斷言
類似于if,實(shí)際的意思就是如多對(duì)應(yīng)的條件為真就執(zhí)行,不為真就報(bào)錯(cuò)。
assert type(1223) is str print("this is str") #等同于 if type(1223) is str:exit("must be int") print("this is str")二、socket繼續(xù)
1、淺談server端的原理:
(1)、申明socket實(shí)例 ? ? server = socket.socket(AF.INET(地址簇),sock.SOCK_STREAM(代表tcp/ip))
地址簇分類:socket.AF_INET ----> ipv4 ? ?, ? ? ? ? ? ? ? ? ? ? ? socket.AF_INET6 -------> ipv6 ? ? ?, ? ? ? ?socket.AF_UNIX --------> ?本地通信
協(xié)議類型:socket.SOCK_STREAM -----> tcp/ip ? ? , ? ? ? ? ? ??socket.SOCK_DGRAM -----> ?udp
? (2)、綁定ip地址和端口 ? ? ?server.bind(("localhost",port))
?(3)、開始監(jiān)聽:while True:
conn,addr = server.accept() ? ?阻塞狀態(tài)
?(4)、循環(huán)接受信息
while True:
print("new conn",addr) ? #打印連接的客戶端ip
data = conn.recv(1024) ? ? ? ? ? ? #接受數(shù)據(jù)大小(官方最大建議8192),這邊接收數(shù)據(jù)的時(shí)候默認(rèn)也是阻塞的
if not data: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?***如果客戶端 已斷開的話conn.recv就會(huì)接收到空數(shù)據(jù)
break ? ? ? ? ? ??
conn.send(data.upper()) ? ? ? ? ? ?#發(fā)送數(shù)據(jù)
? ? ? 淺談客戶端的原理:
(1)、實(shí)例化一個(gè)socket ? ? client = socket.socket()
(2)、定義一個(gè) 鏈接的地址和端口 ? ? ?client.connect(("server_ip",port))
(3)、這會(huì)兒就可以發(fā)數(shù)據(jù)了 ? ?client.send(data)
(4)、接收數(shù)據(jù) ? client.recv()
2、通過socket實(shí)現(xiàn)一個(gè)簡(jiǎn)單的ssh協(xié)議:
client端:
#!/usr/bin/env python # -*- coding:utf-8 -*- #Author:wanghui import socket,os client = socket.socket() #實(shí)例化socket client.connect(("localhost",9999)) #開始連接啦while True: #發(fā)送數(shù)據(jù)啦cmd = input("請(qǐng)輸入命令>>:").strip()if len(cmd) == 0:continue #如果長(zhǎng)度為0,就繼續(xù)返回循環(huán)client.send(cmd.encode('utf-8')) #發(fā)送命令(byte)cmd_res = client.recv(1024) #接收返回結(jié)果print(cmd_res.decode()) #打印結(jié)果 client.close() #關(guān)閉連接server端:?
#!/usr/bin/env python # -*- coding:utf-8 -*- #Author:wanghui import socket,osserver = socket.socket() #申明實(shí)例 server.bind(('localhost',9999)) #綁定ip和端口 server.listen() #等待連接while True:conn,addr= server.accept() #監(jiān)聽print("開始連接啦",addr)while True: #正式接受數(shù)據(jù)啦print("開始新連接啦")data = conn.recv(1024) #定義傳輸大小if not data: #如果客戶端斷開,那么就退出此次接收,重新回到監(jiān)聽狀態(tài)breakprint("開始 執(zhí)行客戶端命令",data)cmd_res = os.popen(data.decode()).read() #讀取客戶端命令(bytes轉(zhuǎn)換成str)print("接受之前:",len(cmd_res))if len(cmd_res) == 0:cmd_res = "cmd has no output ..."conn.send(cmd_res.encode('utf-8')) #向端發(fā)送數(shù)據(jù),必須是bytesprint("發(fā)送完成!") server.close() #斷開連接上面的基本連接模式會(huì)出現(xiàn)客戶端發(fā)送的指令客戶端不能一次性全部返回的問題,這樣的話解決方式只能有:超時(shí)和確認(rèn)緩沖區(qū)多少次發(fā)完的問題
然而多少次將緩沖區(qū)的內(nèi)容發(fā)完呢?不曉得。。。所以只能通過在超時(shí)問題上做文章了
client:
#!/usr/bin/env python # -*- coding:utf-8 -*- #Author:wanghui import socket,os client = socket.socket() #實(shí)例化socket client.connect(("localhost",9999)) #開始連接啦while True: #發(fā)送數(shù)據(jù)啦cmd = input("請(qǐng)輸入命令>>:").strip()if len(cmd) == 0:continue #如果長(zhǎng)度為0,就繼續(xù)返回循環(huán)client.send(cmd.encode('utf-8')) #發(fā)送命令(byte)cmd_res_size = client.recv(1024) #接受返回?cái)?shù)據(jù)的大小print("接受的數(shù)據(jù)",cmd_res_size) #打印接收大小received_size = 0received_data = b''while received_size < int(cmd_res_size.decode()): #只要不相等就一直收data = client.recv(1024)received_size += len(data) #每次接收到的數(shù)據(jù)有可能小于1024,所以要用len判斷received_data += data #每次讀取進(jìn)來的data寫入received_data# print(data.decode())else:print("cmd rees received done",received_size)print(received_data.decode()) client.close() #關(guān)閉連接 View Code?
server:
#!/usr/bin/env python # -*- coding:utf-8 -*- #Author:wanghui import socket,osserver = socket.socket() #申明實(shí)例 server.bind(('localhost',9999)) #綁定ip和端口 server.listen() #等待連接while True:conn,addr= server.accept() #監(jiān)聽print("開始連接啦",addr)while True: #正式接受數(shù)據(jù)啦print("等待新指令:")data = conn.recv(1024) #定義傳輸大小if not data: #如果客戶端斷開,那么就退出此次接收,重新回到監(jiān)聽狀態(tài)print("客戶端已經(jīng)斷開!")breakprint("執(zhí)行命令",data)cmd_res = os.popen(data.decode()).read() #讀取客戶端命令(bytes轉(zhuǎn)換成str)print("接受之前:",len(cmd_res))if len(cmd_res) == 0:cmd_res = "cmd has no output ..."conn.send(str(len(cmd_res.encode())).encode('utf-8')) #先發(fā)大小給客戶端conn.send(cmd_res.encode('utf-8')) #向客戶端發(fā)送數(shù)據(jù),必須是bytesprint("發(fā)送完成!") server.close() #斷開連接 View Code?
3.粘包問題
server連續(xù)調(diào)用send的時(shí)候緩沖區(qū)會(huì)將挨著的兩次操作發(fā)給客戶端,導(dǎo)致兩次send的內(nèi)容都同時(shí)發(fā)給了客戶端,所以其中的一個(gè)方法就是在服務(wù)器端的send之間加入sleep時(shí)間,可以解決這個(gè)問題
? ? ?server:
#!/usr/bin/env python # -*- coding:utf-8 -*- #Author:wanghui import socket,os,timeserver = socket.socket() #申明實(shí)例 server.bind(('localhost',9999)) #綁定ip和端口 server.listen() #等待連接while True:conn,addr= server.accept() #監(jiān)聽print("開始連接啦",addr)while True: #正式接受數(shù)據(jù)啦print("等待新指令:")data = conn.recv(1024) #定義傳輸大小if not data: #如果客戶端斷開,那么就退出此次接收,重新回到監(jiān)聽狀態(tài)print("客戶端已經(jīng)斷開!")breakprint("執(zhí)行命令",data)cmd_res = os.popen(data.decode()).read() #讀取客戶端命令(bytes轉(zhuǎn)換成str)print("接受之前:",len(cmd_res))if len(cmd_res) == 0:cmd_res = "cmd has no output ..."conn.send(str(len(cmd_res.encode())).encode('utf-8')) #先發(fā)大小給客戶端#time.sleep(0.5) #防止粘包的一種方法client_ack= conn.recv(1024) #等待確認(rèn)print('ack from client:',client_ack)conn.send(cmd_res.encode('utf-8')) #向客戶端發(fā)送數(shù)據(jù),必須是bytesprint("發(fā)送完成!") server.close() #斷開連接client:
#!/usr/bin/env python # -*- coding:utf-8 -*- #Author:wanghui import socket,os client = socket.socket() #實(shí)例化socket client.connect(("localhost",9999)) #開始連接啦while True: #發(fā)送數(shù)據(jù)啦cmd = input("請(qǐng)輸入命令>>:").strip()if len(cmd) == 0:continue #如果長(zhǎng)度為0,就繼續(xù)返回循環(huán)client.send(cmd.encode('utf-8')) #發(fā)送命令(byte)cmd_res_size = client.recv(1024) #接受返回?cái)?shù)據(jù)的大小print("接受的數(shù)據(jù)",cmd_res_size) #打印接收大小client.send("準(zhǔn)備確認(rèn)啦".encode('utf-8'))received_size = 0received_data = b''while received_size < int(cmd_res_size.decode()): #只要不相等就一直收data = client.recv(1024)received_size += len(data) #每次接收到的數(shù)據(jù)有可能小于1024,所以要用len判斷received_data += data #每次讀取進(jìn)來的data寫入received_data# print(data.decode())else:print("cmd rees received done",received_size)print(received_data.decode()) client.close() #關(guān)閉連接4.簡(jiǎn)易的文件傳輸案例
server端的設(shè)計(jì):
-
-
- 讀取文件名
- 檢測(cè)文件是否存在
- 打開文件
- 檢測(cè)文件大小
- 發(fā)送文件大小和MD5值給客戶端
- 等待客戶端確認(rèn)
- 開始邊讀取邊發(fā)數(shù)據(jù)
-
client端:
#!/usr/bin/env python # -*- coding:utf-8 -*- #Author:wanghui import socket,os,hashlibclient = socket.socket() #實(shí)例化socket client.connect(("localhost",9999)) #開始連接啦while True: #發(fā)送數(shù)據(jù)啦cmd = input(">>:").strip()if len(cmd) == 0:continue #如果長(zhǎng)度為0,就繼續(xù)返回循環(huán)if cmd.startwith('get'): #定義開始client.send(cmd.encode()) #客戶端發(fā)送命令server_resbonce = client.recv(1024) #接收服務(wù)器端數(shù)據(jù)print("server resbonce:",server_resbonce)client.send("準(zhǔn)備接收文件".encode())file_total_size = int(server_resbonce.decode()) #定義接受的文件總大小received_size=0 #初始接收文件filename = cmd.split()[1] #獲取文件名f = open(filename + '.new','wb') #開始寫文件m = hashlib.md5() #定義MD5加密while received_size < file_total_size: #如果接收的文件小于總文件大小,就執(zhí)行如下data = client.recv(1024) #定義接收文件received_size+=len(data) #接受的文件大小變化m.update(data) #生成客戶端接受的MD5f.write(data) #寫入數(shù)據(jù)#print(file_total_size,received_size) #打印文件接受大小和總大小else:new_file_md5 = m.hexdigest()print("接受完了文件:",file_total_size,received_size)f.close() #關(guān)閉文件server_md5 = client.recv(1024) #接收服務(wù)器端MD5print(server_md5,new_file_md5) #對(duì)比MD5client.close()
?
轉(zhuǎn)載于:https://www.cnblogs.com/wanghui1991/p/5865848.html
總結(jié)
以上是生活随笔為你收集整理的【python自动化第八篇:网络编程】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java9-6 内部类
- 下一篇: Rnotebook中用python画图