1. 程式人生 > >簡單的套接字通訊\加通訊迴圈\修復bug\連結迴圈

簡單的套接字通訊\加通訊迴圈\修復bug\連結迴圈

客戶端

import socket

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

# 2、打電話
phone.connect(("127.0.0.1", 8080))  # phone相當於服務端的conn

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

# 4、關閉
phone.close()

服務端

import socket

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

# 2、繫結手機卡
phone.bind(("127.0.0.1", 8080))   # 127.0.0.1本地地址,埠範圍0-65535:其中0-1024給作業系統使用

# 3、開機
phone.listen(5)   # 5代表最大掛起連線數

# 4、等電話連線
print("starting...")
conn, client = phone.accept()

# 5、收、發訊息
data = conn.recv(1024)  # 收1024個位元組,接受資料的最大數。單位是bytes
print("客戶端的資料", data)
conn.send(data.upper())

# 6、掛電話
conn.close()

# 7、關機
phone.close() 

 

加迴圈(通訊迴圈)

客戶端

import socket

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

# 2、打電話
phone.connect(("127.0.0.1", 8080))  # phone相當於服務端的conn

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

# 4、關閉
phone.close()

服務端

import socket

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

# 2、繫結手機卡
phone.bind(("127.0.0.1", 8080))   # 127.0.0.1本地地址,埠範圍0-65535:其中0-1024給作業系統使用

# 3、開機
phone.listen(5)   # 5代表最大掛起連線數

# 4、等電話連線
print("starting...")
conn, client = phone.accept()

# 5、收、發訊息
while True:
    data = conn.recv(1024)  # 收1024個位元組,接受資料的最大數。單位是bytes
    print("客戶端的資料", data)
    conn.send(data.upper())

# 6、掛電話
conn.close()

# 7、關機
phone.close()

  


加連線迴圈

客戶端

import socket

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

# 2、打電話
phone.connect(("127.0.0.1", 8080))  # phone相當於服務端的conn

# 3、發、收訊息
while True:
    msg = input(">> ").strip()
    if not msg:
        continue
    phone.send(msg.encode("utf-8"))
    data = phone.recv(1024)
    print(data.decode("utf-8"))

# 4、關閉
phone.close()

服務端

import socket

# 1、買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # (如果機器中存在,重新用埠)應對端口占用報錯情況
# 2、繫結手機卡
phone.bind(("127.0.0.1", 8080))   # 127.0.0.1本地地址,埠範圍0-65535:其中0-1024給作業系統使用

# 3、開機
phone.listen(5)   # 5代表最大掛起連線數

# 4、等電話連線
print("starting...")
while True:  # 迴圈連結
    conn, client = phone.accept()  # conn套接字物件

    # 5、收、發訊息
    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

    # 6、掛電話
    conn.close()

# 7、關機
phone.close()

  


 修復bug

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

send 可以發 空 # 發給了os的記憶體 在呼叫網絡卡 傳送資料
recv 不可以 收空 # 到了os的記憶體 在傳給了應用程式記憶體
所以 客戶端 就卡住了 if not msg:continue 卡住原因 os 不會發''(空)資料

 
2、埠已存在,重用
問題:

 


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

解決辦法1:

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

解決辦法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 時間

客戶端
import socket

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

# 2、打電話
phone.connect(("127.0.0.1", 8080))  # phone相當於服務端的conn

# 3、發、收訊息
while True:
    msg = input(">> ").strip()
    if not msg:
        continue
    phone.send(msg.encode("utf-8"))
    data = phone.recv(1024)
    print(data.decode("utf-8"))

# 4、關閉
phone.close()

  服務端

import socket

# 1、買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # (如果機器中存在,重新用埠)應對端口占用報錯情況
# 2、繫結手機卡
phone.bind(("127.0.0.1", 8080))   # 127.0.0.1本地地址,埠範圍0-65535:其中0-1024給作業系統使用

# 3、開機
phone.listen(5)   # 5代表最大掛起連線數

# 4、等電話連線
print("starting...")
conn, client = phone.accept()  # conn套接字物件

# 5、收、發訊息
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

# 6、掛電話
conn.close()

# 7、關機
phone.close()