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


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()
相關文章
相關標籤/搜索