數據的流向:Client-》客戶端OS-》PC機-》網絡設備-》服務器-》服務器OS-》Serverpython
1)生活中通訊舉例:linux
2)計算機與計算機之間通訊舉例;程序員
3)互聯網協議-OSI七層;算法
1)、就是底層的物理連接介質+互聯網協議;shell
2)、互聯網協議就是計算機界的「英語」;編程
1)、物理層-L1;json
功能:發送電信號0101110001;設計模式
2)、數據鏈路層-L2;瀏覽器
造成了統一的標準-Ethernet(以太網協議);服務器
計算機通訊基本靠吼;
3)、網絡層-L3;
引出IP地址的概念;
4)、傳輸層-L4
TCP、UDP協議;
引出端口號的概念;1~65535;
IP+Port能夠表示全世界範圍內惟一一個軟件;
通常來講,服務端會綁定IP和端口;而客戶端不須要;
HTTP、FTP;
1)、接電話方:
1.首先你得有個電話 2.你的電話要有號碼 3.你的電話必須連上電話線 4.開始在家等電話 5.電話鈴響了,接起電話,聽到對方的聲音
2)、打電話方:
1.首先你得有個電話 2.輸入你想撥打的電話 3.等待對方接聽 4.say 「hi 約麼,我有七天酒店的打折卡噢~」 5.等待迴應——》響應迴應——》等待迴應。。。。
1)、接電話方(socket服務器端):
1.首先你得有個電話\(生成socket對象\) 2.你的電話要有號碼\(綁定本機ip+port\) 3.你的電話必須連上電話線\(連網\) 4.開始在家等電話\(開始監聽電話listen\) 5.電話鈴響了,接起電話,聽到對方的聲音\(接受新鏈接\)
2)、打電話方(socket客戶端)
1.首先你得有個電話\(生成socket對象\) 2.輸入你想撥打的電話\(connect 遠程主機ip+port\) 3.等待對方接聽 4.say 「hi 約麼,我有七天酒店的打折卡噢~」\(send\(\) 發消息。。。\) 5.等待迴應——》響應迴應——》等待迴應。。。。
1)server.py;
import socket #一、買手機; phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #二、綁定手機卡; phone.bind(('127.0.0.1',18081))#0~65535,其中0~1024,系統使用 #三、開機; phone.listen(5) #四、等電話來鏈接; print('starting....') # cxz = phone.accept() # print(cxz) conn,client_addr = phone.accept() #五、收、發消息; data = conn.recv(1024)#一、單位bytes;二、1024表明最大接受1024個bytes; print('客戶端數據',data) conn.send(data.upper()) #六、掛電話; conn.close() #七、關機; phone.close()
2) client.py
import socket #一、買手機; phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #print(phone)#<socket.socket fd=428, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0> #二、撥號; phone.connect(('127.0.0.1',18081))#ConnectionRefusedError: [WinError 10061] 因爲目標計算機積極拒絕,沒法鏈接。 #三、發、收消息; phone.send('hello'.encode('utf-8')) data = phone.recv(1024) print(data) #四、關機; phone.close()
1)server.py
import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.bind(('127.0.0.1',18080))#0~65535,其中0~1024,系統使用; phone.listen(5) print('starting....') conn,client_addr = phone.accept() print(client_addr) while True: data = conn.recv(1024)#一、單位bytes;二、1024表明最大接受1024個bytes; print('客戶端數據',data) conn.send(data.upper()) conn.close() phone.close()
2)client.py
import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',18080))#ConnectionRefusedError: [WinError 10061] 因爲目標計算機積極拒絕,沒法鏈接。 while True: msg = input('>>>:').strip() phone.send(msg.encode('utf-8')) data = phone.recv(1024) print(data) phone.close()
import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) phone.bind(('127.0.0.1',18080))#0~65535,其中0~1024,系統使用; phone.listen(5) print('starting....') conn,client_addr = phone.accept() print(client_addr) while True: try: data = conn.recv(1024)#一、單位bytes;二、1024表明最大接受1024個bytes; if not data:break#僅適用於Linux操做系統; print('客戶端數據',data) conn.send(data.upper()) except ConnectionResetError:#適用於Windows操做系統; break conn.close() phone.close()
import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',18080))#ConnectionRefusedError: [WinError 10061] 因爲目標計算機積極拒絕,沒法鏈接。 while True: msg = input('>>>:').strip() if not msg:continue phone.send(msg.encode('utf-8')) data = phone.recv(1024) print(data.decode('utf-8')) phone.close()
1)server.py
import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) phone.bind(('127.0.0.1',18080))#0~65535,其中0~1024,系統使用; phone.listen(5) print('starting....') while True:#連接循環; conn,client_addr = phone.accept() print(client_addr) while True:#進入通訊循環; try: data = conn.recv(1024)#一、單位bytes;二、1024表明最大接受1024個bytes; if not data:break#僅適用於Linux操做系統; print('客戶端數據',data) conn.send(data.upper()) except ConnectionResetError:#適用於Windows操做系統; break conn.close() phone.close()
2)client1.py
import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',18080))#ConnectionRefusedError: [WinError 10061] 因爲目標計算機積極拒絕,沒法鏈接。 while True: msg = input('>>>:').strip() if not msg:continue phone.send(msg.encode('utf-8')) data = phone.recv(1024) print(data.decode('utf-8')) phone.close()
3)client2.py
import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',18080))#ConnectionRefusedError: [WinError 10061] 因爲目標計算機積極拒絕,沒法鏈接。 while True: msg = input('>>>:').strip() if not msg:continue phone.send(msg.encode('utf-8')) data = phone.recv(1024) print(data.decode('utf-8')) phone.close()
import socket import os import subprocess phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) phone.bind(('127.0.0.1',18080))#0~65535,其中0~1024,系統使用; phone.listen(5) print('starting....') while True:#連接循環; conn,client_addr = phone.accept() print(client_addr) while True:#進入通訊循環; try: #一、收命令; cmd = conn.recv(1024)#一、單位bytes;二、1024表明最大接受1024個bytes; if not cmd:break#僅適用於Linux操做系統; print('客戶端數據',cmd) #二、執行命令,拿到結果; obj = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # obj = subprocess.Popen('xxxxxipconfig',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) stdout = obj.stdout.read() # stdout1--->: b'\r\nWindows IP \xc5\xe4\xd6\xc3\r\n\r\n\r\n\xd2\xd4\xcc\xab\xcd\xf8\xca\xca\xc5\xe4\xc6\xf7 \xd2\xd4\xcc\xab\xcd\xf8 2:\r\n\r\n \xc1\xac\xbd\xd3\xcc\xd8\xb6\xa8\xb5\xc4 DNS \xba\xf3\xd7\xba . . . . . . . : \r\n \xb1\xbe\xb5\xd8\xc1\xb4\xbd\xd3 IPv6 \xb5\xd8\xd6\xb7. . . . . . . . : fe80::fdc4:7f23:1928:6026%11\r\n IPv4 \xb5\xd8\xd6\xb7 . . . . . . . . . . . . : 192.168.1.5\r\n \xd7\xd3\xcd\xf8\xd1\xda\xc2\xeb . . . . . . . . . . . . : 255.255.255.0\r\n \xc4\xac\xc8\xcf\xcd\xf8\xb9\xd8. . . . . . . . . . . . . : fe80::1%11\r\n 192.168.1.1\r\n\r\n\xd2\xd4\xcc\xab\xcd\xf8\xca\xca\xc5\xe4\xc6\xf7 \xd2\xd4\xcc\xab\xcd\xf8 3:\r\n\r\n \xc3\xbd\xcc\xe5\xd7\xb4\xcc\xac . . . . . . . . . . . . : \xc3\xbd\xcc\xe5\xd2\xd1\xb6\xcf\xbf\xaa\xc1\xac\xbd\xd3\r\n \xc1\xac\xbd\xd3\xcc\xd8\xb6\xa8\xb5\xc4 DNS \xba\xf3\xd7\xba . . . . . . . : \r\n\r\n\xcb\xed\xb5\xc0\xca\xca\xc5\xe4\xc6\xf7 Teredo Tunneling Pseudo-Interface:\r\n\r\n \xc1\xac\xbd\xd3\xcc\xd8\xb6\xa8\xb5\xc4 DNS \xba\xf3\xd7\xba . . . . . . . : \r\n IPv6 \xb5\xd8\xd6\xb7 . . . . . . . . . . . . : 2001:0:9d38:6ab8:242a:88b7:20b7:be6c\r\n \xb1\xbe\xb5\xd8\xc1\xb4\xbd\xd3 IPv6 \xb5\xd8\xd6\xb7. . . . . . . . : fe80::242a:88b7:20b7:be6c%14\r\n \xc4\xac\xc8\xcf\xcd\xf8\xb9\xd8. . . . . . . . . . . . . : ::\r\n' stderr = obj.stderr.read() # stdout3--->: 'xxxxxipconfig' 不是內部或外部命令,也不是可運行的程序或批處理文件。 #三、把命令結果返回給客戶端; conn.send(stdout+stderr)#+號是一個能夠優化的點子; except ConnectionResetError:#適用於Windows操做系統; break conn.close() phone.close()
import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',18080))#ConnectionRefusedError: [WinError 10061] 因爲目標計算機積極拒絕,沒法鏈接。 while True: #發送命令; cmd = input('>>>:').strip() if not cmd:continue phone.send(cmd.encode('utf-8')) #二、拿到命令的結果 data = phone.recv(1024) print(data.decode('gbk')) phone.close() """ C:\Users\Administrator\PycharmProjects\LFXC2018\venv\Scripts\python.exe "C:/Users/Administrator/PycharmProjects/LFXC2018/第三模塊 面向對象/網絡編程/11-模擬ssh遠程執行命令-代碼實現/11-client.py" >>>:ipconfig Windows IP 配置 以太網適配器 以太網 2: 鏈接特定的 DNS 後綴 . . . . . . . : 本地連接 IPv6 地址. . . . . . . . : fe80::fdc4:7f23:1928:6026%11 IPv4 地址 . . . . . . . . . . . . : 192.168.1.5 子網掩碼 . . . . . . . . . . . . : 255.255.255.0 默認網關. . . . . . . . . . . . . : fe80::1%11 192.168.1.1 以太網適配器 以太網 3: 媒體狀態 . . . . . . . . . . . . : 媒體已斷開鏈接 鏈接特定的 DNS 後綴 . . . . . . . : 隧道適配器 Teredo Tunneling Pseudo-Interface: 鏈接特定的 DNS 後綴 . . . . . . . : IPv6 地址 . . . . . . . . . . . . : 2001:0:9d38:6ab8:242a:88b7:20b7:be6c 本地連接 IPv6 地址. . . . . . . . : fe80::242a:88b7:20b7:be6c%14 默認網關. . . . . . . . . . . . . : :: >>>: """
某個命令的輸出結果字節比較長,但客戶端只recv(1024), 可結果比1024長呀,那怎麼辦,只好在服務器端的IO緩衝區裏把客戶端還沒收走的暫時存下來,等客戶端下次再來收。同志們,這個現象叫作粘包,就是指兩次結果粘到一塊兒了。它的發生主要是由於socket緩衝區致使的,來看一下
仍是看上圖,發送端能夠是一K一K地發送數據,而接收端的應用程序能夠兩K兩K地提走數據,固然也有可能一次提走3K或6K數據,或者一次只提走幾個字節的數據,也就是說,應用程序所看到的數據是一個總體,或說是一個流(stream),一條消息有多少字節對應用程序是不可見的,所以TCP協議是面向流的協議,這也是容易出現粘包問題的緣由。而UDP是面向消息的協議,每一個UDP段都是一條消息,應用程序必須以消息爲單位提取數據,不能一次提取任意字節的數據,這一點和TCP是很不一樣的。怎樣定義消息呢?能夠認爲對方一次性write/send的數據爲一個消息,須要明白的是當對方send一條信息的時候,不管底層怎樣分段分片,TCP協議層會把構成整條消息的數據段排序完成後才呈如今內核緩衝區。
所謂粘包問題主要仍是由於接收方不知道消息之間的界限,不知道一次性提取多少字節的數據所形成的。
#!/usr/bin/env python3 # -*- coding:utf-8 -*- # __Author__:TQTL911 # Version:python3.6.6 # Time:2018/7/14 16:11 import socket import subprocess phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.bind(('127.0.0.1',9901))#0~65525,其中0~1024給操做系統使用; phone.listen(5)#5表示最大掛起的連接數; print('starting...') while True:#連接循環 conn,client_addr = phone.accept() print(client_addr) while True:#通訊循環 try: #一、接收命令; cmd = conn.recv(1024)#接收數據的最大字節數;一、單位:bytes;二、最大接收1024個bytes; #if not cmd:break#僅適用於Linux操做系統 #二、執行命令,拿到結果並打印; obj = subprocess.Popen(cmd.decode('utf-8'),shell=True, stdout = subprocess.PIPE, stderr = subprocess.PIPE) stdout = obj.stdout.read() stderr = obj.stderr.read() #三、把命令的結果返回給客戶端; print(len(stdout)+ len(stderr)) conn.send(stdout + stderr)#+號是一個能夠優化的點 except ConnectionResetError:#異常處理; break conn.close() phone.close()
#!/usr/bin/env python3 # -*- coding:utf-8 -*- # __Author__:TQTL911 # Version:python3.6.6 # Time:2018/7/14 16:17 import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',9901))#0~65525,其中0~1024給操做系統使用; while True: #一、發送命令; cmd = input('>>:').strip()#ls /etc if not cmd:continue phone.send(cmd.encode('utf-8')) #二、拿到命令結果; data = phone.recv(1024)#有可能數據包的大小超過1024bytes; print(data.decode('gbk')) phone.close()
#!/usr/bin/env python3 # -*- coding:utf-8 -*- # __Author__:TQTL911 # Version:python3.6.6 # Time:2018/7/14 16:11 import socket import subprocess server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.bind(('127.0.0.1',9001))#0~65525,其中0~1024給操做系統使用; server.listen(5)#5表示最大掛起的連接數; conn,addr = server.accept() res1 = conn.recv(1024) print('第1次',res1) res2 = conn.recv(1024) print('第2次',res2)
#!/usr/bin/env python3 # -*- coding:utf-8 -*- # __Author__:TQTL911 # Version:python3.6.6 # Time:2018/7/14 16:17 import socket import time client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('127.0.0.1',9001)) client.send('hello'.encode('utf-8')) time.sleep(5) client.send('world'.encode('utf-8'))
1)server.py
import socket import os import subprocess phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) phone.bind(('127.0.0.1',18080))#0~65535,其中0~1024,系統使用; phone.listen(5) print('starting....') while True:#連接循環; conn,client_addr = phone.accept() print(client_addr) while True:#進入通訊循環; try: #一、收命令; cmd = conn.recv(1024)#一、單位bytes;二、1024表明最大接受1024個bytes; if not cmd:break#僅適用於Linux操做系統; print('客戶端數據',cmd) #二、執行命令,拿到結果; obj = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # obj = subprocess.Popen('xxxxxipconfig',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) stdout = obj.stdout.read() # stdout1--->: b'\r\nWindows IP \xc5\xe4\xd6\xc3\r\n\r\n\r\n\xd2\xd4\xcc\xab\xcd\xf8\xca\xca\xc5\xe4\xc6\xf7 \xd2\xd4\xcc\xab\xcd\xf8 2:\r\n\r\n \xc1\xac\xbd\xd3\xcc\xd8\xb6\xa8\xb5\xc4 DNS \xba\xf3\xd7\xba . . . . . . . : \r\n \xb1\xbe\xb5\xd8\xc1\xb4\xbd\xd3 IPv6 \xb5\xd8\xd6\xb7. . . . . . . . : fe80::fdc4:7f23:1928:6026%11\r\n IPv4 \xb5\xd8\xd6\xb7 . . . . . . . . . . . . : 192.168.1.5\r\n \xd7\xd3\xcd\xf8\xd1\xda\xc2\xeb . . . . . . . . . . . . : 255.255.255.0\r\n \xc4\xac\xc8\xcf\xcd\xf8\xb9\xd8. . . . . . . . . . . . . : fe80::1%11\r\n 192.168.1.1\r\n\r\n\xd2\xd4\xcc\xab\xcd\xf8\xca\xca\xc5\xe4\xc6\xf7 \xd2\xd4\xcc\xab\xcd\xf8 3:\r\n\r\n \xc3\xbd\xcc\xe5\xd7\xb4\xcc\xac . . . . . . . . . . . . : \xc3\xbd\xcc\xe5\xd2\xd1\xb6\xcf\xbf\xaa\xc1\xac\xbd\xd3\r\n \xc1\xac\xbd\xd3\xcc\xd8\xb6\xa8\xb5\xc4 DNS \xba\xf3\xd7\xba . . . . . . . : \r\n\r\n\xcb\xed\xb5\xc0\xca\xca\xc5\xe4\xc6\xf7 Teredo Tunneling Pseudo-Interface:\r\n\r\n \xc1\xac\xbd\xd3\xcc\xd8\xb6\xa8\xb5\xc4 DNS \xba\xf3\xd7\xba . . . . . . . : \r\n IPv6 \xb5\xd8\xd6\xb7 . . . . . . . . . . . . : 2001:0:9d38:6ab8:242a:88b7:20b7:be6c\r\n \xb1\xbe\xb5\xd8\xc1\xb4\xbd\xd3 IPv6 \xb5\xd8\xd6\xb7. . . . . . . . : fe80::242a:88b7:20b7:be6c%14\r\n \xc4\xac\xc8\xcf\xcd\xf8\xb9\xd8. . . . . . . . . . . . . : ::\r\n' stderr = obj.stderr.read() # stdout3--->: 'xxxxxipconfig' 不是內部或外部命令,也不是可運行的程序或批處理文件。 #三、把命令結果返回給客戶端; #3-1把數據的長度發給客戶端; #3-2再發送真實的數據 #把報頭(固定長度)發送給客戶端; total_size = print(len(stdout)+len(stderr)) conn.send(str(total_size).encode('utf-8')) #conn.send(stdout+stderr)#+號是一個能夠優化的點子; conn.send(stdout) conn.send(stderr) except ConnectionResetError:#適用於Windows操做系統; break conn.close() phone.close()
2)client.py
import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',18080))#ConnectionRefusedError: [WinError 10061] 因爲目標計算機積極拒絕,沒法鏈接。 while True: cmd = input('>>>:').strip() if not cmd:continue phone.send(cmd.encode('utf-8')) total_size =102400 #第一步,先拿到數據的長度; #接受真實的數據; recv_size = 0 recv_data = b'' while recv_size < total_size: res = phone.recv(1024) recv_data += res recv_size += len(res) print(recv_data.decode('utf-8')) phone.close()
一、簡單版本;
1)、sever.py
import socket import os import subprocess import struct phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) phone.bind(('127.0.0.1',18081))#0~65535,其中0~1024,系統使用; phone.listen(5) print('starting....') while True:#連接循環; conn,client_addr = phone.accept() print(client_addr) while True:#進入通訊循環; try: #一、收命令; cmd = conn.recv(1024)#一、單位bytes;二、1024表明最大接受1024個bytes; if not cmd:break#僅適用於Linux操做系統; print('客戶端數據',cmd) #二、執行命令,拿到結果; obj = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # obj = subprocess.Popen('xxxxxipconfig',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) stdout = obj.stdout.read() # stdout1--->: b'\r\nWindows IP \xc5\xe4\xd6\xc3\r\n\r\n\r\n\xd2\xd4\xcc\xab\xcd\xf8\xca\xca\xc5\xe4\xc6\xf7 \xd2\xd4\xcc\xab\xcd\xf8 2:\r\n\r\n \xc1\xac\xbd\xd3\xcc\xd8\xb6\xa8\xb5\xc4 DNS \xba\xf3\xd7\xba . . . . . . . : \r\n \xb1\xbe\xb5\xd8\xc1\xb4\xbd\xd3 IPv6 \xb5\xd8\xd6\xb7. . . . . . . . : fe80::fdc4:7f23:1928:6026%11\r\n IPv4 \xb5\xd8\xd6\xb7 . . . . . . . . . . . . : 192.168.1.5\r\n \xd7\xd3\xcd\xf8\xd1\xda\xc2\xeb . . . . . . . . . . . . : 255.255.255.0\r\n \xc4\xac\xc8\xcf\xcd\xf8\xb9\xd8. . . . . . . . . . . . . : fe80::1%11\r\n 192.168.1.1\r\n\r\n\xd2\xd4\xcc\xab\xcd\xf8\xca\xca\xc5\xe4\xc6\xf7 \xd2\xd4\xcc\xab\xcd\xf8 3:\r\n\r\n \xc3\xbd\xcc\xe5\xd7\xb4\xcc\xac . . . . . . . . . . . . : \xc3\xbd\xcc\xe5\xd2\xd1\xb6\xcf\xbf\xaa\xc1\xac\xbd\xd3\r\n \xc1\xac\xbd\xd3\xcc\xd8\xb6\xa8\xb5\xc4 DNS \xba\xf3\xd7\xba . . . . . . . : \r\n\r\n\xcb\xed\xb5\xc0\xca\xca\xc5\xe4\xc6\xf7 Teredo Tunneling Pseudo-Interface:\r\n\r\n \xc1\xac\xbd\xd3\xcc\xd8\xb6\xa8\xb5\xc4 DNS \xba\xf3\xd7\xba . . . . . . . : \r\n IPv6 \xb5\xd8\xd6\xb7 . . . . . . . . . . . . : 2001:0:9d38:6ab8:242a:88b7:20b7:be6c\r\n \xb1\xbe\xb5\xd8\xc1\xb4\xbd\xd3 IPv6 \xb5\xd8\xd6\xb7. . . . . . . . : fe80::242a:88b7:20b7:be6c%14\r\n \xc4\xac\xc8\xcf\xcd\xf8\xb9\xd8. . . . . . . . . . . . . : ::\r\n' stderr = obj.stderr.read() # stdout3--->: 'xxxxxipconfig' 不是內部或外部命令,也不是可運行的程序或批處理文件。 #三、把命令結果返回給客戶端; total_size = print(len(stdout) + len(stderr)) header = struct.pack('i',total_size) #第1步:製做固定長度的報頭; conn.send(header) # 第2步:把報頭髮送給客戶端; conn.send(str(total_size).encode('utf-8')) # 第3步:再發送真實的數據; conn.send(stdout) conn.send(stderr) except ConnectionResetError:#適用於Windows操做系統; break conn.close() phone.close()
2)、struct模塊的使用
#!/usr/bin/env python # -*- coding:utf-8 -*- # __Author__:Administrator # Version:Python3.6.5 # Date:2018/6/23 0023 9:32 import struct res = struct.pack('i',1230) print(res,type(res),len(res)) #client.recv(4) obj = struct.unpack('i',res) print(obj[0])
3)、client.py的使用
import socket import struct phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',18081))#ConnectionRefusedError: [WinError 10061] 因爲目標計算機積極拒絕,沒法鏈接。 while True: #一、發送命令; cmd = input('>>>:').strip() if not cmd:continue phone.send(cmd.encode('utf-8')) #二、拿到命令的結果,並打印; #第1步:先收報頭; header = phone.recv(4) # 第2步,從報頭中解析出真實的數據; total_size = struct.unpack('i',header)[0] # 第2步:接受真實的數據; recv_size = 0 recv_data = b'' while recv_size < total_size: res = phone.recv(1024) recv_data += res recv_size += len(res) print(recv_data.decode('utf-8')) phone.close()
1)、server.py
import socket import os import subprocess import struct import json phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) phone.bind(('127.0.0.1',18080))#0~65535,其中0~1024,系統使用; phone.listen(5) print('starting....') while True:#連接循環; conn,client_addr = phone.accept() print(client_addr) while True:#進入通訊循環; try: #一、收命令; cmd = conn.recv(8096)#一、單位bytes;二、1024表明最大接受1024個bytes; if not cmd:break#僅適用於Linux操做系統; #二、執行命令,拿到結果; obj = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # obj = subprocess.Popen('xxxxxipconfig',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) stdout = obj.stdout.read() # stdout1--->: b'\r\nWindows IP \xc5\xe4\xd6\xc3\r\n\r\n\r\n\xd2\xd4\xcc\xab\xcd\xf8\xca\xca\xc5\xe4\xc6\xf7 \xd2\xd4\xcc\xab\xcd\xf8 2:\r\n\r\n \xc1\xac\xbd\xd3\xcc\xd8\xb6\xa8\xb5\xc4 DNS \xba\xf3\xd7\xba . . . . . . . : \r\n \xb1\xbe\xb5\xd8\xc1\xb4\xbd\xd3 IPv6 \xb5\xd8\xd6\xb7. . . . . . . . : fe80::fdc4:7f23:1928:6026%11\r\n IPv4 \xb5\xd8\xd6\xb7 . . . . . . . . . . . . : 192.168.1.5\r\n \xd7\xd3\xcd\xf8\xd1\xda\xc2\xeb . . . . . . . . . . . . : 255.255.255.0\r\n \xc4\xac\xc8\xcf\xcd\xf8\xb9\xd8. . . . . . . . . . . . . : fe80::1%11\r\n 192.168.1.1\r\n\r\n\xd2\xd4\xcc\xab\xcd\xf8\xca\xca\xc5\xe4\xc6\xf7 \xd2\xd4\xcc\xab\xcd\xf8 3:\r\n\r\n \xc3\xbd\xcc\xe5\xd7\xb4\xcc\xac . . . . . . . . . . . . : \xc3\xbd\xcc\xe5\xd2\xd1\xb6\xcf\xbf\xaa\xc1\xac\xbd\xd3\r\n \xc1\xac\xbd\xd3\xcc\xd8\xb6\xa8\xb5\xc4 DNS \xba\xf3\xd7\xba . . . . . . . : \r\n\r\n\xcb\xed\xb5\xc0\xca\xca\xc5\xe4\xc6\xf7 Teredo Tunneling Pseudo-Interface:\r\n\r\n \xc1\xac\xbd\xd3\xcc\xd8\xb6\xa8\xb5\xc4 DNS \xba\xf3\xd7\xba . . . . . . . : \r\n IPv6 \xb5\xd8\xd6\xb7 . . . . . . . . . . . . : 2001:0:9d38:6ab8:242a:88b7:20b7:be6c\r\n \xb1\xbe\xb5\xd8\xc1\xb4\xbd\xd3 IPv6 \xb5\xd8\xd6\xb7. . . . . . . . : fe80::242a:88b7:20b7:be6c%14\r\n \xc4\xac\xc8\xcf\xcd\xf8\xb9\xd8. . . . . . . . . . . . . : ::\r\n' stderr = obj.stderr.read() # stdout3--->: 'xxxxxipconfig' 不是內部或外部命令,也不是可運行的程序或批處理文件。 #三、把命令結果返回給客戶端; # 第1步:製做固定長度的報頭; header_dic = { 'filename':'a.txt', 'md5':'xxxx', 'total_size':len(stdout) + len(stderr) } header_json = json.dumps(header_dic) header_bytes = header_json.encode('utf-8') # 第2步:先發送報頭的長度; conn.send(struct.pack('i',len(header_bytes))) # 第3步:把報頭髮送給客戶端; conn.send(header_bytes) # 第4步:再發送真實的數據; conn.send(stdout) conn.send(stderr) except ConnectionResetError:#適用於Windows操做系統; break conn.close() phone.close()
2)、client.py
import socket import struct import json phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',18080))#ConnectionRefusedError: [WinError 10061] 因爲目標計算機積極拒絕,沒法鏈接。 while True: #一、發送命令; cmd = input('>>>:').strip() if not cmd:continue phone.send(cmd.encode('utf-8')) #二、拿到命令的結果,並打印; #第1步:先收報頭的長度; obj = phone.recv(4) header_size = struct.unpack('i',obj)[0] #第2步,再收報頭; header_bytes = phone.recv(header_size) #第3步,從報頭中解析出真實的數據的描述信息; header_json= header_bytes.decode('utf-8') header_dic = header_json.loads(header_json) print(header_dic) total_size = header_dic['total_size'] # 第4步:接受真實的數據; recv_size = 0 recv_data = b'' while recv_size < total_size: res = phone.recv(1024) recv_data += res recv_size += len(res) print(recv_data.decode('utf-8')) phone.close()
3)、struct.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # __Author__:Administrator # Version:Python3.6.5 # Date:2018/6/23 0023 9:32 import struct import json header_dic = { 'filename': 'a.txt', 'md5': 'xxxx', 'total_size': 33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333 } header_json = json.dumps(header_dic) #print(header_json,type(header_json))#{"filename": "a.txt", "md5": "xxxx", "total_size": 33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333} <class 'str'> header_bytes = header_json.encode('utf-8') print(type(header_bytes))#<class 'bytes'> print(len(header_bytes))#171 # res = struct.pack('i',1230) # print(res,type(res),len(res)) # #client.recv(4) # obj = struct.unpack('i',res) # print(obj[0]) res = struct.pack('l',len(header_bytes)) print(res,len(res))
1)、server.py
import socket import os import subprocess import struct import json share_dir = r'C:\Users\Administrator\PycharmProjects\LFXC2018\第三模塊 面向對象\網絡編程\17-文件傳輸功能實現\server\share' phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) phone.bind(('127.0.0.1',28080))#0~65535,其中0~1024,系統使用; phone.listen(5) print('starting....') while True:#連接循環; conn,client_addr = phone.accept() print(client_addr) while True:#進入通訊循環; try: #一、收命令; res = conn.recv(8096)#一、單位bytes;二、1024表明最大接受1024個bytes; if not res:break#僅適用於Linux操做系統; #二、解析命令,提取相應命令參數; cmds = res.decode('utf-8').split()#['get','a.txt'] filename = cmds[1] #三、以讀的方式打開文件,讀取文件內容,發送給客戶端; # 第1步:製做固定長度的報頭; header_dic = { 'filename':filename,#'filename':'xxx' 'md5':'xxdxxx', 'file_size':os.path.getsize(r'%s\%s'%(share_dir,filename)) } header_json = json.dumps(header_dic) header_bytes = header_json.encode('utf-8') # 第2步:先發送報頭的長度; conn.send(struct.pack('i',len(header_bytes))) # 第3步:把報頭髮送給客戶端; conn.send(header_bytes) # 第4步:再發送真實的數據; with open('%s\%s'%(share_dir,filename),'rb') as f: #conn.send(f.read())#避免使用該方法,大文件將會佔用過多內存; for line in f:#節省內存的方案; conn.send(line) except ConnectionResetError:#適用於Windows操做系統; break conn.close() phone.close()
2)、client.py
import socket import struct import json download_dir =r'C:\Users\Administrator\PycharmProjects\LFXC2018\第三模塊 面向對象\網絡編程\17-文件傳輸功能實現\client\download' phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',28080))#ConnectionRefusedError: [WinError 10061] 因爲目標計算機積極拒絕,沒法鏈接。 while True: #一、發送命令; cmd = input('>>>:').strip()#get a.txt if not cmd:continue phone.send(cmd.encode('utf-8')) #二、以寫的方式打開一個新文件,接收服務端發來的文件的內容寫入客戶的新文件; #第1步:先收報頭的長度; obj = phone.recv(4) header_size = struct.unpack('i',obj)[0] #第2步,再收報頭; header_bytes = phone.recv(header_size) #第3步,從報頭中解析出真實的數據的描述信息; header_json= header_bytes.decode('utf-8') header_dic = json.loads(header_json) print(header_dic) total_size = header_dic['file_size'] filename = header_dic['filename'] # 第4步:接收真實的數據; with open('%s\%s'%(download_dir,filename),'wb') as f: recv_size = 0 while recv_size < total_size: line = phone.recv(1024) f.write(line) recv_size += len(line) print('總大小%s 已下載大小:%s'%(total_size,recv_size)) phone.close()
3)、struct.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # __Author__:Administrator # Version:Python3.6.5 # Date:2018/6/23 0023 9:32 import struct import json header_dic = { 'filename': 'a.txt', 'md5': 'xxxx', 'total_size': 33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333 } header_json = json.dumps(header_dic) #print(header_json,type(header_json))#{"filename": "a.txt", "md5": "xxxx", "total_size": 33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333} <class 'str'> header_bytes = header_json.encode('utf-8') print(type(header_bytes))#<class 'bytes'> print(len(header_bytes))#171 # res = struct.pack('i',1230) # print(res,type(res),len(res)) # #client.recv(4) # obj = struct.unpack('i',res) # print(obj[0]) res = struct.pack('l',len(header_bytes)) print(res,len(res))