1. 程式人生 > >第六章 - 網絡編程 - 1.簡單的套接字通信/2.加上通信循環/3.bug修復/4.加上鏈接循環/5.模擬ssh遠程執行命令

第六章 - 網絡編程 - 1.簡單的套接字通信/2.加上通信循環/3.bug修復/4.加上鏈接循環/5.模擬ssh遠程執行命令

lin 有一種 啟動服務 請求 syn攻擊 最大 效率問題 connect tin

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()

第六章 - 網絡編程 - 1.簡單的套接字通信/2.加上通信循環/3.bug修復/4.加上鏈接循環/5.模擬ssh遠程執行命令