日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Python網絡編程之Python編寫TCP協議程序的步驟_python

作者:廣龍宇 ? 更新時間: 2022-12-09 編程語言

TCP客戶端程序開發

1. 開發 TCP 客戶端程序開發步驟回顧

  • 創建客戶端套接字對象
  • 和服務端套接字建立連接
  • 發送數據
  • 接收數據
  • 關閉客戶端套接字

2. socket 類的介紹

導入 socket 模塊?import socket

創建客戶端 socket 對象?socket.socket(AddressFamily, Type)

參數說明:

  • AddressFamily 表示IP地址類型, 分為TPv4和IPv6
  • Type 表示傳輸協議類型

方法說明:

  • connect((host, port)) 表示和服務端套接字建立連接, host是服務器ip地址,port是應用程序的端口號
  • send(data) 表示發送數據,data是二進制數據
  • recv(buffersize) 表示接收數據, buffersize是每次接收數據的長度

3. TCP 客戶端程序開發示例代碼

import socket
if __name__ == '__main__':
    # 創建tcp客戶端套接字
    # 1. AF_INET:表示ipv4
    # 2. SOCK_STREAM: tcp傳輸協議
    tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 和服務端應用程序建立連接
    tcp_client_socket.connect(("192.168.131.62", 8080))
    # 代碼執行到此,說明連接建立成功
    # 準備發送的數據
    send_data = "你好服務端,我是客戶端小黑!".encode("gbk")
    # 發送數據
    tcp_client_socket.send(send_data)
    # 接收數據, 這次接收的數據最大字節數是1024
    recv_data = tcp_client_socket.recv(1024)
    # 返回的直接是服務端程序發送的二進制數據
    print(recv_data)
    # 對數據進行解碼
    recv_content = recv_data.decode("gbk")
    print("接收服務端的數據為:", recv_content)
    # 關閉套接字
    tcp_client_socket.close()

執行結果:

b'hello'
接收服務端的數據為: hello

說明

  • str.encode(編碼格式) 表示把字符串編碼成為二進制
  • data.decode(編碼格式) 表示把二進制解碼成為字符串

網絡調試助手充當服務端程序:

TCP服務端程序開發

1. 開發 TCP 服務端程序開發步驟回顧

  • 創建服務端端套接字對象
  • 綁定端口號
  • 設置監聽
  • 等待接受客戶端的連接請求
  • 接收數據
  • 發送數據
  • 關閉套接字

2. socket 類的介紹

導入 socket 模塊
import socket

創建服務端 socket 對象
socket.socket(AddressFamily, Type)

參數說明:

  • AddressFamily 表示IP地址類型, 分為TPv4和IPv6
  • Type 表示傳輸協議類型

方法說明:

  • bind((host, port)) 表示綁定端口號, host 是 ip 地址,port 是端口號,ip 地址一般不指定,表示本機的任何一個ip地址都可以。
  • listen (backlog) 表示設置監聽,backlog參數表示最大等待建立連接的個數。
  • accept() 表示等待接受客戶端的連接請求
  • send(data) 表示發送數據,data 是二進制數據
  • recv(buffersize) 表示接收數據, buffersize 是每次接收數據的長度

3. TCP 服務端程序開發示例代碼

import socket
if __name__ == '__main__':
    # 創建tcp服務端套接字
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 設置端口號復用,讓程序退出端口號立即釋放
    tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) 
    # 給程序綁定端口號
    tcp_server_socket.bind(("", 8989))
    # 設置監聽
    # 128:最大等待建立連接的個數, 提示: 目前是單任務的服務端,同一時刻只能服務與一個客戶端,后續使用多任務能夠讓服務端同時服務與多個客戶端,
    # 不需要讓客戶端進行等待建立連接
    # listen后的這個套接字只負責接收客戶端連接請求,不能收發消息,收發消息使用返回的這個新套接字來完成
    tcp_server_socket.listen(128)
    # 等待客戶端建立連接的請求, 只有客戶端和服務端建立連接成功代碼才會解阻塞,代碼才能繼續往下執行
    # 1. 專門和客戶端通信的套接字: service_client_socket
    # 2. 客戶端的ip地址和端口號: ip_port
    service_client_socket, ip_port = tcp_server_socket.accept()
    # 代碼執行到此說明連接建立成功
    print("客戶端的ip地址和端口號:", ip_port)
    # 接收客戶端發送的數據, 這次接收數據的最大字節數是1024
    recv_data = service_client_socket.recv(1024)
    # 獲取數據的長度
    recv_data_length = len(recv_data)
    print("接收數據的長度為:", recv_data_length)
    # 對二進制數據進行解碼
    recv_content = recv_data.decode("gbk")
    print("接收客戶端的數據為:", recv_content)
    # 準備發送的數據
    send_data = "ok, 問題正在處理中...".encode("gbk")
    # 發送數據給客戶端
    service_client_socket.send(send_data)
    # 關閉服務與客戶端的套接字, 終止和客戶端通信的服務
    service_client_socket.close()
    # 關閉服務端的套接字, 終止和客戶端提供建立連接請求的服務
    tcp_server_socket.close()

執行結果:

客戶端的ip地址和端口號: ('172.16.47.209', 52472)
接收數據的長度為: 5
接收客戶端的數據為: hello

說明:

  • 更換服務端端口號
  • 設置端口號復用(推薦大家使用),也就是說讓服務端程序退出后端口號立即釋放。

解決辦法有兩種:

更換服務端端口號設置端口號復用(推薦大家使用),也就是說讓服務端程序退出后端口號立即釋放。

設置端口號復用的代碼如下:

# 參數1: 表示當前套接字
# 參數2: 設置端口號復用選項
# 參數3: 設置端口號復用選項對應的值
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)

網絡調試助手充當客戶端程序:

TCP網絡應用程序的注意點

  • 當 TCP 客戶端程序想要和 TCP 服務端程序進行通信的時候必須要先建立連接
  • TCP 客戶端程序一般不需要綁定端口號,因為客戶端是主動發起建立連接的。
  • TCP 服務端程序必須綁定端口號,否則客戶端找不到這個 TCP 服務端程序。
  • listen 后的套接字是被動套接字,只負責接收新的客戶端的連接請求,不能收發消息。
  • 當 TCP 客戶端程序和 TCP 服務端程序連接成功后, TCP 服務器端程序會產生一個新的套接字,收發客戶端消息使用該套接字。
  • 關閉 accept 返回的套接字意味著和這個客戶端已經通信完畢。
  • 關閉 listen 后的套接字意味著服務端的套接字關閉了,會導致新的客戶端不能連接服務端,但是之前已經接成功的客戶端還能正常通信。
  • 當客戶端的套接字調用 close 后,服務器端的 recv 會解阻塞,返回的數據長度為0,服務端可以通過返回數據的長度來判斷客戶端是否已經下線,反之服務端關閉套接字,客戶端的 recv 也會解阻塞,返回的數據長度也為0。

案例:多任務版TCP服務端程序開發

1. 需求

目前我們開發的TCP服務端程序只能服務于一個客戶端,如何開發一個多任務版的TCP服務端程序能夠服務于多個客戶端呢?

完成多任務,可以使用線程,比進程更加節省內存資源。

2. 具體實現步驟

  • 編寫一個TCP服務端程序,循環等待接受客戶端的連接請求
  • 當客戶端和服務端建立連接成功,創建子線程,使用子線程專門處理客戶端的請求,防止主線程阻塞
  • 把創建的子線程設置成為守護主線程,防止主線程無法退出。

3. 多任務版TCP服務端程序的示例代碼:

import socket
import threading
 
 
# 處理客戶端的請求操作
def handle_client_request(service_client_socket, ip_port):
    # 循環接收客戶端發送的數據
    while True:
        # 接收客戶端發送的數據
        recv_data = service_client_socket.recv(1024)
        # 容器類型判斷是否有數據可以直接使用if語句進行判斷,如果容器類型里面有數據表示條件成立,否則條件失敗
        # 容器類型: 列表、字典、元組、字符串、set、range、二進制數據
        if recv_data:
            print(recv_data.decode("gbk"), ip_port)
            # 回復
            service_client_socket.send("ok,問題正在處理中...".encode("gbk"))
 
        else:
            print("客戶端下線了:", ip_port)
            break
    # 終止和客戶端進行通信
    service_client_socket.close()
 
 
if __name__ == '__main__':
    # 創建tcp服務端套接字
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 設置端口號復用,讓程序退出端口號立即釋放
    tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    # 綁定端口號
    tcp_server_socket.bind(("", 9090))
    # 設置監聽, listen后的套接字是被動套接字,只負責接收客戶端的連接請求
    tcp_server_socket.listen(128)
    # 循環等待接收客戶端的連接請求
    while True:
        # 等待接收客戶端的連接請求
        service_client_socket, ip_port = tcp_server_socket.accept()
        print("客戶端連接成功:", ip_port)
        # 當客戶端和服務端建立連接成功以后,需要創建一個子線程,不同子線程負責接收不同客戶端的消息
        sub_thread = threading.Thread(target=handle_client_request, args=(service_client_socket, ip_port))
        # 設置守護主線程
        sub_thread.setDaemon(True)
        # 啟動子線程
        sub_thread.start()
 
 
    # tcp服務端套接字可以不需要關閉,因為服務端程序需要一直運行
    # tcp_server_socket.close()

執行結果:

客戶端連接成功: ('172.16.47.209', 51528)
客戶端連接成功: ('172.16.47.209', 51714)
hello1 ('172.16.47.209', 51528)
hello2 ('172.16.47.209', 51714)

socket的send和recv原理剖析

1. 認識TCP socket的發送和接收緩沖區

當創建一個TCP socket對象的時候會有一個發送緩沖區和一個接收緩沖區這個發送和接收緩沖區指的就是內存中的一片空間。

2. send原理剖析

send是不是直接把數據發給服務端?

不是,要想發數據,必須得通過網卡發送數據,應用程序是無法直接通過網卡發送數據的,它需要調用操作系統接口,也就是說,應用程序把發送的數據先寫入到發送緩沖區(內存中的一片空間),再由操作系統控制網卡把發送緩沖區的數據發送給服務端網卡?

3. recv原理剖析

recv是不是直接從客戶端接收數據?

不是,應用軟件是無法直接通過網卡接收數據的,它需要調用操作系統接口,由操作系統通過網卡接收數據,把接收的數據寫入到接收緩沖區(內存中的一片空間),應用程序再從接收緩存區獲取客戶端發送的數據

4. send和recv原理剖析圖

說明:

  • 發送數據是發送到發送緩沖區
  • 接收數據是從接收緩沖區 獲取

原文鏈接:https://blog.csdn.net/weixin_47754149/article/details/119406124

欄目分類
最近更新