網路程式通訊的流程:
1.透過ip地址找到網路中的裝置
2.透過埠號找到對應程序的埠
3.傳輸資料時還需要使用傳輸協議(TCP),保證資料的可靠性
4.socket完成程序之間網路資料的傳輸
ip地址的介紹
IP地址是網際網路協議地址(Internet Protocol Address)的縮寫,用於在IP網路中唯一標識一個裝置。它通常由四個數字組成,每個數字在0-255之間,用點號分隔。IP地址分為IPv4和IPv6兩種版本,其中IPv4是目前廣泛使用的版本。
埠和埠號的介紹
埠是計算機上用於接收和傳送資料的介面。每個埠都有一個唯一的埠號,用於標識和區分不同的服務或應用程式。常見的埠號有HTTP(80)、HTTPS(443)、FTP(21)等。
tcp的介紹
1.透過ip地址找到網路中的裝置
2.透過埠號找到對應程序的埠
3.傳輸資料時還需要使用傳輸協議(TCP),保證資料的可靠性
4.socket完成程序之間網路資料的傳輸
socket的介紹
程序之間通訊的一個工具。Socket是網路程式設計中用於程序間通訊的一個抽象層,它提供了對TCP/IP、UDP等網路通訊協議的封裝。透過Socket,應用程式可以傳送和接收資料,實現不同計算機之間的通訊。
tcp網路應用程式的開發流程
tcp客戶端程式開發
- 建立Socket物件。
- 連線到伺服器(指定IP地址和埠號)。
- 傳送和接收資料。
- 關閉連線。
import socket if __name__ == '__main__': # 1.建立tcp客戶端套接字 # socket.AF_INET:ipv4 # socket.SOCK_STREAM:tcp傳輸協議 tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 2.和服務端套接字建立連線 tcp_client_socket.connect(('192.168.198.1', 8080)) # 3.傳送資料到服務端 send_content = "請輸入要傳輸的資料" send_data = send_content.encode('utf-8') tcp_client_socket.send(send_data) # 4.接收服務端的資料 recv_data = tcp_client_socket.recv(1024) print(recv_data.decode('utf-8')) # 5.關閉套接字 tcp_client_socket.close()
tcp服務端的程式開發
- 建Socket物件。
- 繫結IP地址和埠號。
- 開始監聽連線請求。
- 接受客戶端連線。
- 傳送和接收資料。
- 關閉連線。
import socket if __name__ == "__main__": # 1.建立TCP服務端套接字 tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 2.繫結埠號 # ip地址一般不用指定,表示本機的任何一個ip即可 tcp_server_socket.bind(('', 8080)) # 3.設定監聽 # 128表示最大等待建立連線的個數 tcp_server_socket.listen(128) # 4.等待接收客戶端的連線請求 # 注意點:每次當客戶端和伺服器端建立連線成功都會返回一個新的套接字 # tcp_server_socket只負責等待接收客戶端建立連線成功,收發訊息不使用該套接字 new_client, ip_port = tcp_server_socket.accept() print("客戶端的ip地址個埠號為:", ip_port) # 5.接收資料 # 收發資訊都使用返回的這個新的套接字 recv_data = new_client.recv(1024) # 對二進位制資料進行解碼變成字串 recv_content = recv_data.decode("gbk") print("接受的資料為:", recv_content) # 6.傳送資料到客戶端 send_content = "問題正在處理中..." # 對字串進行編碼 send_data = send_content.encode("gbk") new_client.send(send_data) # 關閉服務與客戶端的套接字,表示和客戶端終止通訊 new_client.close() # 7.關閉服務端套接字,表示服務端以後不在等待接收客戶端的連線請求 tcp_server_socket.close()
設定埠號複用
在某些情況下,伺服器程式可能需要在程式重啟時立即使用之前繫結的埠號。這時可以設定埠號複用(SO_REUSEADDR)選項,允許伺服器程式立即重新繫結到該埠。
import socket if __name__ == "__main__": # 1.建立TCP服務端套接字 tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 設定埠號複用,表示意思:服務端程式退出埠號立即釋放 # 1.SOL_SOCKET:表示當前套接字 # 2.SO_REUSEADDER:表示複用埠號的選項 tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,True) # 2.繫結埠號 # ip地址一般不用指定,表示本機的任何一個ip即可 tcp_server_socket.bind(('', 8080)) # 3.設定監聽 # 128表示最大等待建立連線的個數 tcp_server_socket.listen(128) # 4.等待接收客戶端的連線請求 # 注意點:每次當客戶端和伺服器端建立連線成功都會返回一個新的套接字 # tcp_server_socket只負責等待接收客戶端建立連線成功,收發訊息不使用該套接字 new_client, ip_port = tcp_server_socket.accept() # 程式碼執行到此,說明客戶端和伺服器建立連線成功 print("客戶端的ip地址個埠號為:", ip_port) # 5.接收客戶端對的資料 # 收發資訊都使用返回的這個新的套接字 recv_data = new_client.recv(1024) print("接收的資料長度為:",len(recv_data)) # 對二進位制資料進行解碼變成字串 recv_content = recv_data.decode("gbk") print("接受的資料為:", recv_content) send_content = "問題正在處理中..." # 對字串進行編碼 send_data = send_content.encode("gbk") # 6.傳送資料到客戶端 new_client.send(send_data) # 關閉服務與客戶端的套接字,表示和客戶端終止通訊 new_client.close() # 7.關閉服務端套接字,表示服務端以後不在等待接收客戶端的連線請求 tcp_server_socket.close()
tcp網路應用程式的注意點
- 併發處理:服務端需要能夠同時處理多個客戶端的連線請求和資料傳輸。
- 異常處理:在網路程式設計中,網路故障、連線中斷等異常情況時有發生,需要編寫健壯的異常處理程式碼。
- 資源管理:合理管理Socket資源、記憶體資源等,避免資源洩漏和效能問題
- 當 TCP 客戶端程式想要和 TCP 服務端程式進行通訊的時候必須要先建立連線
- TCP 客戶端程式一般不需要繫結埠號,因為客戶端是主動發起建立連線的。
- TCP 服務端程式必須繫結埠號,否則客戶端找不到這個 TCP 服務端程式。
- listen 後的套接字是被動套接字,只負責接收新的客戶端的連線請求,不能收發訊息。
- 當TCP 客戶端程式和 TCP 服務端程式連線成功後,TCP 伺服器端程式會產生一個新的套接字,收發客戶端訊息使用該套接字。
- 關閉 accept 返回的套接字意味著和這個客戶端已經通訊完畢。
- 關閉 listen 後的套接字意味著服務端的套接字關閉了,會導致新的客戶端不能連線服務端,但是之前已經接成功的客戶端還能正常通訊。
- 當客戶端的套接字呼叫 close後,伺服器端的recv 會解阻塞,返回的資料長度為0,服務端可以透過8.返回資料的長度來判斷客戶端是否已經下線,反之服務端關閉套接字,客戶端的recv 也會解阻塞,返回的資料長度也為0。
多人版tcp服務端程式
多人版TCP服務端程式需要能夠同時處理多個客戶端的連線請求和資料傳輸。這通常需要使用多執行緒或多程序技術來實現併發處理。每個客戶端連線都由一個單獨的執行緒或程序負責處理,從而實現多人同時線上通訊。
import socket if __name__ == "__main__": # 1.建立TCP服務端套接字 tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 設定埠號複用,表示意思:服務端程式退出埠號立即釋放 # 1.SOL_SOCKET:表示當前套接字 # 2.SO_REUSEADDER:表示複用埠號的選項 tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,True) # 2.繫結埠號 # ip地址一般不用指定,表示本機的任何一個ip即可 tcp_server_socket.bind(('', 8080)) # 3.設定監聽 # 128表示最大等待建立連線的個數 tcp_server_socket.listen(128) # 4.等待接收客戶端的連線請求 # 注意點:每次當客戶端和伺服器端建立連線成功都會返回一個新的套接字 # tcp_server_socket只負責等待接收客戶端建立連線成功,收發訊息不使用該套接字 # 迴圈等待接收客戶端的連線請求 while True: new_client, ip_port = tcp_server_socket.accept() # 程式碼執行到此,說明客戶端和伺服器建立連線成功 print("客戶端的ip地址個埠號為:", ip_port) # 5.接收客戶端對的資料 # 收發資訊都使用返回的這個新的套接字 recv_data = new_client.recv(1024) print("接收的資料長度為:",len(recv_data)) # 對二進位制資料進行解碼變成字串 recv_content = recv_data.decode("gbk") print("接受的資料為:", recv_content) send_content = "問題正在處理中..." # 對字串進行編碼 send_data = send_content.encode("gbk") # 6.傳送資料到客戶端 new_client.send(send_data) # 關閉服務與客戶端的套接字,表示和客戶端終止通訊 new_client.close() # 7.關閉服務端套接字,表示服務端以後不在等待接收客戶端的連線請求 tcp_server_socket.close()
socket之send和recv的原理剖析
- send:在TCP中,send函式用於向連線的對端傳送資料。資料被封裝在TCP報文中,透過網路傳輸到對端。send函式在資料被成功寫入傳送緩衝區後返回,但並不意味著資料已經被對端接收。
- recv:recv函式用於從連線的對端接收資料。它從接收緩衝區中讀取資料,並返回給呼叫者。如果接收緩衝區中沒有資料