SOCKET 協(xié)議
Socket 是傳輸層協(xié)議的具體軟件實現(xiàn),它封裝了協(xié)議底層的復(fù)雜實現(xiàn)方法,為開發(fā)人員提供了便利的網(wǎng)絡(luò)連接。Socket 是網(wǎng)絡(luò)編程的基石,像 Http 的請求,MySQL 數(shù)據(jù)庫的連接等絕大部分的網(wǎng)絡(luò)連接都是基于 Socket 實現(xiàn)的。
1. 傳輸層協(xié)議
傳輸層有 TCP/UDP 兩種連接方式,所以對應(yīng)的 Socket 也有兩種不同實現(xiàn)方式,掌握 Socket 的前提是了解清楚這兩種協(xié)議。
1.1 TCP 協(xié)議
面向連接,且具備順序控制和重發(fā)機(jī)制的可靠傳輸。他的可靠性是在于傳輸數(shù)據(jù)前要先建立連接,確保要傳輸?shù)膶Ψ接许憫?yīng)才進(jìn)行數(shù)據(jù)的傳輸。因此 TCP 有個經(jīng)典的 3 次握手和 4 次揮手。
3 次握手
握手的目的是為了相互確認(rèn)通信雙方的狀態(tài)都是正常的,沒有問題后才會進(jìn)行正式的通信:
- 第一次握手:客戶端發(fā)送請求連接的消息給服務(wù)端,但發(fā)出去的消息是否到達(dá)并不清楚,要基于第二次握手的反饋;
- 第二次握手:服務(wù)端返回消息說明客戶端的消息收到了,此時它也糾結(jié)了,我的反饋信息對方有沒有收到,所以得依托第三次得握手;
- 第三次握手:客戶端反饋第二次握手的消息收到了。至此,通信雙發(fā)的發(fā)送消息和接受消息能力都得到了檢驗。
3 次握手的整個過程看著似乎有點過于謹(jǐn)慎,但是互聯(lián)網(wǎng)的初期網(wǎng)絡(luò)基礎(chǔ)設(shè)施是很落后的,丟包的概率非常大的。而且這個過程也只是在通信前期建立連接的時候進(jìn)行,3 次握手過后就是正常的消息傳輸了。
4 次揮手
4 次揮手的目的跟 3 次握手目的是一樣的,謹(jǐn)慎的確保雙方消息狀態(tài)的準(zhǔn)確:
- 第一次揮手:客戶端(服務(wù)端也可以主動斷開)向服務(wù)端說明想要關(guān)閉連接;
- 第二次揮手:服務(wù)端首先回復(fù)第一次的消息已經(jīng)收到。但是并不是立馬關(guān)閉,因為此時服務(wù)端可能還有數(shù)據(jù)在傳輸中;
- 第三次揮手:待到數(shù)據(jù)傳輸都結(jié)束后,服務(wù)端向客戶端發(fā)出消息,告知一切都準(zhǔn)備好了,我要斷開連接了;
- 第四次揮手:客戶端收到服務(wù)端的斷開信息后,給予確認(rèn)。服務(wù)端收到確認(rèn)后正式關(guān)閉??蛻舳俗约阂舶l(fā)出關(guān)閉信息,因為服務(wù)端已經(jīng)關(guān)閉了無法確認(rèn),等到一段時間后客戶端正式關(guān)閉。
1.2 UDP 協(xié)議
UDP 是一種不可靠的傳輸機(jī)制,但是它的數(shù)據(jù)報文比 TCP 小,所以相同數(shù)據(jù)的傳輸 UDP 所需的帶寬更少,傳輸速度更快。它不要事先建立連接,知道對方的地址后直接數(shù)據(jù)包就扔過去,也不保證對方有沒有收到。
2. 連接方式
我們知道 TCP 數(shù)據(jù)發(fā)送前要建立連接,UDP 不需要,而 Socket 的連接又有如下區(qū)分:
2.1 長連接
- 兩個節(jié)點建立連接并保持不斷開的狀態(tài);
- 兩邊雙向自由的進(jìn)行數(shù)據(jù)傳輸;
- 直到數(shù)據(jù)全部交互結(jié)束才斷開。
2.2 短連接
- 節(jié)點 A 向節(jié)點 B 建立連接;
- A 發(fā)送數(shù)據(jù)給 B;
- 一條數(shù)據(jù)發(fā)送完立馬斷開。
2.3 適用場景
- 連接的建立需要開銷,頻繁的重建連接容易造成資源浪費(fèi),長連接適合客戶端和服務(wù)端都比較明確且傳輸數(shù)據(jù)比較大的情況;
- 每臺服務(wù)器的連接數(shù)都是有限制的,如果太多的長連接阻塞會影響到新連接的建立。Http 是一種短連接的方式,這樣有利于他處理高并發(fā)的請求。有一種
slowHttp
的攻擊,就是利用 Http 協(xié)議的特點,故意制造了一個很長的報文,然后每次發(fā)送很少量的數(shù)據(jù),使請求一直占用最終耗盡服務(wù)器的連接。所以 Http 雖然是短連接,但是一般是等到數(shù)據(jù)傳輸完成才斷開的,我們應(yīng)該根據(jù)具體業(yè)務(wù)設(shè)置 Http 請求的超時時間。
3. socket 編程
下面的代碼實現(xiàn)了一個 Socket 的服務(wù)端服務(wù)和一個客戶端,服務(wù)端在 6000 端口上面監(jiān)聽連接,收到客戶端的連接后向客戶端發(fā)出 hello
問候語,客戶端打印出服務(wù)端發(fā)送過來的消息。
3.1 服務(wù)端
public class Server {
public static void main(String[] args) {
// 創(chuàng)建一個serverSocket監(jiān)聽本地的6000端口
try(ServerSocket server = new ServerSocket (6000)) {
// 當(dāng)有客戶端連接上就建立一個socket通道
Socket socket = server.accept();
OutputStream outputStream = socket.getOutputStream();
// 有客戶端連接上來就主動發(fā)送問候語
outputStream.write("hello".getBytes());
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.2 客戶端
public class Client {
public static void main(String[] args) {
// 根據(jù){IP}+{port}與服務(wù)器建立連接
try( Socket socket=new Socket("127.0.0.1",6000)){
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 打印服務(wù)端發(fā)送的信息
System.out.println("Client:"+bufferedReader.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}
4. websocket
Websocket 是一種升級版的 Http 服務(wù),傳統(tǒng)的 Http 服務(wù)都是客戶端發(fā)起,服務(wù)端響應(yīng),而 Websocket 支持服務(wù)端向客戶端主動推送消息,增強(qiáng)了瀏覽器的交互場景。Websocket 也是應(yīng)用層協(xié)議,跟 Http 一樣具體的實現(xiàn)都要基于 Socket,除此之外并沒有什么特殊。
5. 小結(jié)
幾乎所有的軟件都需要通信,而幾乎所有的通信都是基于 Socket 實現(xiàn)的,Socket 從軟件的層面屏蔽了傳輸層的細(xì)節(jié),開發(fā)人員可以很方便的使用。Socket 起源于 Unix,而 Unix/Linux 基本哲學(xué)之一就是“一切皆文件”,使用的時候就打開,不用就關(guān)閉。