1.簡單的套接字通訊
服務端
1 ''' 2 服務端 接電話 3 客戶端 打電話 4 1.先啓動服務端 5 2.服務端有兩種套接字 6 1.phone 用來幹接收連接的 7 2.conn 用來幹收發消息的 8 9 ''' 10 import socket 11 # 1.買手機 12 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 基於網絡通訊的 基於tcp通訊的套接字 13 # print(phone) 14 # <socket.socket fd=416, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0> 15 16 # 2.綁定手機卡(IP地址) 運行這個軟件的電腦IP地址 ip和端口都應該寫到配置文件中 17 phone.bind(('127.0.0.1',8080)) # 端口0-65535 0-1024 給操縱系統 18 19 # 3.開機 20 phone.listen(5) # 5 表明最大掛起的連接數 21 22 # 4.等電話連接 23 print('starting...') 24 # res = phone.accept() #底層 就是 tcp 三次握手 25 # print(res) 26 # (<socket.socket fd=476, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 58886)>, ('127.0.0.1', 58886)) 27 conn,client_addr = phone.accept() # conn 電話線 拿到能夠收發消息的管道 conn對象 28 29 # 5.收發消息 30 data = conn.recv(1024) # 1024個字節 1.單位:bytes 2.1024表明最大接收1024個bytes 31 print(data) 32 33 conn.send(data.upper()) 34 35 # 6.掛電話 36 conn.close() 37 38 # 7.關機 39 phone.close()
客戶端
1 ''' 2 服務端 接電話 3 客戶端 打電話 4 1.客戶端有一種套接字: 5 phone 用來建鏈接請求 並用來收發消息 6 ''' 7 import socket 8 # 1.買手機 客戶端的phone 至關於服務端的 conn 9 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 基於網絡通訊的 基於tcp通訊的套接字 10 # print(phone) 11 12 # 2.撥號 (服務端的ip 和服務端的 端口) 13 phone.connect(('127.0.0.1',8080)) #phone 拿到能夠發收消息的管道 phone 對象 14 15 # 3.發收消息 bytes型 16 phone.send('hello'.encode('utf-8')) 17 data = phone.recv(1024) 18 print(data) 19 20 # 4.關閉 21 phone.close()
2.加上通訊循環
服務端
1 import socket 2 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 3 phone.bind(('127.0.0.1',8080)) 4 phone.listen(5) 5 print('strating...') 6 conn,client_addr = phone.accept() 7 print(client_addr) 8 while True: # 通訊循環 9 data = conn.recv(1024) 10 print('客戶端數據:',data) 11 conn.send(data.upper()) 12 13 conn.close() 14 phone.close()
客戶端
1 import socket 2 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 3 phone.connect(('127.0.0.1',8080)) 4 while True: # 通訊循環 5 msg = input('msg>>>:').strip() 6 phone.send(msg.encode('utf-8')) 7 data = phone.recv(1024) 8 print(data) 9 10 phone.close()
3.bug修復
端口已存在 重用一下:
http://www.cnblogs.com/linhaifeng/articles/6129246.html
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
還有一種 linux 操做系統 修改內核參數 讓os 儘量快的回收端口
有時os回收端口慢
客戶端斷開: linux 解決辦法:if not data:break
wwindows 解決辦法:try...except
問題:
這個是因爲你的服務端仍然存在四次揮手的time_wait狀態在佔用地址
windows解決辦法:
#加入一條socket配置,重用ip和端口
phone=socket(AF_INET,SOCK_STREAM)
phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
phone.bind(('127.0.0.1',8080))
linux 解決辦法:
發現系統存在大量TIME_WAIT狀態的鏈接,經過調整linux內核參數解決,
vi /etc/sysctl.conf
編輯文件,加入如下內容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
而後執行 /sbin/sysctl -p 讓參數生效。
net.ipv4.tcp_syncookies = 1 表示開啓SYN Cookies。當出現SYN等待隊列溢出時,啓用cookies來處理,可防範少許SYN攻擊,默認爲0,表示關閉;
net.ipv4.tcp_tw_reuse = 1 表示開啓重用。容許將TIME-WAIT sockets從新用於新的TCP鏈接,默認爲0,表示關閉;
net.ipv4.tcp_tw_recycle = 1 表示開啓TCP鏈接中TIME-WAIT sockets的快速回收,默認爲0,表示關閉。
net.ipv4.tcp_fin_timeout 修改系統默認的 TIMEOUT 時間
服務端
1 import socket 2 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 3 phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 4 phone.bind(('127.0.0.1',8080)) #若是端口已被佔用 就換一個 5 phone.listen(5) 6 print('strating...') 7 conn,client_addr = phone.accept() # conn 三次握手的成果 雙向連接 8 print(client_addr) 9 while True: # 通訊循環 10 try: # try...except 出異常適合windows 出異常這裏指客戶端斷開 11 data = conn.recv(1024) # 如何客戶端 斷開了 linux 就會死循環 12 # if not data:break # 出異常纔會有 # 這裏適合linux 出異常指客戶端斷開 13 print('客戶端數據:',data) 14 conn.send(data.upper()) 15 except ConnectionResetError: # 適用windows os 16 break 17 18 conn.close() 19 phone.close()
客戶端
send 能夠發 空 # 發給了os的內存 在調用網卡 發送數據
recv 不能夠 收空 # 到了os的內存 在傳給了應用程序內存
因此 客戶端 就卡住了 if not msg:continue 卡住緣由 os 不會發''數據
1 import socket 2 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 3 4 phone.connect(('127.0.0.1',8080)) 5 while True: # 通訊循環 6 msg = input('msg>>>:').strip() # '' 7 if not msg:continue 8 # 這個調用了硬件 應用程序裏的內存傳給了os的內存,由os 調用網卡傳數據 9 phone.send(msg.encode('utf-8')) # b'' 10 # print('has send') # 打印了 證實能夠 發 空 '' 11 # 和os要數據,你幫我調用網卡 收數據 12 data = phone.recv(1024) 13 # print('has recv') 14 # print(data) 15 print(data.decode('utf-8')) #解碼 16 17 phone.close()
4.加上連接循環
服務端
1 ''' 2 服務端:不斷的接收客戶端的 鏈接 3 服務端accept 這裏不是併發 的效果 但能夠一個一個接收客戶端的鏈接 4 phone.listen(5) 監聽5個 5 ''' 6 import socket 7 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 8 phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 9 phone.bind(('127.0.0.1',8080)) 10 phone.listen(0) 11 print('strating...') 12 while True: #鏈接循環 沒有併發 但可一個一個 接收客戶端 幹通訊活的同時不能幹鏈接 13 conn,client_addr = phone.accept() # 如今沒併發 只能一個一個 14 print(client_addr) 15 16 while True: 17 try: 18 data = conn.recv(1024) 19 if not data:break 20 print('客戶端數據:',data) 21 conn.send(data.upper()) 22 except ConnectionResetError: 23 break 24 conn.close() 25 26 phone.close()
客戶端1
1 import socket 2 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 3 phone.connect(('127.0.0.1',8080)) 4 while True: 5 msg = input('msg>>>:').strip() # '' 6 if not msg:continue 7 phone.send(msg.encode('utf-8')) # b'' 8 data = phone.recv(1024) 9 print(data.decode('utf-8')) #解碼 10 11 phone.close()
客戶端2
1 import socket 2 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 3 phone.connect(('127.0.0.1',8080)) 4 while True: 5 msg = input('msg>>>:').strip() # '' 6 if not msg:continue 7 phone.send(msg.encode('utf-8')) # b'' 8 data = phone.recv(1024) 9 print(data.decode('utf-8')) #解碼 10 11 phone.close()
5.模擬ssh遠程執行命令
什麼叫命令?
windows:
dir:查看某一個文件夾下的子文件名與子文件夾名
ipconfig:查看本地網卡的ip信息
tasklist:查看運行的進程
Linux:
ls
ifconfig
ps aux
如何執行系統命令: 並拿到執行結果
import os
os.system # 只能拿到 運行結果 0 執行成功 非0 失敗
通常用:
import subprocess
subprocess.Popen('dir d:',shell=True) # shell 啓了一個cmd
把命令結果丟到管道里面:
subprocess.Popen('dir d:',shell=True,
stdout=subprocess.PIPE)
1 # import os 2 # res = os.system('dir d:') 3 # print(os.system('dir d:')) 4 # # print(res) 5 6 import subprocess 7 obj=subprocess.Popen('dir d:ss',shell=True, 8 stdout=subprocess.PIPE, # 正確的結果 9 stderr=subprocess.PIPE) # 錯誤的結果 10 print(obj) # 執行的結果 是bytes 11 print('stdout 1--:',obj.stdout.read().decode('gbk')) # linux 是 utf-8 windows 是 gbk 12 print('stdout 2--:',obj.stdout.read().decode('gbk')) # 由於管道沒有了 13 print('stdout 3--:',obj.stderr.read().decode('gbk')) # 錯誤管道里有 緣由 拿不到數據
服務端
1 import subprocess 2 import socket 3 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 4 # phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 重用ip和端口 任然存在4次揮手的狀態 解決辦法 5 phone.bind(('127.0.0.1',8080)) 6 phone.listen(5) 7 print('strating...') 8 while True: 9 conn,client_addr = phone.accept() 10 print(client_addr) 11 12 while True: 13 try: 14 # 1.收命令 15 cmd = conn.recv(1024) 16 if not cmd:break 17 print('客戶端數據:',cmd) 18 19 # 2.執行命令,拿到結果 20 obj = subprocess.Popen(cmd.decode('utf-8'), shell=True, # 客戶端用 utf-8發的 21 stdout=subprocess.PIPE, 22 stderr=subprocess.PIPE) 23 stdout = obj.stdout.read() 24 stderr = obj.stderr.read() 25 26 # 3.把命令的結果返回給客戶端 27 print(len(stdout)+len(stderr)) 28 conn.send(stdout+stderr) # 有效率問題的 這裏 以後 能夠優化 29 except ConnectionResetError: 30 break 31 conn.close() 32 33 phone.close()
客戶端
1 import socket 2 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 3 phone.connect(('127.0.0.1',8080)) 4 while True: 5 # 1.發命令 6 cmd = input('msg>>>:').strip() # dir ls 7 if not cmd:continue 8 phone.send(cmd.encode('utf-8')) 9 10 # 2.拿到命令的結果,並打印 11 data = phone.recv(1024) # 這裏是個坑 有可能會大於1024 接收數據量的最大限制 12 # data = phone.recv(526) # 這裏是個坑 有可能會大於1024 接收數據量的最大限制 13 14 print(data.decode('gbk')) # linux:utf-8 windows:gbk 15 16 phone.close()