首页 > 其他分享 >Websocket

Websocket

时间:2023-05-17 17:12:30浏览次数:43  
标签:websocket nil err Websocket http HTTP conn

websocket是什么

websocket与http一样都是OSI模型中应用层的协议,都是基于TCP协议来传输数据的,我们把这些更高级的协议理解成对TCP的封装。

socket与websocket的关系

socket与websocket的关系:就是毫无关系。
socket并不是一种协议,而是一个抽象层,将物理层、数据链路层、网络层与传输层向用户抽象成一层,用户直接使用socket封装的API即可操作这四层所带来的功能。
websocket是一种完整的应用层协议,包含一套完整的API。WebSocket API 是 HTML5 标准的一部分, 但这并不代表 WebSocket 一定要用在 HTML 中,或者只能在基于浏览器的应用程序中使用。
实际上,许多语言、框架和服务器都提供了 WebSocket 支持。

有了http协议,为什么还要有websocket协议?

非常好的一篇文章:https://blog.csdn.net/java_beautiful/article/details/127283971

文章总结

问题的痛点

Q:怎么样才能在用户不做任何操作的情况下,使客户端的数据发生实时的变化?
如果只有http协议的话,我们需要使用http不断轮询,即前端不断定时发送http请求到服务器,服务器收到请求后响应消息。这是一种伪的实时更新,只是背着用户偷偷不断发请求,用户没有感觉到罢了。这种轮询的应用场景也有很多,比如扫码登录等需要扫二维码的场景,手机发送了请求,但是网页前端不知道用户扫没扫,就需要不断向后端询问,保证用户在扫码后能立即得到回应。
只用http轮询的缺点:

  1. 当你打开F12页面时,你会发现满屏的HTTP请求。虽然很小,但这其实也消耗带宽,同时也会增加下游服务器的负担。
  2. 用户会感到明显的卡顿
  3. 所以http接口来进行前后端交互,需要用在实时交互不是很密集的场景。由于http是短连接,一旦请求后会断开与服务器的连接,因此不适合一些长时间的实时交互。但是,优点是不受网络的限制,断开重连非常之快,一般非实时的请求都会使用HTTP。

而Websocket是长连接,缺点是会受到网络波动的影响,但优点也是明显的,就是所谓的全双工通信,服务器与客户端可以实时地交换数据,很明显游戏就一定是建立在websocket协议上的。

websocket原理

我们平时刷网页,一般都是在浏览器上刷的,一会刷刷图文,这时候用的是HTTP协议,一会打开网页游戏,这时候就得切换成我们新介绍的websocket协议。 为了兼容这些使用场景。浏览器在TCP三次握手建立连接之后,都统一使用HTTP协议先进行一次通信。
如果此时是普通的HTTP请求,那后续双方就还是老样子继续用普通HTTP协议进行交互,这点没啥疑问。
如果这时候是想建立websocket连接,就会在HTTP请求里带上一些特殊的header头。

Connection: Upgrade 
Upgrade: websocket 
Sec-WebSocket-Key: T2a6wZlAwhgQNqruZ2YUyg
​
// 这些header头的意思是,浏览器想升级协议(Connection: Upgrade),并且想升级成websocket协议(Upgrade: websocket)。
// 同时带上一段随机生成的base64码(Sec-WebSocket-Key),发给服务器。

如果服务器正好支持升级成websocket协议。就会走websocket握手流程,同时根据客户端生成的base64码,用某个公开的算法变成另一段字符串,放在HTTP响应的 Sec-WebSocket-Accept 头里,同时带上101状态码(协议切换状态码),发回给浏览器。

HTTP/1.1 101 Switching Protocols
Sec-WebSocket-Accept: iBJKv/ALIW2DobfoA4dmr3JHBCY
Upgrade: websocket
Connection: Upgrade 

TCP支持全双工通信的,即双方都可以同时发送数据。而HTTP在同一时间只有客户端或者服务端一方能主动发送数据,是半双工通信。为了弥补http无法满足实时互相大量发送数据的场景,所以websocket协议被设计出来了。

websocket借鸡生蛋

websocket并不是HTTP的新协议,因为websocket只有在建立连接时才用到了HTTP,升级完成了之后就跟HTTP没有任何区别。
websocket完美继承了TCP协议的全双工能力,并且还贴心的提供了解决粘包的方案。它适用于需要服务器和客户端(浏览器)频繁交互的大部分场景。比如网页/小程序游戏,网页聊天室,以及一些类似飞书这样的网页协同办公软件。

使用Go搭建简单的websocket

这里没有使用官方的websocket包

github.com/gorilla/websocket

http升级为websocket

服务端

package main
​
import (
    "fmt"
    "github.com/gorilla/websocket"
    "log"
    "net/http"
)
​
var UP = websocket.Upgrader{
    // HandshakeTimeout:  0,     // 握手时间0为不限制
    ReadBufferSize:  1024, // 以字节为单位的IO缓冲区,如果缓冲区大小为0,则使用HTTP服务器分配的缓冲区(不为0就是读写做限制)
    WriteBufferSize: 1024, // 以字节为单位的IO缓冲区,如果缓冲区大小为0,则使用HTTP服务器分配的缓冲区(不为0就是读写做限制)
    // WriteBufferPool:   nil,   // WriteBufferPool是用于写操作的缓冲池
    // Error:             nil,   // 指定用于生成HTTP错误响应的函数
    // CheckOrigin:       nil,   // 对过来的请求做校验用的
    // EnableCompression: false, // 指定服务器是否应尝试根据进行协商消息压缩
}
​
func handler(w http.ResponseWriter, r *http.Request) { // http 原生写法
    conn, err := UP.Upgrade(w, r, nil) // 响应,请求,响应头可以不写
    if err != nil {
        log.Println(err)
        return
    }
​
    for {
        messageType, content, err := conn.ReadMessage()
        if err != nil {
            break
        }
        fmt.Println(messageType, string(content))
    }
    defer conn.Close()
    log.Println("服务关闭...")
}
​
func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8888", nil) // 端口号前必须加上冒号
}

客户端

package main
​
import (
    "bufio"
    "fmt"
    "github.com/gorilla/websocket"
    "log"
    "os"
)
​
func main() {
    dl := websocket.Dialer{
        // NetDial:           nil,
        // NetDialContext:    nil,
        // NetDialTLSContext: nil,
        // Proxy:             nil,
        // TLSClientConfig:   nil,
        // HandshakeTimeout:  0,
        // ReadBufferSize:    0, // 重要
        // WriteBufferSize:   0, // 重要
        // WriteBufferPool:   nil,
        // Subprotocols:      nil,
        // EnableCompression: false,
        // Jar:               nil,
    }
​
    conn, _, err := dl.Dial("ws://127.0.0.1:8888", nil) // 返回连接,http响应,错误
    if err != nil {
        log.Println(err)
        return
    }
​
    go send(conn)
    for {
        messageType, content, err := conn.ReadMessage()
        if err != nil {
            break
        }
        fmt.Println(messageType, string(content))
    }
​
}
​
func send(conn *websocket.Conn) {
    for {
        reader := bufio.NewReader(os.Stdin)
        l, _, _ := reader.ReadLine()
        conn.WriteMessage(websocket.TextMessage, l)
    }
}

多个客户端之间进行通讯,在服务端进行处理:

package main
​
import (
    "github.com/gorilla/websocket"
    "log"
    "net/http"
)
​
var UP = websocket.Upgrader{
    // HandshakeTimeout:  0,     // 握手时间0为不限制
    ReadBufferSize:  1024, // 以字节为单位的IO缓冲区,如果缓冲区大小为0,则使用HTTP服务器分配的缓冲区(不为0就是读写做限制)
    WriteBufferSize: 1024, // 以字节为单位的IO缓冲区,如果缓冲区大小为0,则使用HTTP服务器分配的缓冲区(不为0就是读写做限制)
    // WriteBufferPool:   nil,   // WriteBufferPool是用于写操作的缓冲池
    // Error:             nil,   // 指定用于生成HTTP错误响应的函数
    // CheckOrigin:       nil,   // 对过来的请求做校验用的
    // EnableCompression: false, // 指定服务器是否应尝试根据进行协商消息压缩
}
​
// 客户端每一个conn都是独立的,因此要完成客户端之间的通信,我们要把所有注册进来的conn都获取
var conns []*websocket.Conn
​
func handler(w http.ResponseWriter, r *http.Request) { // http 原生写法
    conn, err := UP.Upgrade(w, r, nil) // 响应,请求,响应头可以不写
    if err != nil {
        log.Println(err)
        return
    }
    conns = append(conns, conn)
    for {
        _, content, err := conn.ReadMessage()
        if err != nil {
            break
        }
        // 每一个客户端发一个请求,我们就让所有用户都能获取信息
        for i := range conns {
            conns[i].WriteMessage(websocket.TextMessage, []byte("你说的是:"+string(content)+"吗?"))
        }
    }
    defer conn.Close()
    log.Println("服务关闭...")
}
​
func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8888", nil) // 端口号前必须加上冒号
}

作者:陈双寅

标签:websocket,nil,err,Websocket,http,HTTP,conn
From: https://www.cnblogs.com/DTCLOUD/p/17409342.html

相关文章

  • .NET + SignalR 的反向代理 websocket/http 数据隧道
    开源项目TuToDataTunnel:https://github.com/viordash/TuToDataTunnel,这个项目可以满足以下几个需求:使用一个公网IP地址和一个tcp端口,默认端口为80http。Websocket或http隧道传输、性能或可访问性。理想情况下,将自动选择最佳可用交换协议。同时通过隧道传输多个TCP和u......
  • .Net Core 实现WebSocket Server 的另外三种方式
    回顾之前已经写过关于《WebSocket原生socket实现》和《.NetCoreWebSocket服务端与客户端完整示例》以及《基于.NetTcpListener实现WebSocketServer通讯》。其中除了《.NetCoreWebSocket服务端与客户端完整示例》外,都是基于自己对Websocket协议的实现,这种实现在生产环境......
  • 用QWebsocket时关于信号槽的一个坑
    https://blog.csdn.net/zerolity/article/details/94746977 坑描述:connect(&m_webSocket,&QWebSocket::textMessageReceived,this,&BWebsocket::onTextMessageReceived);1和主机通过websocket通信。接收主机发的指令有时导致重复接收。信号发送者和接受者同一线程。onTe......
  • WebSocket 通信使用
    传送门:https://blog.csdn.net/FTEzreal/article/details/115245562传送门:https://juejin.cn/post/6844904016976035854......
  • c#高性能服务器源代码,其中包括mvc api服务,http服务,ftp服务,sokect服务,websocket服务,大
    c#高性能服务器源代码,其中包括mvcapi服务,http服务,ftp服务,sokect服务,websocket服务,大文件传输服务。这些服务均抛开iis及第三支持,可写成服务或随软件启动而启动。ID:85320654113922032......
  • django通过channels实现websocket
     WebSocket协议是基于TCP的一种新的协议。WebSocket最初在HTML5规范中被引用为TCP连接,作为基于TCP的套接字API的占位符。它实现了浏览器与服务器全双工(full-duplex)通信。其本质是保持TCP连接,在浏览器和服务端通过Socket进行通信。当客户端向服务端发送连接请求时,不仅连接还会......
  • 推荐一个.Net Core开发的Websocket群聊、私聊的开源项目
    今天给大家推荐一个使用Websocket协议实现的、高性能即时聊天组件,可用于群聊、好友聊天、游戏直播等场景。项目简介这是一个基于.NetCore开发的、简单、高性能的通讯组件,支持点对点发送、群聊、在线状态的订阅。该项目还包含群聊例子,可以用于学习。技术架构1、跨平台:基于.Ne......
  • websocket多实例推送解决方案-数据实时展示
    需求需要前端展示实时的订单数据信息。如下图所示,实时下单实时页面统计更新展示 思路方案前端使用websocket建立通信  后端监听数据库的binglog变更,实时得到最新数据,推送到前端 现状及问题客户端想实现实时获取数据的变更,使用了websocket+kafkaMq,当......
  • websocket.go
    packagemainimport("encoding/json""fmt""net/http""github.com/gorilla/websocket")varUP=websocket.Upgrader{ReadBufferSize:1024,WriteBufferSize:1024,CheckOrigin:func(r*http.Request)bool{returntr......
  • WebSocket协议:5分钟从入门到精通
    一、内容概览WebSocket的出现,使得浏览器具备了实时双向通信的能力。本文由浅入深,介绍了WebSocket如何建立连接、交换数据的细节,以及数据帧的格式。此外,还简要介绍了针对WebSocket的安全攻击,以及协议是如何抵御类似攻击的。二、什么是WebSocketHTML5开始提供的一种浏览器与服务......