Socket(套接字)通信{網絡通信其實就是Socket間的通信},首先了解下概念:【來源於百度百科】
"兩個程序通過一個雙向的通信連接實現數據的交換,這個連接的一端稱為一個socket。"
可以這么說,Socket就是一個網絡編程的接口(API),它定義了一種標准,並對TCP/IP進行封裝,實現了網絡傳輸數據的能力。
這篇文章默認您已經了解IP、端口等基本網絡概念,如未了解,請移步:https://baike.baidu.com/item/IP/224599
我們想象這么一個場景,如果兩個人,想要互相送一份禮物【用某風快遞】,那么每個人都需要知道對方的什么信息?
- 地址【IP】:不然你讓快遞公司送到哪里?【不然你讓互聯網提供商把數據送到哪台電腦?】
- 姓名【端口】:一個地點不一定住一個人啊,快遞小哥怎么知道要送給誰?【一台電腦不一定只有一個程序使用網絡啊,系統怎么知道把數據傳給哪個程序?】
再一點,快遞公司有很多種,不一定非得選擇某風快遞,你也可以用某通快遞、某達快遞、某國郵政之類的,各有各的特點。在socket通信中也是這樣,分為TCP、UDP兩種。
TCP(Transmission Control Protocol,傳輸控制協議)是基於連接的協議,也就是說,在正式收發數據前,必須和對方建立可靠的連接。
UDP(User Data Protocol,用戶數據報協議)是與TCP相對應的協議。它是面向非連接的協議,它不與對方建立連接,而是直接就把數據包發送過去!
關鍵詞我已經標記出來了,配合上面的情景引入,可以很容易的理解。既然各有各的特色,那么根據生物學定理:“結構決定功能”,我們也很容易知道這倆東西肯定有不一樣的地方。
TCP,由於是基於雙方連接的情況下傳輸的,因此它的連接以及數據傳輸是非常穩定可靠的,可以使一台計算機發出的字節流完好無損的發生給另一台計算機。對要求可靠性非常高的應用程序會選擇此種通信方式。
UDP,肯定是不太穩定的了,它適用於一次只傳送少量數據、對可靠性要求不高的應用環境。其實我們常常使用的【ping】命令的工作原理就是向對方主機發送ICMP數據包【自行百度】,然后對方主機確認收到數據包,如果數據包是否到達的消息及時反饋回來,那么網絡就是通的。對了,QQ的聊天功能大部分是用UDP來實現的,因為這樣可以使得傳輸速率極快,但同時也會出現發生失敗的情況,更極端的就是遇到掉包的情況。
另外,關於Socket通信還需理解的兩對概念:長連接與短連接、異步與同步【這個概念理解起來較難,但你可以先不理解,不會妨礙你實現小項目,在你實現完幾個小項目后,再反過來看這塊,你會有恍然大悟的感覺】
1、長連接
顧名思義,長連接就是連接時間更長的連接方式:連接——>傳輸數據——>等待——>傳輸數據…………——>結束
Socket無論在是否使用都處於連接狀態,雖然占用資源更小,但安全性較差。
2、短連接
同樣也是顧名思義,短連接就是連接時間更短的連接方式,但會多次連接:連接——>傳輸數據——>結束 連接——>傳輸數據…………——>結束
SOCKET連接后發送后接收完數據后馬上斷開連接。
1、異步
報文發送和接收是分開的,相互獨立的,互不影響。這種方式又分兩種情況:
(1)異步雙工:接收和發送在同一個程序中,由兩個不同的子進程分別負責發送和接收
(2)異步單工:接收和發送是用兩個不同的程序來完成。
2、同步
報文發送和接收是同步進行,既報文發送后等待接收返回報文。 同步方式一般需要考慮超時問題,即報文發出去后不能無限等待,需要設定超時時間,超過該時間發送方不再等待讀返回報文,直接通知超時返回。
在長連接中一般是沒有條件能夠判斷讀寫什么時候結束,所以必須要加長度報文頭。讀函數先是讀取報文頭的長度,再根據這個長度去讀相應長度的報文。
原諒我,同步異步實在沒找到合適的圖,我也實在想不出怎么來舉栗子能讓讀者更好的理解。我個人經歷是:做了個評測機【評測機和網站服務器間用socket傳輸數據】后才理解的。
下面我們就得了解這些快遞公司到底如何實現交互的?
先看這個圖,其實這個圖就可以概括一切了,但是為了讓大部分更好的理解,我再解釋下的。
首先,客戶端和服務端會分別新建一個socket,服務端的socket需要通過bind()來綁定上端口,啟動listen()進行實時監聽,並等待客戶端的接入,即accept()。而客戶端則需要通過服務器IP和端口兩個參數來建立connect()連接,此時,服務器會得到有新客戶端連接的信息,啟動read()等待客戶端數據的傳人,客戶端如果成功接收到服務端的連接成功后,繼續執行write()來向服務端發生數據,同理,服務端也使用這樣的模式回饋客戶端的數據,知道客戶端關閉,服務端會收到客戶端退出連接的消息,服務器重新進入等待狀態,等待新客戶端的進入。
下面是用python寫的示例,其他語言也都遵循上面的標准,C++采用的擴展庫來實現的,在<WINSOCKET2>這個庫中實現。
1 import socket 2 #服務端 3 new_socket = socket.socket() # 創建 socket 對象 4 ip = "127.0.0.1" # 獲取本地主機名 5 port = 52052 # 設置端口 6 new_socket.bind((ip, port)) # 綁定端口 7 new_socket.listen(5) # 等待客戶端連接並設置最大連接數 8 while True: 9 new_cil, addr = new_socket.accept() # 建立客戶端連接。 10 print('新進來的客戶端的地址:', addr) 11 print(new_cil.recv().decode()) 12 new_cil.send('答案為6') 13 new_cil.close() # 關閉連接
import socket #客戶端 ip = "127.0.0.1" port = 52052 new_socket = socket.socket() #創建socket對象 new_socket.connect((ip,port)) #連接 new_socket.send("請求給我計算下1+5=多少?".encode(encoding='utf-8')) #發生數據 print("客戶端發給服務端:請求給我計算下1+5=多少?") back_str = new_socket.recv().decode() #結束數據 print("服務端發給客戶端:"+back_str) new_socket.close() #關閉客戶端 print("客戶端結束運行")
人生苦短,我用python!隔壁C語言實現這個至少200行代碼!