Go?實(shí)現(xiàn)?WebSockets和什么是?WebSockets
前言
日常工作中,在不刷新頁(yè)面的情況下發(fā)送消息并獲得即時(shí)響應(yīng)是我們認(rèn)為理所當(dāng)然的事情。但在過(guò)去,啟用實(shí)時(shí)功能對(duì)開(kāi)發(fā)人員來(lái)說(shuō)是一個(gè)真正的挑戰(zhàn)。開(kāi)發(fā)者社區(qū)從 HTTP 長(zhǎng)輪詢(xún)和 AJAX 走過(guò)了漫長(zhǎng)的道路,終于找到了構(gòu)建真正實(shí)時(shí)應(yīng)用程序的解決方案。
這個(gè)解決方案以 WebSockets 的形式出現(xiàn),它可以在用戶(hù)的瀏覽器和服務(wù)器之間打開(kāi)一個(gè)交互式會(huì)話(huà)。 WebSockets 允許瀏覽器向服務(wù)器發(fā)送消息并接收事件驅(qū)動(dòng)的響應(yīng),而無(wú)需輪詢(xún)服務(wù)器以獲取回復(fù)。
目前,WebSockets 是構(gòu)建實(shí)時(shí)應(yīng)用程序的第一大解決方案:在線(xiàn)游戲、即時(shí)通訊、跟蹤應(yīng)用程序等。
本文將解釋 WebSockets 的運(yùn)作方式,然后使用 Go 語(yǔ)言構(gòu)建一個(gè)簡(jiǎn)單的 WebSocket 應(yīng)用程序。
什么是 WebSockets
簡(jiǎn)而言之,WebSocket是一種 Web 技術(shù),可以通過(guò)持久的單個(gè)套接字連接實(shí)現(xiàn)客戶(hù)端和服務(wù)器之間的雙向,全雙工通信。WebSocket 是為 Web 應(yīng)用程序開(kāi)發(fā)人員提供基本上是一個(gè)接近原始的TCP通信層。
WebSocket 連接以 HTTP 請(qǐng)求/響應(yīng)握手啟動(dòng)。如果此初始握手成功,則客戶(hù)端和服務(wù)器已同意使用為 HTTP 請(qǐng)求作為 WebSocket 連接建立的現(xiàn)有 TCP / IP 連接。只要需要一旦 WebSocket 連接服務(wù)了它的目的,它可以通過(guò)關(guān)閉握手終止,客戶(hù)端和服務(wù)器都可以啟動(dòng)。

WebSockets 標(biāo)志著 Web 開(kāi)發(fā)的轉(zhuǎn)折點(diǎn)。直到 WebSockets 的出現(xiàn),實(shí)時(shí)網(wǎng)絡(luò)難以實(shí)現(xiàn)和慢于我們習(xí)慣于現(xiàn)在;它是通過(guò)使用像 Ajax 和 Comet? ?(長(zhǎng))輪詢(xún)??的技術(shù)提供的技術(shù),這些輪詢(xún)沒(méi)有真正優(yōu)化用于實(shí)時(shí)應(yīng)用。
WebSocket 技術(shù)具有廣泛的適用性。您可以在不同的目的中使用它,例如后端服務(wù)之間的流數(shù)據(jù),或者通過(guò)長(zhǎng)期的全雙工連接連接前端。簡(jiǎn)而言之,WebSockets 是架構(gòu)事件驅(qū)動(dòng)的系統(tǒng)和構(gòu)建實(shí)時(shí)應(yīng)用程序和服務(wù)的絕佳選擇,在那里它必須隨時(shí)隨地提供數(shù)據(jù)所必需的數(shù)據(jù)。
我們可以將 WebSocket 用例大致分為兩個(gè)不同的類(lèi)別:
- 實(shí)時(shí)更新。通信是單向的,服務(wù)器將低延遲(通常是頻繁的)更新流式傳輸?shù)娇蛻?hù)端。想想現(xiàn)場(chǎng)體育更新、警報(bào)、實(shí)時(shí)儀表板或位置跟蹤,僅舉幾個(gè)用例
- 雙向通信。客戶(hù)端和服務(wù)器都發(fā)送和接收消息。示例包括聊天,虛擬事件和虛擬教室(最后兩個(gè)通常涉及輪詢(xún),測(cè)驗(yàn)和 Q&AS )等功能。WebSocket 還可用于支撐多用戶(hù)同步協(xié)作功能,例如同時(shí)編輯同一文檔的多個(gè)人員?
網(wǎng)絡(luò)套接字與 WebSockets
網(wǎng)絡(luò)套接字,或簡(jiǎn)稱(chēng)為套接字,用作在同一臺(tái)計(jì)算機(jī)或同一網(wǎng)絡(luò)上不同計(jì)算機(jī)上運(yùn)行的應(yīng)用程序之間交換數(shù)據(jù)的內(nèi)部端點(diǎn)。
套接字是基于 Unix 和 Windows 的操作系統(tǒng)的關(guān)鍵部分,它們使開(kāi)發(fā)人員更容易創(chuàng)建支持網(wǎng)絡(luò)的軟件。應(yīng)用程序開(kāi)發(fā)人員可以在他們的程序中包含套接字,而不是從頭開(kāi)始構(gòu)建網(wǎng)絡(luò)連接。由于網(wǎng)絡(luò)套接字用于多種網(wǎng)絡(luò)協(xié)議(HTTP、FTP 等),因此可以同時(shí)使用多個(gè)套接字。
套接字是由套接字的應(yīng)用程序編程接口 (API) 定義的一組函數(shù)調(diào)用創(chuàng)建和使用的。
有幾種類(lèi)型的網(wǎng)絡(luò)套接字:
- 數(shù)據(jù)報(bào)套接字(SOCK_DGRAM),也稱(chēng)為無(wú)連接套接字,使用用戶(hù)數(shù)據(jù)報(bào)協(xié)議 (UDP)。數(shù)據(jù)報(bào)套接字支持雙向消息流并保留記錄邊界。
- 流式套接字(SOCK_STREAM),也稱(chēng)為面向連接的套接字,使用傳輸控制協(xié)議 (TCP)、流控制傳輸協(xié)議 (SCTP) 或數(shù)據(jù)報(bào)擁塞控制協(xié)議 (DCCP)。這些套接字提供雙向、可靠、有序且不重復(fù)的數(shù)據(jù)流,沒(méi)有記錄邊界。
- 原始套接字(raw IP sockets) 通常在路由器和其他網(wǎng)絡(luò)設(shè)備中可用。這些套接字通常是面向數(shù)據(jù)報(bào)的,盡管它們的確切特性取決于協(xié)議提供的接口。大多數(shù)應(yīng)用程序不使用原始套接字。提供它們是為了支持新通信協(xié)議的開(kāi)發(fā),并提供對(duì)現(xiàn)有協(xié)議更深?yuàn)W的設(shè)施的訪(fǎng)問(wèn)。
套接字通信
每個(gè)網(wǎng)絡(luò)套接字由地址標(biāo)識(shí),地址是傳輸協(xié)議、IP 地址和端口號(hào)的三元組。
主機(jī)之間的通信主要有兩種協(xié)議:TCP 和 UDP。讓我們看看您的應(yīng)用程序如何連接到 TCP 和 UDP 套接字。
- 連接到 TCP 套接字
為了建立 TCP 連接,Go 客戶(hù)端使用 net 包中的 DialTCP 函數(shù)。 DialTCP 返回一個(gè) TCPConn 對(duì)象。建立連接后,客戶(hù)端和服務(wù)器開(kāi)始交換數(shù)據(jù):客戶(hù)端通過(guò) TCPConn 對(duì)象向服務(wù)器發(fā)送請(qǐng)求,服務(wù)器解析請(qǐng)求并發(fā)送響應(yīng),TCPConn 對(duì)象接收服務(wù)器的響應(yīng)。

此連接保持有效,直到客戶(hù)端或服務(wù)器關(guān)閉它。創(chuàng)建連接的函數(shù)如下:
客戶(hù)端代碼:
// init
tcpAddr, err := net.ResolveTCPAddr(resolver, serverAddr)
if err != nil {
// handle error
}
conn, err := net.DialTCP(network, nil, tcpAddr)
if err != nil {
// handle error
}
// send message
_, err = conn.Write({message})
if err != nil {
// handle error
}
// receive message
var buf [{buffSize}]byte
_, err := conn.Read(buf[0:])
if err != nil {
// handle error
}服務(wù)端代碼:
// init
tcpAddr, err := net.ResolveTCPAddr(resolver, serverAddr)
if err != nil {
// handle error
}
listener, err := net.ListenTCP("tcp", tcpAddr)
if err != nil {
// handle error
}
// listen for an incoming connection
conn, err := listener.Accept()
if err != nil {
// handle error
}
// send message
if _, err := conn.Write({message}); err != nil {
// handle error
}
// receive message
buf := make([]byte, 512)
n, err := conn.Read(buf[0:])
if err != nil {
// handle error
}- 連接到 UDP 套接字
與 TCP 套接字相比,使用 UDP 套接字時(shí),客戶(hù)端只需向服務(wù)器發(fā)送數(shù)據(jù)報(bào)。沒(méi)有 Accept 函數(shù),因?yàn)榉?wù)器不需要接受連接,只是等待數(shù)據(jù)報(bào)到達(dá)。

其他 TCP 函數(shù)有 UDP 對(duì)應(yīng)函數(shù);只需在上面的函數(shù)中將 TCP 替換為 UDP 即可。
客戶(hù)端:
// init
raddr, err := net.ResolveUDPAddr("udp", address)
if err != nil {
// handle error
}
conn, err := net.DialUDP("udp", nil, raddr)
if err != nil {
// handle error
}
.......
// send message
buffer := make([]byte, maxBufferSize)
n, addr, err := conn.ReadFrom(buffer)
if err != nil {
// handle error
}
.......
// receive message
buffer := make([]byte, maxBufferSize)
n, err = conn.WriteTo(buffer[:n], addr)
if err != nil {
// handle error
}服務(wù)端:
// init
udpAddr, err := net.ResolveUDPAddr(resolver, serverAddr)
if err != nil {
// handle error
}
conn, err := net.ListenUDP("udp", udpAddr)
if err != nil {
// handle error
}
.......
// send message
buffer := make([]byte, maxBufferSize)
n, addr, err := conn.ReadFromUDP(buffer)
if err != nil {
// handle error
}
.......
// receive message
buffer := make([]byte, maxBufferSize)
n, err = conn.WriteToUDP(buffer[:n], addr)
if err != nil {
// handle error
}總結(jié)
WebSocket 通信包通過(guò)單個(gè) TCP 連接提供全雙工通信通道。這意味著客戶(hù)端和服務(wù)器都可以在需要時(shí)同時(shí)發(fā)送數(shù)據(jù)而無(wú)需任何請(qǐng)求。
對(duì)于需要持續(xù)數(shù)據(jù)交換的服務(wù),例如即時(shí)通訊、在線(xiàn)游戲和實(shí)時(shí)交易系統(tǒng),WebSockets 是一個(gè)很好的解決方案。您可以在 Internet 工程任務(wù)組 (IETF) ? ?RFC 6455 規(guī)范??中找到有關(guān) WebSocket 協(xié)議的完整信息。
WebSocket 連接由瀏覽器請(qǐng)求并由服務(wù)器響應(yīng),然后建立連接。這個(gè)過(guò)程通常稱(chēng)為握手。 WebSockets 中的特殊類(lèi)型的標(biāo)頭只需要瀏覽器和服務(wù)器之間的一次握手即可建立一個(gè)在其生命周期內(nèi)保持活動(dòng)狀態(tài)的連接。
WebSocket 協(xié)議使用端口 80 進(jìn)行不安全連接,使用端口 443 進(jìn)行安全連接。 WebSocket 規(guī)范確定 ws (WebSocket) 和 wss (WebSocket Secure) 協(xié)議需要哪些統(tǒng)一的資源標(biāo)識(shí)符方案。

這是客戶(hù)端請(qǐng)求的樣子:
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin: http://example.com
這是服務(wù)器響應(yīng):
HTTP/1.1 101 Switching Protocols Upgrade: websocketConnection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat
WebSockets 解決了開(kāi)發(fā)實(shí)時(shí) Web 應(yīng)用程序的許多難題,并且與傳統(tǒng) HTTP 相比具有以下幾個(gè)優(yōu)點(diǎn):
- 輕量級(jí)報(bào)頭減少了數(shù)據(jù)傳輸開(kāi)銷(xiāo)。
- 單個(gè) Web 客戶(hù)端只需要一個(gè) TCP 連接。
WebSocket服務(wù)器可以將數(shù)據(jù)推送到 Web 客戶(hù)端。
WebSocket 協(xié)議實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單。它使用 HTTP 協(xié)議進(jìn)行初始握手。成功握手后,建立連接,WebSocket 本質(zhì)上使用原始 TCP 讀取/寫(xiě)入數(shù)據(jù)。
到此這篇關(guān)于Go 實(shí)現(xiàn) WebSockets和什么是 WebSockets的文章就介紹到這了,更多相關(guān)Go 實(shí)現(xiàn) WebSockets內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
GoFrame 框架緩存查詢(xún)結(jié)果的示例詳解
GoFrame的gdb對(duì)查詢(xún)結(jié)果的緩存處理是不是非常的優(yōu)雅。尤其是*gcache.Cache對(duì)象采用了適配器設(shè)計(jì)模式,可以輕松實(shí)現(xiàn)從單進(jìn)程內(nèi)存緩存切換為分布式的Redis緩存,本文重點(diǎn)給大家介紹GoFrame 如何優(yōu)雅的緩存查詢(xún)結(jié)果,感興趣的朋友一起看看吧2022-06-06
CMD下執(zhí)行Go出現(xiàn)中文亂碼的解決方法
需要在Go寫(xiě)的服務(wù)里面調(diào)用命令行或者批處理,并根據(jù)返回的結(jié)果做處理。但是windows下面用cmd返回中文會(huì)出現(xiàn)亂碼,本文就詳細(xì)的介紹一下解決方法,感興趣的可以了解一下2021-12-12
go使用errors.Wrapf()代替log.Error()方法示例
這篇文章主要為大家介紹了go使用errors.Wrapf()代替log.Error()的方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
使用Go和Tesseract實(shí)現(xiàn)驗(yàn)證碼識(shí)別的流程步驟
驗(yàn)證碼主要用于區(qū)分人類(lèi)用戶(hù)和機(jī)器程序,Tesseract 是一個(gè)開(kāi)源的光學(xué)字符識(shí)別(OCR)引擎,支持多種語(yǔ)言和字體,并具有較高的識(shí)別準(zhǔn)確率,它由 Google 維護(hù),并且可以通過(guò)多種編程語(yǔ)言調(diào)用,本文給大家介紹了使用Go和Tesseract實(shí)現(xiàn)驗(yàn)證碼識(shí)別的流程步驟2025-01-01
golang簡(jiǎn)單tls協(xié)議用法完整示例
這篇文章主要介紹了golang簡(jiǎn)單tls用法,分析了tls協(xié)議的使用步驟及客戶(hù)端與服務(wù)器端的相關(guān)實(shí)現(xiàn)代碼,需要的朋友可以參考下2016-07-07

