網絡 #TCP #UDP #文件下載器 #網絡通信

網絡基礎

  • 網絡把多方連接在一起,然後可以進行數據傳遞
  • 所謂的網絡編程就是:在不同的電腦上的軟件能夠進行數據傳遞,即進程之間的通信

1)IP地址

  • 如何將數據精確地傳遞到目標電腦⇒ 通過IP地址
  • 如果我們把一棟棟大房子比作一臺臺電腦,IP地址就類似這個大房子的位置。
  • IP地址的作用是:在網絡上標記唯一一臺電腦

1>查看網卡信息

  • Win中:打開終端,輸入ipconfig
    -
  • Linux:打開終端,輸入ifconfig
    -
  • 每一個縮進的塊就是一個網卡,前面的就是網卡名
  • lo表示本地環回,測試用的
  • ifconfig不僅可以查看網卡信息,還能關閉/打開網卡
sudo ifconfig 網卡名 down  # 關閉網卡
sudo ifconfig 網卡名 up  # 打開網卡
  • 小tips: Linux中,Ctrl A在終端中可以讓指針快速回到行首;Ctrl E可以回到行尾。

2>IP地址分類

  • IPv4: xxx.xxx.xxx.xxx IP 地址的第四種版本,以四個分隔的數字組成,每個數字最大值爲255。
  • IPv6: ipv4已經被瓜分完了,枯竭了。未來的趨勢,遙遠的未來。號稱可以標記每一粒沙。

192.168.88.xxx

  • 前三位標記網絡,前三位相同可以通信。後面一位標記主機。前三位叫網絡號,後一位叫主機號。主機號爲0,還有255不能用,所以一個網內最多可以有254個主機。這種就被稱爲C類IP。
  • 主機太多了,就可以以後兩位爲主機號,前兩位爲網絡號。
    在這裏插入圖片描述

3>私有IP

  • 有一部分的IP地址是屬於我們的局域網使用,也就是私網IP。它們的範圍是:

10.0.0.0~10.255.255.255
172.16.0.0~172.31.255.255
192.168.0.0~192.168.255.255

  • IP地址127.0.0.1~127.255.255.255用於迴路測試。

如127.0.0.1可以測試本機中配置的web服務器

2)端口

  • 如果把電腦比作一棟棟大房子,應用程序就是每一個住戶,電腦爲這些住戶分配門牌號。有了這些門牌號就不會串錯門,這個門牌號就叫做端口號,它是用來唯一標記應用程序的。

1>端口的分類(部分)

1.知名端口

  • 知名端口是衆所周知的端口號,範圍從0到1023

80端口分配給HTTP服務
21端口分配給FTP服務

  • 在一般情況下,一個程序需要使用知名端口時,需要有root權限

2.動態端口

  • 動態端口的範圍是從1024到65535
  • 它一般不固定分配某種服務,而是動態分配。
  • 當一個系統程序或應用程序需要網絡通信時,它向主機申請一個端口,主機從可用的端口號中分配一個供它使用。
  • 當這個程序關閉時,這個佔用的端口號隨之釋放。

2>查看端口號

netstat -an  # 查看端口狀態
lsof -i [tcp/udp]:端口號  # 知道該端口被哪個應用佔用

→具體參考這個博客,寫得很全很好←

3)socket

  • socket 插口、插排
  • socket是完成網絡通信的必備東西
  • 不同電腦的進程間如何通信?
  • 首要解決的問題是如何唯一標識一個進程,否則通信無從談起!
  • 在1臺電腦上可以通過進程號(PID)來唯一標識一個進程,但是在網絡中這是行不通的。
  • 其實TCP/IP協議族已經幫我們解決了這個問題,網絡層的“ip地址”可以唯一標識網絡中的主機,而傳輸層的“協議+端口”可以唯一標識主機中的應用進程(進程)。
  • 這樣利用ip地址,協議,端口就可以標識網絡的進程了,網絡中的進程通信就可以利用這個標誌與其它進程進行交互

創建socket

  • python 中,使用socket模塊即可:
import socket
socket.socket(AddressFamily, Type)  # 第一個參數是協議、族,第二個寫UDP或tcp
  • Address Family:可以選擇 AF_INET(用於 Internet 進程間通信) 或者 AF_UNIX(用於同一臺機器進程間通信),實際工作中常用AF_INET
  • Type:套接字類型,可以是 SOCK_STREAM(流式套接字,主要用於 TCP 協議)或者 SOCK_DGRAM(數據報套接字,主要用於 UDP 協議)
  • 創建一個tcp socket(tcp套接字)
import socket

# 創建tcp的套接字(s即套接字對象)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

# TODO 這裏使用套接字功能

# 關閉套接字
s.close()
  • 創建一個udp socket(udp套接字)
import socket

# 創建udp的套接字(s即套接字對象)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# TODO 這裏使用套接字功能

# 關閉套接字
s.close()

4)UDP

  • 傳輸控制報協議,類似於寫信
  • 只有位於同一個網絡才能進行通信

1>發送UDP

  • 在Linux中編寫代碼:
    在這裏插入圖片描述
  • Windows搜索網絡調試助手,下載
    在這裏插入圖片描述
  • 運行py文件,與該程序進行對話
    在這裏插入圖片描述
    (這裏亂碼了,編碼改成gbk即可)

2>增加循環和跳出

  • 先備份一下文件:

:w udp發送1.py
在這裏插入圖片描述

  • 循環跳出:
    在這裏插入圖片描述
  • 發送數據驗證一下:
    在這裏插入圖片描述

3>接收udp數據

  • 接收udp數據,首先需要綁定 一個端口。

在這裏插入圖片描述

這裏分配了一個8090的端口
必須綁定自己電腦的IP和端口,其它的不行

  • 其次,等待接收對方發送的數據,並打印出來
    在這裏插入圖片描述

可以試一下打印recv_data,發現是一個元組:(內容,(對方IP, 對方端口)

  • 互相發送數據:
    在這裏插入圖片描述
  • 完整代碼如下:
    在這裏插入圖片描述
  • 一個套接字可以即發又收

4>單工、半雙工、全雙工

網絡通信的概念

  • 單工:信息指向是單向的,比如收音機。
  • 半雙工:信息指向雙向,但不能同時收發,比如對講機
  • 全雙工:手機之類的。socket套接字是全雙工的。

5>創建一個UDP聊天小程序

  • 先完成主體(完成之後備份):
  • 封裝在函數內,添加一個選擇功能
    在這裏插入圖片描述
    在這裏插入圖片描述

用python3打開,先不選擇功能。拿網絡調試助手給其發送三條消息。然後終端中選擇接收功能,發現一次接收一條消息。當第四次接收時,發現程序一直在等待頁面,沒有數據就一直在那裏卡着。這說明:

操作系統,把接收到的數據入棧了。套接字對象每一次調用接收打印,操作系統就查看是否有該端口的數據,有就彈出一條數據。

如果知道別人的端口,就可以一直髮數據,操作系統會一直存着。當發送的數據足夠大足夠多時,對方電腦就會卡到崩潰。

  • 效果展示:

在這裏插入圖片描述

5)TCP

  • 傳輸控制協議(Transmission Control Protocol)是一種面向連接的可靠的,基於字節流的傳輸層協議,由ETF的RFC 793定義
  • TCP通信需要經過創建連接、數據傳遞、終止連接 三個步驟
  • TCP通信模型中,在通信開始之前,一定要先建立相關的連接,才能發送數據,類似打電話
  • TCP更穩定和可靠(丟包或是包損壞,會要求計算機重新發一份)

1>TCP特點

1.面向連接

  • 通信雙方必須先建立連接才能進行數據的傳輸,雙方都必須爲該連接分配必要的系統內核資源,以管理連接的狀態和連接上的傳輸。
  • 雙方間的數據傳輸都可以通過這一個連接進行。
  • 完成數據交換後,雙方必須斷開此連接,以釋放系統資源。
  • 這種連接是一對一的,因此TCP不適用於廣播的應用程序,基於廣播的應用程序請使用UDP協議。

2.可靠傳輸

  1. TCP採用發送應答機制
    TCP發送的每個報文段都必須得到接收方的應答才認爲這個TCP報文段傳輸成功
  2. 超時重傳
    發送端發出一個報文段之後就啓動定時器,如果在定時時間內沒有收到應答就重新發送這個報文段。
    TCP爲了保證不發生丟包,就給每個包一個序號,同時序號也保證了傳送到接收端實體的包的按序接收。然後接收端實體對已成功收到的包發回一個相應的確認(ACK);如果發送端實體在合理的往返時延(RTT)內未收到確認,那麼對應的數據包就被假設爲已丟失將會被進行重傳。
  3. 錯誤校驗
    TCP用一個校驗和函數來檢驗數據是否有錯誤;在發送和接收時都要計算校驗和。
  4. 流量控制和阻塞管理
    流量控制用來避免主機發送得過快而使接收方來不及完全收下。

3.爲什麼常用TCP而不是UDP

  • 面向連接(確認有三方交握,連接創建後才做傳輸)
  • 有序數據傳輸
  • 重發丟失的數據包
  • 捨棄重複的數據包
  • 無差值的數據傳輸
  • 阻塞/流量控制

2>tcp客戶端

  • TCP嚴格區分服務器端和客戶端
  • 服務器端,就是提供服務的一方。客戶端,就是需要被服務的一方
  • 參照下方的代碼:(讓程序當客戶端,網絡調試助手當服務器)
    在這裏插入圖片描述

send參數只有一個要發送的內容;sendto參數有要發送的內容和地址

  • 接收用的網絡調試工具,選擇TCP服務器選項,然後開啓
    在這裏插入圖片描述

3>tcp服務器

1.tcp服務器1.0

  • 創建服務器的流程很固定:
  1. socket創建一個套接字
  2. listen使套接字可以變爲被動鏈接
  3. accept等待客戶端的鏈接
  4. accept等待客戶端的鏈接
  5. recv/send接收發送數據
  • 參照下方代碼,注意閱讀註釋:
    在這裏插入圖片描述
    在這裏插入圖片描述
  • 服務器的監聽套接字打開,客戶端C1和C2先連接監聽套接字,然後服務器爲其分配新套接字,客戶端與新套接字建立鏈接,與監聽套接字斷開鏈接。監聽套接字保持監聽,服務套接字負責服務。
  • 服務器先運行。
  • 服務器先收後發。

2.tcp服務器2.0(接待多個客戶端)

  • 加個循環:
    在這裏插入圖片描述
  • 打開多個網絡助手向其發送數據(也可以使用之前寫好的客戶端程序)
    在這裏插入圖片描述
  • 強行退出的話,再次打開會發現端口被佔用(其實等待一段時間就好,不想等的話,看下面的解決辦法)
    在這裏插入圖片描述
  • 可以:
  1. net -anp | grep 端口號 # 查看該端口是否被佔用
  2. fuser -vn tcp 端口號 # 查看佔用該端口的進程
  3. kill -s 9 查出來的PID # 殺死該進程,PID就是進程號
  4. ps # 查看所有進程號,以檢查是否被真正殺死

3.tcp服務器3.0(斷開鏈接,保持鏈接)

  • 現在在接待客戶端時有個問題,每個客戶端執行了一次操作後,就需要再次鏈接了。(加循環,輔助條件判斷退出)
  • 因爲上面在循環,所以監聽套接字不可能退出(輔助條件判斷退出)。
  • 因爲兩個需求都要輔助條件判斷退出,所以定義一個方法。
  • 看下列代碼:
    在這裏插入圖片描述
    在這裏插入圖片描述
  • 效果:
    在這裏插入圖片描述
    在這裏插入圖片描述

4.tcp服務器

  • 以下是在2.0的基礎上進行操作的,請複製2.0版本到4.0,然後編輯
  • 每次都要輸入判斷,麻不麻煩?有沒有辦法判斷客戶端的狀態,如果客戶端主動斷開連接,就退出爲整個客戶端的服務。還真有:
  • 如果recv解堵塞,那麼有兩種可能:
  1. 客戶端數據已經發送過來了
  2. 客戶端調用了close()斷開連接
  • 由於不能發送空數據,所以只要判斷是否傳來數據(沒有傳來會爲None),就可以進行分支判斷了。
  • 代碼如下:
    在這裏插入圖片描述
    在這裏插入圖片描述
  • 結果如下:
  • 在這裏插入圖片描述
  • 服務器在這裏告一段落,仍然有需要解決的問題:比如,如何同時接入多個客戶端,同時工作?後面多任務再進行補充。

4>tcp文件下載器

5>其它注意事項

  • listen(128) 中的參數是指同一時刻最大達訪問數,這個數字填多少其實沒太大關係,取決於操作系統處理的邏輯(不然高併發只要改個數字?)。這也是爲什麼Linux做服務器非常好的原因。
  • tcp&udp處理邏輯如下:
tcp_client tcp_server udp
socket socket socket
conect bind bind(若是客戶端可省)
send/recv listen sendto/recvfrom
close accept close
recv/send
close
  • 爲了保證客戶端不因多開出問題,不綁定

騰訊QQ採取半UDP半TCP,當登錄QQ時,會獲得一個動態端口。當要和他人聊天時,發送信息,首先到騰訊服務器中(服務器有固定端口),然後服務器就知道其此時此刻的端口號。然後另一方的QQ登錄時,也獲得一個動態端口。於是騰訊服務器就知道兩方端口,起到一個橋樑的作用,傳遞數據。但是,雁過拔毛,騰訊服務器會存儲聊天信息。國家規定,至少保存六個月。像騰訊這種體量的大公司,根本不刪的。

  • 關閉listen,新的客戶端不能再接入。但已經服務的客戶端依舊會服務完。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章