Python-TCP實現socket通信

1、套接字工作流程

  1. 服務器端先初始化Socket,建立一個套接字
  2. 與端口綁定(bind),用 bind 函數來綁定一個端口號和 IP 地址。
  3. 對端口進行監聽(listen),服務器調用 listen 函數,使服務器的這個端口和 IP 處於監聽狀態
  4. 服務器調用accept阻塞,等待客戶端連接。等待客戶機的連接。
  5. 客戶機用 socket 函數建立一個套接字,設定遠程 IP 和端口。
  6. 客戶機調用 connect 函數連接遠程計算機指定的端口。
  7. 服務器用 accept 函數來接受遠程計算機的連接,建立起與客戶機之間的通信。
  8. 建立連接以後,客戶機用 write 函數向 socket 中寫入數據。也可以用 read 函數讀取服務器發送來的數據。
  9. 服務器用 read 函數讀取客戶機發送來的數據,也可以用 write 函數來發送數據。
  10. 完成通信以後,用 close 函數關閉 socket 連接。

常用語法:

import socket
socket.socket(socket_family,socket_type,protocal=0)

# 獲取tcp/ip套接字
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 獲取udp/ip套接字
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

注:socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默認值爲 0。

服務端套接字函數

  • s.bind() 綁定(主機,端口號)到套接字
  • s.listen() 開始TCP監聽
  • s.accept() 被動接受TCP客戶的連接,(阻塞式)等待連接的到來

注意:bind()其中INADDR_ANY就是指定地址爲0.0.0.0的地址,這個地址事實上表示不確定地址,或“所有地址”、“任意地址”。

客戶端套接字函數

  • s.connect() 主動初始化TCP服務器連接
  • s.connect_ex() connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常

公共用途的套接字函數

  • s.recv() 接收TCP數據
  • s.send() 發送TCP數據(send在待發送數據量大於己端緩存區剩餘空間時,數據丟失,不會發完)
  • s.sendall() 發送完整的TCP數據(本質就是循環調用send,sendall在待發送數據量大於己端緩存區剩餘空間時,數據不丟失,循環調用send直到發完)
  • s.recvfrom() 接收UDP數據
  • s.sendto() 發送UDP數據
  • s.getpeername() 連接到當前套接字的遠端的地址
  • s.getsockname() 當前套接字的地址
  • s.getsockopt() 返回指定套接字的參數
  • s.setsockopt() 設置指定套接字的參數
  • s.close() 關閉套接字

面向鎖的套接字方法

  • s.setblocking() 設置套接字的阻塞與非阻塞模式
  • s.settimeout() 設置阻塞套接字操作的超時時間
  • s.gettimeout() 得到阻塞套接字操作的超時時間

面向文件的套接字的函數

  • s.fileno() 套接字的文件描述符
  • s.makefile() 創建一個與該套接字相關的文件

客戶端和服務端交互示例:

# 服務端
import socket
test=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
test.bind(('127.0.0.1',8080))  # 綁定的IP和端口
test.listen(5)  # 參數表示最大可以掛起的連接數
conn,client_addr=test.accept()  # 建立的鏈接,客戶端的鏈接消息

print(conn)
print(client_addr)
client_data=conn.recv(1024) # 表示最大收取的消息
conn.send(client_data.upper()) # 將消息轉換爲大寫後發回

conn.close()  # 關閉鏈接
test.close()  # 

# 客戶端
import socket
test=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
test.connect(('127.0.0.1',8080))
test.send('hello'.encode('utf-8'))
server_data=test.recv(1024)
print('the server respond:',server_data)
test.close()

防止啓動的時候地址端口被佔用,未被釋放,可在bind前添加test.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

import socket
test=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
test.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 在鏈接異常終止後,再次啓動會複用之前的IP端口,防止資源沒有釋放而產生地址衝突
test.bind(('127.0.0.1',8080))  # 綁定的IP和端口
test.listen(5)  # 參數表示最大可以掛起的連接數
conn,client_addr=test.accept()  # 建立的鏈接,客戶端的鏈接消息

while True: #
    client_data=conn.recv(1024) # 表示最大收取的消息
    conn.send(client_data.upper()) # 將消息轉換爲大寫後發回

conn.close()  # 關閉鏈接
test.close()

提示:當客戶端發送空字符串時,服務端是不會收取的,這樣就會倒是通訊終止在當前,可以通過控制客戶端發送的內容來防止出現此問題。

 

————————————————————————————————————
參考:

  1. https://www.jianshu.com/p/f75bc9971169 作者:斷尾壁虎V
  2. https://blog.csdn.net/qq_26399665/article/details/52932755
  3. https://www.cnblogs.com/daijingkun/p/10871976.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章