天天看點

[python複習3]網絡通信socket TCP協定TCP介紹:UDP和TCP差別:tcp注意點

TCP介紹:

TCP協定:傳輸控制協定,是一種面向連接配接的、可靠、基于位元組流的傳輸層的通信協定,有IETF的RFC 793定義

TCP通信需要經過建立連接配接、資料傳送、終止連接配接三個步驟:

TCP通信模型中,在通信開始之前,一定要先建立相關連結,才能發送資料,類似于生活中的“打電話”

特點:面向連接配接

通信雙方必須先建立連接配接才能進行資料的傳輸,雙方都必須為該連接配接配置設定必須的系統核心資源,以管理連接配接的狀态和連接配接上的傳輸

雙方間的資料傳輸都可以通過這一個連接配接進行

完成資料交換後,雙方必須斷開此連結,已釋放資源

UDP和TCP差別:

  1. udp不區分用戶端伺服器,tcp嚴格區分
  2. udp不能确定資料是否到達接收方,
  3. tcp會有一個逾時重傳,當給接受方發送消息消息,對方如果收到會給發送方回,表示以收到,發送方在一定的時間内,如果沒有收到回複就會逾時重傳
[python複習3]網絡通信socket TCP協定TCP介紹:UDP和TCP差別:tcp注意點
[python複習3]網絡通信socket TCP協定TCP介紹:UDP和TCP差別:tcp注意點

TCP采用發送應答機制:

TCP發送的每個封包段都必須得到接收方的應答才能認為這個TCP封包段傳輸成功

逾時重傳:

發送端發出一個封包段之後就啟動定時器,如果在定時器時間内沒有收到應答就會重新發送

錯誤校驗:

TCP用一個校驗和函數來檢驗資料是否有錯誤:在發送和接受時都要計算校驗和

浏覽控制和阻塞管理:

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

tcp伺服器:

import socket

def main():
    # 建立套接字
    tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    # 綁定端口bind
    tcp_socket.bind(("",8899))

    # 設定套接字預設主動為被動listen
    tcp_socket.listen(128)  # 表示同一時間可以有128個用戶端連結

    while True:
        print("等待伺服器連結.....")
        # 等待用戶端連結accept(),然後傳回一個元組,元組第一個值是一個新的套接字,第二個值是用戶端的ip和端口
        new_socket,client_addr = tcp_socket.accept()
        print("%s伺服器鍊成功" % str(client_addr))
        while True:
            # 接受消息
            recv_Data = new_socket.recv(1024)
            print("ip位址是%s的用戶端,發來消息:%s" %(client_addr,recv_Data.decode('gbk')))

            # 如果recv解堵塞,那麼有2中方式
            # 用戶端發送過來資料
            # 用戶端調用close導緻
            # 是以這裡我們判斷用戶端發過來的資料要是為空表示用戶端調用close是以結束服務
            if  not recv_Data :
                break
            # 回複消息
            new_socket.send("你好我是你爸爸".encode("gbk"))
        print("結束服務")
        # 關閉套接字
        new_socket.close()
    tcp_socket.close()

if __name__ == "__main__":
    main()

           

tcp用戶端:

import socket 
def main():
    # 建立套接字
    tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    ip = input("請輸入人ip位址:")
    port = int(input("請輸入端口:"))
    # 連結伺服器
    tcp_socket.connect((ip,port))

    while True:
        # 發送消息
        send_Data = input("輸入你需要發送的消息:")
        if send_Data == "exit":
            break
        tcp_socket.send(send_Data.encode("gbk"))

        # 接受消息
        recv_data = tcp_socket.recv(1024)
        print("接受伺服器發來的消息:%s" % recv_data.decode('gbk'))
    
    # 關閉套接字
    tcp_socket.close()
    
if __name__ == "__main__":
    main()
	
           

tcp注意點

1.tcp伺服器一般情況下都需要綁定,否則用戶端找不到這個伺服器:

伺服器一般适用于接受請求,給人回複,如果不綁定用戶端連接配接不到

2.tcp用戶端一般不綁定,因為是主動連結伺服器,是以隻需要确定伺服器ip,port等資訊就好了,本地用戶端可以随機

3.tcp伺服器中通過listen可以将socket建立出來的主動套接字變為被動的,這是左tcp伺服器時必須需要做的

4.當用戶端需要連結伺服器是,就需要使用connect進行連結,udp是不需要連結的而是直接發送,但是tcp需要先,隻有連結成功才可以通信

5.當一個tcp用戶端連接配接伺服器時,伺服器端會有一個新的套接字,這個套接字用來标記這個用戶端,單獨為這個客戶服務

6.listen後的套接字是被動套接字,用來接收新用戶端連結請求的,而accept傳回的新套接字是标記這個新用戶端的

7.關閉listen後的套接字以為着被動套接字關閉了,會導緻新的用戶端不能連結伺服器,但是之前已經連結成功的用戶端正常通信

8.關閉accept傳回的套接字以為這個用戶端已經服務完畢

9.當用戶端的套接字調用colse後,服務端會recv解堵塞,并且傳回的長度為0,是以伺服器可以通過傳回的資料長度來差別伺服器是否已經下線

小案例:

模拟檔案下載下傳:

用戶端:

import socket

def main():
    # 建立套接字
    tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    # 請輸入下載下傳伺服器ip以及端口
    ip = input("請輸入目标伺服器IP位址:")
    port = int(input("請輸入伺服器端口:"))

    # 連結伺服器
    tcp_socket.connect((ip,port))

    # 輸入檔案名
    file_name = input('請輸入需要下載下傳的檔案:')

    # 檔案名發給伺服器
    tcp_socket.send(file_name.encode('gbk'))

    # 接受伺服器發來的消息
    recv_Data = tcp_socket.recv(1024)
    
    if recv_Data:
        # 儲存檔案
        with open('[新]'+file_name,'wb') as f:
            f.write(recv_Data)
        
    # 關閉他套接字
    tcp_socket.close()

if __name__ == "__main__":
    main()
           

服務端:

import socket

def send_file_clinet(new_socket,client_addr):
    # 接受用戶端需要下載下傳的檔案名:
    recv_Data = new_socket.recv(1024)
    print("ip位址是%s的用戶端,需要下載下傳的檔案:%s" %(client_addr,recv_Data.decode('gbk')))
    
    file_content = None
    # 打開這個檔案,讀取資料
    try:
        f = open(recv_Data,'rb')
        file_content = f.read()
        f.close()
    except Exception as ret:
        print("沒有要下載下傳的檔案(%s)" % ret)

    if file_content:
        new_socket.send(file_content)

def main():
    # 建立套接字
    tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    # 綁定端口bind
    tcp_socket.bind(("",8890))

    # 設定套接字預設主動為被動listen
    tcp_socket.listen(128)  # 表示同一時間可以有128個用戶端連結

    while True:
        print("等待伺服器連結.....")
        # 等待用戶端連結accept(),然後傳回一個元組,元組第一個值是一個新的套接字,第二個值是用戶端的ip和端口
        new_socket,client_addr = tcp_socket.accept()
        print("%s伺服器鍊成功" % str(client_addr))

        send_file_clinet(new_socket,client_addr)

        print("結束服務")
        # 關閉套接字
        new_socket.close()
    tcp_socket.close()

if __name__ == "__main__":
    main()