文章目錄TCP簡介TCP介紹TCP協(xié)議,傳輸控制協(xié)議(英語:Transmission Control Protocol,縮寫為 TCP)是一種面向連接的,、可靠的、基于字節(jié)流的傳輸層通信協(xié)議,,由IETF的RFC 793定義。 TCP通信需要經(jīng)過創(chuàng)建連接,、數(shù)據(jù)傳送,、終止連接三個步驟。 TCP通信模型中,,在通信開始之前,,一定要先建立相關的鏈接,才能發(fā)送數(shù)據(jù),,類似于生活中,,“打電話”" TCP特點1. 面向連接通信雙方必須先建立連接才能進行數(shù)據(jù)的傳輸,雙方都必須為該連接分配必要的系統(tǒng)內(nèi)核資源,,以管理連接的狀態(tài)和連接上的傳輸,。 雙方間的數(shù)據(jù)傳輸都可以通過這一個連接進行,。 完成數(shù)據(jù)交換后,雙方必須斷開此連接,,以釋放系統(tǒng)資源。
2. 可靠傳輸1)TCP采用發(fā)送應答機制 TCP發(fā)送的每個報文段都必須得到接收方的應答才認為這個TCP報文段傳輸成功 2)超時重傳 發(fā)送端發(fā)出一個報文段之后就啟動定時器,,如果在定時時間內(nèi)沒有收到應答就重新發(fā)送這個報文段,。 TCP為了保證不發(fā)生丟包,就給每個包一個序號,,同時序號也保證了傳送到接收端實體的包的按序接收,。然后接收端實體對已成功收到的包發(fā)回一個相應的確認(ACK);如果發(fā)送端實體在合理的往返時延(RTT)內(nèi)未收到確認,,那么對應的數(shù)據(jù)包就被假設為已丟失將會被進行重傳,。 3)錯誤校驗 TCP用一個校驗和函數(shù)來檢驗數(shù)據(jù)是否有錯誤;在發(fā)送和接收時都要計算校驗和,。 4) 流量控制和阻塞管理 流量控制用來避免主機發(fā)送得過快而使接收方來不及完全收下,。 TCP與UDP的不同點
tcp通信模型udp通信模型中,在通信開始之前,,不需要建立相關的鏈接,,只需要發(fā)送數(shù)據(jù)即可,類似于生活中,,“寫信"”
TCP網(wǎng)絡程序tcp客戶端和服務端所謂的服務器端:就是提供服務的一方,而客戶端,,就是需要被服務的一方 tcp客戶端構(gòu)建流程tcp的客戶端要比服務器端簡單很多,,如果說服務器端是需要自己買手機、查手機卡,、設置鈴聲,、等待別人打電話流程的話,那么客戶端就只需要找一個電話亭,,拿起電話撥打即可,流程要少很多 客戶端一般不綁定端口 from socket import * # 創(chuàng)建socket tcp_client_socket = socket(AF_INET, SOCK_STREAM) # 目的信息 server_ip = input("請輸入服務器ip:") server_port = int(input("請輸入服務器port:")) # 鏈接服務器 tcp_client_socket.connect((server_ip, server_port)) # 提示用戶輸入數(shù)據(jù) send_data = input("請輸入要發(fā)送的數(shù)據(jù):") tcp_client_socket.send(send_data.encode("gbk")) # 接收對方發(fā)送過來的數(shù)據(jù),,最大接收1024個字節(jié) recvData = tcp_client_socket.recv(1024) print('接收到的數(shù)據(jù)為:', recvData.decode('gbk')) # 關閉套接字 tcp_client_socket.close() 請輸入服務器ip:10.10.0.47 請輸入服務器port:8080 請輸入要發(fā)送的數(shù)據(jù):你好啊 接收到的數(shù)據(jù)為: 我很好,,你呢 網(wǎng)絡調(diào)試助手:https://www.cr173.com/soft/746079.html TCP服務器tcp服務器的構(gòu)建流程如果想要完成一個tcp服務器的功能(聯(lián)通買座機接聽電話為例子),需要的流程如下:
from socket import * # 創(chuàng)建socket tcp_server_socket = socket(AF_INET, SOCK_STREAM) # 本地信息 address = ('', 7788) # 綁定 tcp_server_socket.bind(address) # 使用socket創(chuàng)建的套接字默認的屬性是主動的,,使用listen將其變?yōu)楸粍拥模@樣就可以接收別人的鏈接了 listen里的數(shù)字表征同一時刻能連接客戶端的程度. tcp_server_socket.listen(128) # 如果有新的客戶端來鏈接服務器,,那么就產(chǎn)生一個新的套接字專門為這個客戶端服務 # client_socket用來為這個客戶端服務 # tcp_server_socket就可以省下來專門等待其他新客戶端的鏈接 # clientAddr 是元組(ip,,端口) client_socket, clientAddr = tcp_server_socket.accept() # 接收對方發(fā)送過來的數(shù)據(jù),和udp不同返回的只有數(shù)據(jù) recv_data = client_socket.recv(1024) # 接收1024個字節(jié) print('接收到的數(shù)據(jù)為:', recv_data.decode('gbk')) # 發(fā)送一些數(shù)據(jù)到客戶端 client_socket.send("thank you !".encode('gbk')) # # 關閉為這個客戶端服務的套接字,,只要關閉了,,就意味著為不能再為這個客戶端服務了,如果還需要服務,,只能再次重新連接 client_socket.close() tcp注意點
文件下載器服務器 from socket import * import sys def get_file_content(file_name): """獲取文件的內(nèi)容""" try: with open(file_name, "rb") as f: content = f.read() return content except: print("沒有下載的文件:%s" % file_name) def main(): if len(sys.argv) != 2: print("請按照如下方式運行:python3 xxx.py 7890") return else: # 運行方式為python3 xxx.py 7890 port = int(sys.argv[1]) # 創(chuàng)建socket tcp_server_socket = socket(AF_INET, SOCK_STREAM) # 本地信息 address = ('', port) # 綁定本地信息 tcp_server_socket.bind(address) # 將主動套接字變?yōu)楸粍犹捉幼? tcp_server_socket.listen(128) while True: # 等待客戶端的鏈接,,即為這個客戶端發(fā)送文件 client_socket, clientAddr = tcp_server_socket.accept() # 接收對方發(fā)送過來的數(shù)據(jù) recv_data = client_socket.recv(1024) # 接收1024個字節(jié) file_name = recv_data.decode("utf-8") print("對方請求下載的文件名為:%s" % file_name) file_content = get_file_content(file_name) # 發(fā)送文件的數(shù)據(jù)給客戶端 # 因為獲取打開文件時是以rb方式打開,,所以file_content中的數(shù)據(jù)已經(jīng)是二進制的格式,因此不需要encode編碼 if file_content: client_socket.send(file_content) # 關閉這個套接字 client_socket.close() # 關閉監(jiān)聽套接字 tcp_server_socket.close() if __name__ == "__main__": main() 客戶端 from socket import * def main(): # 創(chuàng)建socket tcp_client_socket = socket(AF_INET, SOCK_STREAM) # 目的信息 server_ip = input("請輸入服務器ip:") server_port = int(input("請輸入服務器port:")) # 鏈接服務器 tcp_client_socket.connect((server_ip, server_port)) # 輸入需要下載的文件名 file_name = input("請輸入要下載的文件名:") # 發(fā)送文件下載請求 tcp_client_socket.send(file_name.encode("utf-8")) # 接收對方發(fā)送過來的數(shù)據(jù),,最大接收1024個字節(jié)(1K) recv_data = tcp_client_socket.recv(1024) # print('接收到的數(shù)據(jù)為:', recv_data.decode('utf-8')) # 如果接收到數(shù)據(jù)再創(chuàng)建文件,,否則不創(chuàng)建 if recv_data: with open("[接收]"+file_name, "wb") as f: f.write(recv_data) # 關閉套接字 tcp_client_socket.close() if __name__ == "__main__": main() |
|