1. 程式人生 > >標號(7):python(就業階段)——網路TCP

標號(7):python(就業階段)——網路TCP

<1>TCP概念

英文全拼(Transmission Control Protocol)簡稱傳輸控制協議,它是一種面向連線的、可靠的、基於位元組流的傳輸層通訊協議.

<2>TCP特點
 1、 面向連線

TCP不適用於廣播的應用程式,基於廣播的應用程式請使用UDP協議。這種連線是一對一的。

 2.、可靠傳輸

TCP採用傳送應答機制:TCP傳送的每個報文段都必須得到接收方的應答才認為這個TCP報文段傳輸成功

 3、超時重傳

傳送端發出一個報文段之後就啟動定時器,如果在定時時間內沒有收到應答就重新發送這個報文段。

 4、錯誤校驗

由傳送端計算,然後由接收端驗證,其目的是為了檢測資料在傳送端到接收端之間是否有改動,如果接收方檢測到校驗和有差錯,則直接丟棄這個資料包。

 5、流量控制和阻塞管理

流量控制用來避免主機發送得過快而使接收方來不及完全收下。

<3>TCP的優缺點

優點:可靠,穩定、適合傳輸大量資料。
缺點:傳輸速度較udp慢、佔用系統資源高。

<4>TCP和UDP區別

tcp udp
TCP面向連線 UDP是不面向連線
TCP提供可靠的資料傳輸 UDP不保證可靠的資料傳輸,容易出現丟包情況
TCP需要連線傳輸速度慢 UDP不需要連線傳輸速度快
TCP不支援發廣播 UDP支援發廣播
TCP對系統資源要求較多 UDP對系統資源要求較少
TCP適合傳送大量資料 UDP適合傳送少量資料
TCP有流量控制 UDP沒有流量控制

<5>TCP使用場景

當對網路通訊質量有要求的時候

<6>TCP客戶端

所謂的客戶端,就是需要被服務的一方,而伺服器端就是提供服務的一方.

<7>TCP伺服器

  完成一個tcp伺服器的功能,需要的流程如下:

(1)socket建立一個套接字
(2)bind繫結ip和port
(3)listen使套接字變為可以被動連結
(4)accept等待客戶端的連結
(5)recv/send接收發送資料

<8>TCP的注意點

1、tcp伺服器一般情況下都需要繫結埠號,否則客戶端找不到這個伺服器
2、tcp客戶端一般不繫結埠號,使用隨機生成的埠號即可
3、tcp伺服器中通過listen可以將socket創建出來的主動套接字變為被動的,這是做tcp伺服器時必須要做的
4、當tcp客戶端和服務端建立好連線才可以收發資料,udp是不需要建立連線,直接就可以傳送資料
5、當一個tcp客戶端和服務端連線成功後,伺服器端會有1個新的套接字,這個套接字用來標記這個客戶端,單獨為這個客戶端服務
6、listen後的套接字是被動套接字,用來接收新的客戶端的連結請求的,而accept返回的新套接字是標記這個新客戶端的
7、關閉listen後的套接字意味著被動套接字關閉了,會導致新的客戶端不能夠連結伺服器,但是之前已經連結成功的客戶端正常通訊。
8、關閉accept返回的套接字意味著這個客戶端已經服務完畢
9、當客戶端的套接字呼叫close後,伺服器端會recv解堵塞,並且返回的長度為0,因此伺服器可以通過返回資料的長度來區別客戶端是否已經下線
10、tcp服務端繫結埠號,程式退出後端口號不會立即釋放,解決辦法可以設定socket選項,讓程式退出埠號立即釋放,也稱為埠號複用

<補充>判斷檔案是否存在

import os -> os.path.exists(“檔名”)

<9>TCP的三次握手(建立連線時)
1、符號

(1)SYN: 表示連線請求
(2)ACK: 表示確認
(3)FIN: 表示關閉連線
(4)seq:表示報文序號
(5)ack: 表示確認序號

2、含義:

(1)第一次握手:Client將標誌位SYN置為1,隨機產生一個值seq=J,並將該資料包傳送給Server,Client進入SYN_SENT狀態,等待Server確認。
(2)第二次握手:Server收到資料包後由標誌位SYN=1知道Client請求建立連線,Server將標誌位SYN和ACK都置為1,ack (number )=J+1,隨機產生一個值seq=K,並將該資料包傳送給Client以確認連線請求,Server進入SYN_RCVD狀態。
(3)第三次握手:Client收到確認後,檢查ack是否為J+1,ACK是否為1,如果正確則將標誌位ACK置為1,ack=K+1,並將該資料包傳送給Server,Server檢查ack是否為K+1,ACK是否為1,如果正確則連線建立成功,Client和Server進入ESTABLISHED狀態,完成三次握手,隨後Client與Server之間可以開始傳輸資料了。

<10>TCP的4次揮手(斷開連線時)

(1)第一次揮手:Client傳送一個FIN,用來關閉Client到Server的資料傳送。
(2)第二次揮手:Server收到FIN後,傳送一個ACK給Client,確認序號為收到序號+1。
(3)第三次揮手:Server傳送一個FIN,用來關閉Server到Client的資料傳送。
(4)第四次揮手:Client收到FIN後,接著傳送一個ACK給Server,確認序號為收到序號+1。
等待1-2分鐘,沒有收到服務端的關閉請求,才真正關閉

<11>wireshark抓包工具使用

1、通過interface List -> 獲取互動列表
2、通過ip地址找到對應的那個點選start選項,然後會顯示捕獲的資料列表
3、.在Fileter中輸入過濾條件 3.在Fileter中輸入過濾條件
4、點選任意一行獲取詳細資訊

<12>檔案下載器——示例程式碼

1、客戶端

import socket

if __name__ == '__main__':
    # 建立tcp客戶端套接字
    tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 和服務端應用程式建立連線
    tcp_client_socket.connect(("192.168.14.99", 8080))
    # 傳送下載檔案的請求
    file_name = input("請輸入您要下載的檔名:")
    file_name_data = file_name.encode("utf-8")
    # 傳送請求資料
    tcp_client_socket.send(file_name_data)
    # 把資料寫入到下載檔案裡面
    with open("/home/python/Desktop/" + file_name, "wb") as file:
        while True:
            # 迴圈接收服務端傳送的檔案資料
            file_data = tcp_client_socket.recv(1024)
            if file_data:
                file.write(file_data)
            else:
                print("服務端把資料傳送完成並關閉連線了")
                break

    # 關閉客戶端套接字
    tcp_client_socket.close()

2、服務端

import socket
import os


if __name__ == '__main__':
    # 建立tcp服務端套接字
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 繫結埠號
    tcp_server_socket.bind(("", 8080))
    # 設定監聽,把主動套接字變成被動套接字,服務端套接字只負責接收客戶端的連線請求
    tcp_server_socket.listen(128)
    # 迴圈呼叫accept可以支援多個客戶端連線服務端,但是不能同時多個客戶端連線伺服器端,因為是同步下載的
    # 一個客戶端下載完成以後另外一個客戶端才能和服務端建立連線下載對應的檔案
    while True:
        # 等待接收客戶端的連線請求
        service_client_socket, ip_port = tcp_server_socket.accept()
        print("客戶端連線成功了:", ip_port)
        # 接收客戶端的請求資訊
        file_name_data = service_client_socket.recv(1024)
        # 對二進位制資料進行解碼
        file_name = file_name_data.decode("utf-8")
        # 判斷檔案是否存在
        if os.path.exists(file_name):
            # 檔案存在
            # 開啟檔案, with open 關閉檔案操作不需要程式設計師自己去做,有系統去做
            with open(file_name, "rb") as file:
                # 讀取檔案資料
                while True:
                    # 迴圈讀取檔案資料
                    file_data = file.read(1024)
                    if file_data:
                        # 表示讀到資料,然後把資料傳送給客戶端
                        service_client_socket.send(file_data)
                    else:
                        print("請求的檔案資料傳送完成")
                        break

        else:
            print("下載的檔案伺服器不存在")

        # 終止和這個客戶端服務
        service_client_socket.close()
    # 終止客戶端連線請求服務, 服務端的套接字可以不用關閉
    tcp_server_socket.close()