WebSocket

156 阅读3分钟

1.什么是websocket

1.WebSocket只有在建立握手连接的时候借用了HTTP协议,连接成功后的通信部分都是基于TCP的连接。

2.WebSocket连接服务器的URI以“ws”或者“wss”开头。ws开头的默认TCP端口为80,wss开头的默认端口为443。

3.协议分为两个部分: 握手阶段和全双工通信阶段。

2.WebSocket 的工作流程

握手阶段、数据传输阶段和关闭阶段

image.png

2.1握手阶段

Websocket协议的握手阶段是使用的HTTP协议。

1.客户端发送一个 HTTP GET 请求给服务器,请求头中包含了 Upgrade、Connection、Sec-WebSocket-Key 等字段,告诉服务器要升级到 WebSocket 协议。

GET /nickname11 HTTP/1.1 
	Host: 127.0.0.1:9090
	Connection: Upgrade
	Upgrade: websocket
	Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
	Sec-WebSocket-Key: wJdg8v4EJiDsIZg5+s0hY8RUQ2A=
	Sec-WebSocket-Version: 13
	Origin: http://127.0.0.1

2.响应头中包含了 Upgrade、Connection、Sec-WebSocket-Accept 等字段,告诉客户端已经成功升级到 WebSocket 协议。

HTTP/1.1 101 Switching Protocol
Upgrade: WebSocket
Sec-WebSocket-Version: 13
Connection: Upgrade
Sec-WebSocket-Accept: wJdg8v4EJiDsIZg5+s0hY8RUQ2A=

3.客户端和服务器之间的连接就在这个阶段建立。

2.2数据传输阶段

在数据传输阶段,客户端和服务器之间可以直接发送消息,不需要像 HTTP 协议那样每次都发送请求和响应。

1.客户端可以通过 WebSocket 对象的 send() 方法向服务器发送消息.

2.服务器可以通过 WebSocket 的 onmessage 事件监听客户端发送的消息,然后根据消息的内容进行相应的操作

3.客户端和服务器之间可以通过 WebSocket 对象的 close() 方法关闭连接,或者等待网络中断或其他原因自动断开连接。

2.3关闭阶段

1.客户端可以通过 WebSocket 对象的 close() 方法发送关闭消息给服务器

2.服务器可以通过 WebSocket 对象的 onclose 事件监听客户端发送的关闭消息,然后发送一条关闭消息给客户端。

3,客户端和服务器之间可以交替发送关闭消息,直到连接关闭为止。

3.WebSocket的优点

1.实时性好:WebSocket 可以实现实时交互和即时通信,对于在线游戏、聊天室、股票行情等实时性要求高的应用场景非常重要。

2.数据传输量小:HTTP长连接中,每次数据交换除了真正的数据部分外,服务器和客户端还要大量交换HTTP header,信息交换效率很低。Websocket协议通过第一个request建立了TCP连接之后,之后交换的数据都不需要发送 HTTP header就能交换数据。

3.双向通信:WebSocket 支持客户端和服务器之间的双向通信,客户端和服务器之间可以直接发送消息,不需要像 HTTP 协议那样每次都发送请求和响应。

4.长连接:WebSocket 的连接可以保持长时间,而不需要像 HTTP 协议那样在每次请求和响应之间重新建立连接。

4.JAVA如何用WebSocket?

1.引入jar包

<!-- 引入websocket -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2.服务端使用@ServerEndpoint注解标注当前类为一个 WebSocket 服务器,客户端可以通过ws://localhost:7777/webSocket/10086来连接到 WebSocket 服务器端。

@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")
public class WebSocketServer {
    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    private static final CopyOnWriteArraySet<WebSocketServer> webSockets = new CopyOnWriteArraySet<>();
    // 用来存在线连接数
    private static final Map<String, Session> sessionPool = new HashMap<String, Session>();
    /**
     * 链接成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") String userId) {
        try {
            this.session = session;
            webSockets.add(this);
            sessionPool.put(userId, session);
            log.info("websocket消息: 有新的连接,总数为:" + webSockets.size());
        } catch (Exception e) {
        }
    }
    /**
     * 收到客户端消息后调用的方法
     */
    @OnMessage
    public void onMessage(String message) {
        log.info("websocket消息: 收到客户端消息:" + message);
    }
    /**
     * 此为单点消息
     */
    public void sendOneMessage(String userId, String message) {
        Session session = sessionPool.get(userId);
        if (session != null && session.isOpen()) {
            try {
                log.info("websocket消: 单点消息:" + message);
                session.getAsyncRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

详情可以参考这篇文章:一步步教你如何使用Java实现WebSocket_java_脚本之家 (jb51.net)

参考文献:1.【直播开发】WebSocket 协议详解-五八三 (583.cn)

2.JavaGuide(Java面试 + 学习指南)