簡單的套接字通訊\加通訊循環\修復bug\連接循環\模擬ssh遠程執行命令

客戶端python

import socket

# 一、買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 二、打電話
phone.connect(("127.0.0.1", 8080))  # phone至關於服務端的conn

# 三、發、收消息
phone.send('hello'.encode("utf-8"))
data = phone.recv(1024)
print(data)

# 四、關閉
phone.close()

服務端linux

import socket

# 一、買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 二、綁定手機卡
phone.bind(("127.0.0.1", 8080))   # 127.0.0.1本地地址,端口範圍0-65535:其中0-1024給操做系統使用

# 三、開機
phone.listen(5)   # 5表明最大掛起鏈接數

# 四、等電話鏈接
print("starting...")
conn, client = phone.accept()

# 五、收、發消息
data = conn.recv(1024)  # 收1024個字節,接受數據的最大數。單位是bytes
print("客戶端的數據", data)
conn.send(data.upper())

# 六、掛電話
conn.close()

# 七、關機
phone.close() 

 

加循環(通訊循環)

客戶端shell

import socket

# 一、買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 二、打電話
phone.connect(("127.0.0.1", 8080))  # phone至關於服務端的conn

# 三、發、收消息
while True:
    msg = input(">> ").strip()
    phone.send(msg.encode("utf-8"))
    data = phone.recv(1024)
    print(data)

# 四、關閉
phone.close()

服務端windows

import socket

# 一、買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 二、綁定手機卡
phone.bind(("127.0.0.1", 8080))   # 127.0.0.1本地地址,端口範圍0-65535:其中0-1024給操做系統使用

# 三、開機
phone.listen(5)   # 5表明最大掛起鏈接數

# 四、等電話鏈接
print("starting...")
conn, client = phone.accept()

# 五、收、發消息
while True:
    data = conn.recv(1024)  # 收1024個字節,接受數據的最大數。單位是bytes
    print("客戶端的數據", data)
    conn.send(data.upper())

# 六、掛電話
conn.close()

# 七、關機
phone.close()

 


 修復bug

一、客戶端單方面斷開,服務端: linux 解決辦法:if not data:break
         windows 解決辦法:try...except

send 能夠發 空 # 發給了os的內存 在調用網卡 發送數據
recv 不能夠 收空 # 到了os的內存 在傳給了應用程序內存
因此 客戶端 就卡住了 if not msg:continue 卡住緣由 os 不會發''(空)數據cookie

 

  二、端口已存在,重用ssh

問題:socket

 這個是因爲你的服務端仍然存在四次揮手的time_wait狀態在佔用地址tcp

 

解決辦法1:優化

#加入一條socket配置,重用ip和端口
phone=socket(AF_INET,SOCK_STREAM)
phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
phone.bind(('127.0.0.1',8080))spa


解決辦法2:

發現系統存在大量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 時間

 

解決辦法3:

解決前面啓動多個socket程序,佔用系統端口問題。(命令提示符cmd)
linux: pkill -9 python
windows: taskkill python (打開任務管理器,找到python,關閉)


客戶端
import socket

# 一、買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 二、打電話
phone.connect(("127.0.0.1", 8080))  # phone至關於服務端的conn

# 三、發、收消息
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

# 一、買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # (若是機器中存在,從新用端口)應對端口占用報錯狀況
# 二、綁定手機卡
phone.bind(("127.0.0.1", 8080))   # 127.0.0.1本地地址,端口範圍0-65535:其中0-1024給操做系統使用

# 三、開機
phone.listen(5)   # 5表明最大掛起鏈接數

# 四、等電話鏈接
print("starting...")
conn, client = phone.accept()  # conn套接字對象

# 五、收、發消息
while True:
    try:
        data = conn.recv(1024)  # 收1024個字節,接受數據的最大數。單位是bytes
       # if not data: break         # 僅適用於Linux操做系統(客戶端單方面斷開),win 用try...except
        print("客戶端的數據", data)
        conn.send(data.upper())
    except ConnectionRefusedError:
        break

# 六、掛電話
conn.close()

# 七、關機
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", 8080))   # 127.0.0.1本地地址,端口範圍0-65535:其中0-1024給操做系統使用

# 三、開機
phone.listen(5)   # 5表明最大掛起鏈接數

# 四、等電話鏈接
print("starting...")
while True:  # 循環連接
    conn, client = phone.accept()  # conn套接字對象

    # 五、收、發消息
    while True:    # 通信循環
        try:
            data = conn.recv(1024)  # 收1024個字節,接受數據的最大數。單位是bytes
           # if not data: break  # 僅適用於Linux操做系統(客戶端斷開),win 用try...except
            print("客戶端的數據", data)
            conn.send(data.upper())
        except ConnectionRefusedError:
            break

    # 六、掛電話
    conn.close()

# 七、關機
phone.close()

客戶端1

import socket

# 一、買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 二、打電話
phone.connect(("127.0.0.1", 8080))  # phone至關於服務端的conn

# 三、發、收消息
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()

客戶端2

import socket

# 一、買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 二、打電話
phone.connect(("127.0.0.1", 8080))  # phone至關於服務端的conn

# 三、發、收消息
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()

 


 模擬ssh遠程執行命令

 

# windows
dir:查看某一個文件夾下的子文件名與文件夾名
ipconfig:查看本地網卡的ip信息
tasklist:查看運行的進程


# Linux
ls:查看某一個文件夾下的子文件名與文件夾名
ifconfig:查看本地網卡的ip信息(查看網卡的信息)
ps aux:查看運行的進程


在機器上執行系統命令
# import os
# res = os.system( ) # 只能拿到執行成功與否的標誌(0表明成功,非零表明不成功)


import subprocess
obj = subprocess.Popen("dir/",shell = True,stdout = subprocess.PIPE, stderr = subprocess.PIPE) #stdout命令正確結果


print("stdout", obj.stdout.read().decode("gbk")) # 打印出來結果(解碼linux:utf-8,windows:GBK)
print("stderr", obj.stderr.read().decode("gbk")) # 打印出來結果(解碼linux:utf-8,windows:GBK)

# import os
# res = os.system('dir d:')
# print(os.system('dir d:'))
# # print(res)

import subprocess
obj=subprocess.Popen('dir d:ss',shell=True,
                 stdout=subprocess.PIPE,  # 正確的結果
                 stderr=subprocess.PIPE)  # 錯誤的結果
print(obj)  # 執行的結果 是bytes
print('stdout 1--:',obj.stdout.read().decode('gbk'))  # linux 是 utf-8  windows 是 gbk
print('stdout 2--:',obj.stdout.read().decode('gbk'))  # 由於管道沒有了
print('stdout 3--:',obj.stderr.read().decode('gbk'))  # 錯誤管道里有 緣由 拿不到數據

服務端

import socket
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", 9900))   # 127.0.0.1本地地址,端口範圍0-65535:其中0-1024給操做系統使用

# 三、開機
phone.listen(5)   # 5表明最大掛起鏈接數

# 四、等電話鏈接
print("starting...")
while True:  # 循環連接
    conn, client = phone.accept()  # conn套接字對象

# 五、收、發消息
    while True:    # 通信循環
        try:
            # a、接收命令  (命令:執行系統命令)
            cmd = conn.recv(1024)  # 收1024個字節,接受數據的最大數。單位是bytes
           # if not data: break  # 僅適用於Linux操做系統(客戶端斷開),win 用try...except
            # b、執行命令,拿到結果
            obj = subprocess.Popen(cmd.decode("utf-8"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdout = obj.stdout.read()
            stderr = obj.stderr.read()

            # c、把命令的結果返回給客戶端
            print(len(stdout)+len(stderr))
            conn.send(stdout+stderr)  # 加是從新申請了一塊內存地址,不是在原來地方變更(是一個能夠優化的點)

        except ConnectionRefusedError:
            break

# 六、掛電話
    conn.close()

# 七、關機
phone.close()

客戶端

import socket

# 一、買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 二、打電話
phone.connect(("127.0.0.1", 9900))  # phone至關於服務端的conn

# 三、發、收消息
while True:
    # a、發命令
    cmd = input(">> ").strip()
    if not cmd:
        continue
    phone.send(cmd.encode("utf-8"))

    # b、拿命令結果並打印
    data = phone.recv(1024)   # 1024是個坑
    print(data.decode("gbk"))   # 系統發回的結果

# 四、關閉
phone.close()
相關文章
相關標籤/搜索