1. 程式人生 > >網路傳輸--TCP

網路傳輸--TCP

TCP網路程式設計

一、TCP簡介

二、TCP網路程式--客戶端

三、TCP網路程式--服務端

四、TCP知識總結

五、檔案下載案例

六、3次握手和4次揮手

回到頂部

 

一、TCP簡介TCP

1.TCP的簡介

  TCP通訊需要通過建立連結, 資料傳送, 終止連結3個步驟

  

2.TCP的特點

  面向連線: 建立間接, 通訊, 關閉連線. 這種連線方式是一對一的, 所以不支援廣播模式

  可靠傳輸

    應答機制: TCP傳送的報文段必須都得到接受方的應答,才可以進行下步傳輸

    超時重傳: TCP傳送報文段的時候, 會啟動定時器, 在規定時間內沒有迴應, 就進行重發

    錯誤校驗: 由傳送端計算,然後由接收端驗證, 在此過程中出現差誤的話, 則會直接丟棄這個包

    流量控制和阻礙管理: 根據實際情況來進行調整發送速度

  優缺點:

    優點: 可靠, 穩定傳輸資料

    缺點: 傳輸速度慢, 佔用系統資源高, 不可以進行廣播傳輸

  TCP和UDP的區別:

TCP 面向連線; UDP 是不面向連線;

TCP 提供可靠的資料傳輸,也就是說,通過 TCP 連線傳送的資料,無差錯,不丟失,不重複,且按序到達; UDP 不保證可靠的資料傳輸,容易出現丟包情況;

TCP 需要連線傳輸速度慢,UDP 不需要連線傳輸速度快

TCP 不支援發廣播; UDP 支援發廣播

TCP 對系統資源要求較多,UDP 對系統資源要求較少。

TCP 適合傳送大量資料,UDP 適合傳送少量資料

TCP 有流量控制,UDP 沒有流量控制

二、TCP網路程式--客戶端

***注意***

在使用windows的網路除錯助手的過程中, 此軟體傳出的位元組是GBK的編碼, 但接收的過程中是Unicode的編碼形式

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:Mr.yang
import socket

# 1.買個電話 -- 建立TCP套接字   引數是 地址協議版本 套接字型別
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 2.撥號 建立和伺服器的連結 tcp_socket.connect(('192.168.33.68', 8080)) # 3.傳送資料 choose = input(">>>:") tcp_socket.send(choose.encode()) # 4.接受資料 阻塞等待資料 recv返回值一般情況下 就是對方傳送的資料; 如果對方斷開了連結 返回值就是 '' recv_data = tcp_socket.recv(1024) if not recv_data: print("對方斷開連結") else: print(recv_data.decode('gbk')) # 5.關閉套接字 tcp_socket.close()
客戶端

三、TCP網路程式--服務端

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:Mr.yang
import socket

# 1.總機 - 建立TCP套接字<伺服器套接字 監聽套接字>
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 2.固定號碼 - 固定埠
server_socket.bind(('', 8888))

# 3.安裝客戶服務系統 - 主動 -> 被動監聽模式
server_socket.listen(128)

while True:
    # 4.從等待服務區取出一個客戶端用以服務 轉接到分機 - 接受連結
    # (<socket.socket 和客戶端關聯起來的套接字物件), raddr=('172.17.99.129', 53614)>, ('172.17.99.129', 53614))
    client_socket, client_addr = server_socket.accept()
    print("接受來自%s的資料請求" % str(client_socket))

    while True:
        # 5.使用分機進行深入的交流 - echo 回射伺服器
        recv_data = client_socket.recv(1024)
        print("接受資料:%s" % recv_data.decode('gbk'))
        client_socket.send(recv_data.decode('gbk').encode())
        if not  recv_data:
            print("客戶端下線了")
            break

    # 6.分機掛機
    client_socket.close()

# 7.主機掛機
server_socket.close()
服務端

四、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,因此伺服器可以通過返回資料的長度來區別客戶端是否已經下線

五、檔案下載案例

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:Mr.yang
import socket

# 1.建立和伺服器的連線
# 1.1 使用者輸入IP地址和埠
IP = input("伺服器IP:")
port = int(input("伺服器埠:"))

# 1.2 建立TCP套接字
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 1.3 連線伺服器
tcp_socket.connect((IP, port))

# 2.向伺服器傳送需要下載檔案的名稱
# 2.1 輸入檔名稱
file_name = input('需要下載的檔名稱:')

# 2.2 傳送
tcp_socket.send(file_name.encode())

# 3.一遍接收檔案資料 一遍寫入資料
# 3.1 開啟檔案用於儲存 接收到的資料
file = open("下載" + file_name, "wb")
while True:
    # 3.2 接收資料 寫入檔案
    file_data = tcp_socket.recv(4096)

    # 3.3 如果資料是'' 傳輸完成 關閉檔案 套接字  否則繼續3.2的步驟
    if not file_data:
        print("檔案下載完成")
        file.close()
        tcp_socket.close()
        break
    file.write(file_data)
客戶端
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:Mr.yang
import socket

def main():

    # 1.建立和客戶端的連線
    # 1.1 建立套接字
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    # 1.2 繫結埠
    tcp_socket.bind(('192.168.33.68', 8888))

    # 1.3 監聽
    tcp_socket.listen(128)

    # 1.4 接收連線

    while True:
        clent_socket, clent_addr = tcp_socket.accept()
        print("接收來自%s的連線" %  str(clent_socket))

        # 2.接收客戶端傳送的檔名
        # 2.1 使用和客戶關聯的套接字物件 接收資料
        file_name = clent_socket.recv(4096)
        if not file_name:
            print("客戶端已經斷開連結")
            clent_socket.close()
            continue
        # 2.2 檔名稱解碼成 str
        new_file_name = file_name.decode()

        # 3.根據檔名稱 讀取檔案資料 傳送給客戶端
        # 3.1 開啟檔案
        with open(new_file_name, "rb") as file:
            # 3.2讀取整個檔案的資料
            data = file.read() # 如果檔案大 可能導致程式出現風險

            # 3.3 向客戶端傳送資料
            clent_socket.send(data)

    tcp_socket.close()

if __name__ == '__main__':
    main()
服務端

六、3次握手和4次揮手

3次握手

              

    標誌位:

      SYN: 表示連線請求  ACK: 表示確認  FIN: 表示關閉連線  seq:表示報文序號  ack: 表示確認序號

第一次握手:
    Client將標誌位SYN置為1,隨機產生一個值seq=J,並將該資料包傳送給Server,Client進入SYN_SENT狀態,等待Server確認。

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

4次揮手

第一次揮手:Client傳送一個FIN,用來關閉Client到Server的資料傳送。

第二次揮手:Server收到FIN後,傳送一個ACK給Client,確認序號為收到序號+1。

第三次揮手:Server傳送一個FIN,用來關閉Server到Client的資料傳送。

第四次揮手:Client收到FIN後,接著傳送一個ACK給Server,確認序號為收到序號+1。