Python 實現 tcp 網絡程序,發送、接收數據


TCP協議,傳輸控制協議(英語:Transmission Control Protocol,縮寫為 TCP)是一種面向連接的、可靠的、基於字節流的傳輸層通信協議,由IETF的RFC 793定義。

TCP通信需要經過創建連接、數據傳送、終止連接三個步驟。

TCP通信模型中,在通信開始之前,一定要先建立相關的鏈接,才能發送數據,類似於生活中打電話。

tcp網絡通信模型

TCP通信模型

一、tcp客戶端構建流程

tcp的客戶端要比服務器端簡單很多。

import socket
# 1.創建socket
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 2. 鏈接服務器
server_addr = ("192.168.65.149", 3000)
tcp_socket.connect(server_addr)

# 3. 發送數據
send_data = input("請輸入要發送的數據:")
tcp_socket.send(send_data.encode("gbk"))

# 4. 關閉套接字
tcp_socket.close()

二、tcp服務器構建流程

在程序中,如果想要完成一個tcp服務器的功能,需要的流程如下:

  1. socket創建一個套接字
  2. bind綁定ip和port
  3. listen使套接字變為可以被動鏈接
  4. accept等待客戶端的鏈接
  5. recv接收數據
import socket

# 創建socket
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 本地信息
address = ('', 7788)

# 綁定
tcp_server_socket.bind(address)

# 使用socket創建的套接字默認的屬性是主動的,
# 使用listen將其變為被動的,這樣就可以接收別人的鏈接了
tcp_server_socket.listen(128)

# 如果有新的客戶端來鏈接服務器,
# 那么就產生一個新的套接字專門為這個客戶端服務
# client_socket用來為這個客戶端服務
# tcp_server_socket就可以省下來專門等待其他新客戶端的鏈接
client_socket, clientAddr = tcp_server_socket.accept()

# 接收對方發送過來的數據
recv_data = client_socket.recv(1024)  # 接收1024個字節
print('接收到的數據為:', recv_data.decode('gbk'))

client_socket.close()

作為服務器而言,不可能一次只能有一個客戶端進行訪問,我們來修改下代碼,讓服務端可以一次讓多個客戶端進行連接。

import socket

# 創建socket
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 本地信息
address = ('', 7788)

# 綁定
tcp_server_socket.bind(address)

tcp_server_socket.listen(128)

while True:
    # 等待新的客戶端連接
    client_socket, clientAddr = tcp_server_socket.accept()

    # 接收對方發送過來的數據
    recv_data = client_socket.recv(1024)  # 接收1024個字節
    print('接收到的數據為:', recv_data.decode('gbk'))

    client_socket.close()

tcp_server_socket.close()

運行上面的代碼,雖然程序可以讓多個客戶端訪問了,但是從實際情況考慮,一個客戶端連接一次,不會只發一條信息吧。

那我們來給單個客戶端的服務流程增加一個循環。

import socket

# 創建socket
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 本地信息
address = ('', 7788)

# 綁定
tcp_server_socket.bind(address)

tcp_server_socket.listen(128)

while True:
    # 等待新的客戶端連接
    client_socket, clientAddr = tcp_server_socket.accept()
    while True:
        # 接收對方發送過來的數據
        recv_data = client_socket.recv(1024)  # 接收1024個字節
        print('接收到的數據為:', recv_data.decode('gbk'))

    client_socket.close()

tcp_server_socket.close()

如果客戶端不需要服務的時候,該怎么關掉連接?或者換個問題,怎么知道客戶端不需要服務了?

recv 默認會堵塞,堵塞到客戶端發來信息為止。

而當客戶端關閉的時候,會調用 close,導致recv解堵塞,並且解堵塞的時候是沒有數據的。

所以 recv 解堵塞有兩種情況,對方發過來數據或者對方調用close。

那怎么判斷客戶端調用了 close 呢?

那就是判斷收到的數據為空。

import socket

# 創建socket
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 本地信息
address = ('', 7788)

# 綁定
tcp_server_socket.bind(address)

tcp_server_socket.listen(128)

while True:
    # 等待新的客戶端連接
    client_socket, clientAddr = tcp_server_socket.accept()
    while True:
        # 接收對方發送過來的數據
        recv_data = client_socket.recv(1024)  # 接收1024個字節
        if recv_data:
            print('接收到的數據為:', recv_data.decode('gbk'))
        else:
            break
    client_socket.close()

tcp_server_socket.close()

但是,我們始終都只能同時為一個客戶端服務。

以后,學了多任務就可以實現了。

最后總結一下 TCP

1、tcp服務器一般情況下都需要綁定,否則客戶端找不到這個服務器。

2、tcp客戶端一般不綁定,因為是主動鏈接服務器,所以只要確定好服務器的ip、port等信息就好,本地客戶端可以隨機。

3、tcp服務器中通過listen可以將socket創建出來的主動套接字變為被動的,這是做tcp服務器時必須要做的。

4、當客戶端需要鏈接服務器時,就需要使用connect進行鏈接,udp是不需要鏈接而是直接發送,但是tcp必須先鏈接,只有鏈接成功才能通信。

5、當一個tcp客戶端連接服務器時,服務器端會有1個新的套接字,這個套接字用來標記這個客戶端,單獨為這個客戶端服務。

6、listen后的套接字是被動套接字,用來接收新的客戶端的鏈接請求的,而accept返回的新套接字是標記這個新客戶端的。

7、關閉listen后的套接字意味着被動套接字關閉了,會導致新的客戶端不能夠鏈接服務器,但是之前已經鏈接成功的客戶端正常通信。

8、關閉accept返回的套接字意味着這個客戶端已經服務完畢。

9、當客戶端的套接字調用close后,服務器端會recv解堵塞,並且返回的長度為0,因此服務器可以通過返回數據的長度來區別客戶端是否已經下線。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM