網路程式設計-socket

李帅啊發表於2024-10-31

1.什麼是socket?

socket的意願是“插座”,在計算機通訊領域,socket被翻譯為“套接字”,他是計算機之間進行通訊的一種約定或者一種方式,透過socket這種約定,一臺計算機可以接受其他計算機的資料,也可以向其他計算機傳送資料。

我們把插頭插到插座上就能從電網獲得電力供應,同樣,為了遠端計算機進行資料傳輸,需要連線到因特網,而socket就是用來連線到因特網的工具。

2.Unix/Linux中的socket是什麼?

在Unix/Linux系統中,為了統一對各種硬體的操作,簡化介面,不同的硬體裝置也都被看成一個檔案,對這些檔案的操作,等同於對磁碟上普通檔案的操作。

UNIX/Linux中的一切都是檔案

檔案描述符(file descriptor)

  • 通常用 0 來表示標準輸入檔案(stdin),他對應的硬體裝置就是鍵盤。
  • 通常用 1 來表示標準輸出檔案(stdout),他對應的硬體裝置就是顯示器。

Unix/Linux程式在執行任何形式的I/O操作時,都是在讀取或者寫入一個檔案描述符,一個檔案描述符只是一個和開啟的檔案相關聯的整數,他的背後可能是一個硬碟上的普通檔案、FIFO、管道、終端、鍵盤、顯示器,甚至是一個網路連線。

我們可以透過socket()來建立一個網路連線,或者說開啟一個網路檔案,socket()的返回值就是檔案描述符,有了檔案描述符,我們就可以使用普通的檔案操作函式來傳輸資料了。

  • 用recv()讀取從遠端計算機傳來的資料;
  • 用write()向遠端計算機寫入資料;

只要使用socket()建立了連線,剩下的就是檔案操作了;網路程式設計就是如此簡單!

3.socket有哪些型別?

根據資料的傳輸方式,可以將Internet套接字分成兩種型別,透過socket()建立連線時,必須告訴它使用哪種資料傳輸方式。

3.1 流格式套接字(SOCK_STREAM)

流格式套接字(stream sockets)也叫“面向連線的套接字”,在程式碼中使用SOCK_STREAM表示。
SOCK_STREAM是一種可靠的、雙向的通訊資料流,資料可以準確無誤地到達另一臺計算機,如果損壞或者丟失,可以重新傳送。
流格式套接字有自己的糾錯機制

SOCK_STREAM的特徵

  • 資料在傳輸過程中不會消失;
  • 資料是按照傳輸順傳輸的;
  • 資料的傳送和接收不是同步的(不存在資料邊界)

可以將SOCK_STREAM比喻成一條傳送帶,只要傳送帶本身沒有問題(不會斷網),就能保證資料不丟失;同時。較晚傳送的資料不會優先到達,較早傳送的資料不會晚到達,這就保證了資料是按照順序傳遞的。

為什麼流格式套接字可以達到高質量的資料傳輸呢?這是因為它使用了 TCP 協議(The Transmission Control Protocol,傳輸控制協議),TCP 協議會控制你的資料按照順序到達並且沒有錯誤。

你也許見過 TCP,是因為你經常聽說“TCP/IP”。TCP 用來確保資料的正確性,IP(Internet Protocol,網路協議)用來控制資料如何從源頭到達目的地,也就是常說的“路由”。

假設傳送帶傳送的是水果,接收者需要湊齊 100 個後才能裝袋,但是傳送帶可能把這 100 個水果分批傳送,比如第一批傳送 20 個,第二批傳送 50 個,第三批傳送 30 個。接收者不需要和傳送帶保持同步,只要根據自己的節奏來裝袋即可,不用管傳送帶傳送了幾批,也不用每到一批就裝袋一次,可以等到湊夠了 100 個水果再裝袋。

也就是說,不管資料分幾次傳送過來,接收端只需要根據自己的要求讀取,不用非得在資料到達時立即讀取。傳送端有自己的節奏,接收端也有自己的節奏,它們是不一致的。

3.2、資料包格式套接字(SOCK_DGRAM)

資料包格式套接字(Datagram Sockets)也叫“無連線的套接字”,在程式碼中使用 SOCK_DGRAM 表示。
計算機只管傳輸資料,不作資料校驗,如果資料在傳輸中損壞,或者沒有到達另一臺計算機,是沒有辦法補救的。也就是說,資料錯了就錯了,無法重傳。

可以將 SOCK_DGRAM 比喻成高速移動的摩托車快遞,它有以下特徵:

另外,用兩輛摩托車分別傳送兩件包裹,那麼接收者也需要分兩次接收,所以“資料的傳送和接收是同步的”;換句話說,接收次數應該和傳送次數相同。

資料包套接字也使用 IP 協議作路由,但是它不使用 TCP 協議,而是使用 UDP 協議(User Datagram Protocol,使用者資料包協議)。

注意:SOCK_DGRAM 沒有想象中的糟糕,不會頻繁的丟失資料,資料錯誤只是小機率事件。

實現服務端和客戶端交流的程式

server端

import socket

# 1.構建套接字物件
sock = socket.socket()

# 2.繫結:度無端的ip和埠
sock.bind(("127.0.0.1",8899))

# 3.確定最大監聽數
sock.listen(3)

# 4.等待連線
while 1:
    print("等待伺服器連線。。。")
    #獲取客戶端的套接字物件和地址
    conn,addr = sock.accept()
    print(conn,addr)

    #conn:傳送訊息  send 方法   接收資料 recv方法
    while 1:
        msg = conn.recv(1024)
        print(msg.decode())
        if msg.decode() == "quit":
            break
        res = input("響應>>>")
        conn.send(res.encode())

client端

import socket

# 建立客戶端的套接字物件
sock = socket.socket()

# 連線伺服器
sock.connect(("127.0.0.1",8899))

while 1:
    data = input(">>>")
    sock.send(data.encode())
    if data == "quit":
        break
    res = sock.recv(1024)
    print("伺服器響應",res.decode())

互動
服務端

客戶端

超出監聽數

監聽數:只包括等待連線的客戶端,連線成功的客戶端不算數

相關文章