分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 软件开发

webSocket

发布时间:2023-09-06 01:56责任编辑:熊小新关键词:暂无标签

概述

什么是webSocket

WebSocket是为Html5提供了一种在单个TCP上实现全双工的网络通信协议。

为什么需要webSocket

http协议是一种无状态、无连接的通信协议,使用的是请求/应答模型,客户端发出一次请求,服务器端作出响应,没有主动的向客户端推送信息的机制。这就导致客户端不能及时的获取后端数据。websocket实现了全双工主动向客户端推送信息的机制,是一种持久化的协议。

webSocket工作原理

客户端与服务端的只要建立一次连接,就可以实现客户端与服务度互相主动推送。WebSocket 协议本质上是一个基于 TCP 的协议。为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息。运行图如下:

 客户端发送给服务端的信息包括如下信息:

GET /chat HTTP/1.1Host: server.example.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13Origin: http://example.com
其中Upgrade: websocket和Connection: Upgrade,告诉服务器:注意啦,我发起的是Websocket协议,快点帮我找到对应的助理处理~不是那个老土的HTTP。
Sec-WebSocket-Key 是一个 Base64 encode 的值,这个是浏览器随机生成的,告诉服务器,客户端要验证尼是不是真的是Websocket助理。
Sec_WebSocket-Protocol 是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的协议。
Sec-WebSocket-Version 是告诉服务器所使用的 Websocket Draft (协议版本)
服务器会返回下列信息:
HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=Sec-WebSocket-Protocol: chat
Sec-WebSocket-Accept 这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key 。 服务器:好啦好啦,知道啦,给你看我的ID CARD来证明行了吧。。
Sec-WebSocket-Protocol 则是表示最终使用的协议。

webSocket客户端

创建WebSocket对象

var Socket = new WebSocket(url, [protocol] );   //代码中的参数url为指定连接的URL,第二个参数为可接受的子协议。

webSocket属性

Socket.readyState:只读属性 readyState 表示连接状态,可以是以下值:0 - 表示连接尚未建立。1 - 表示连接已建立,可以进行通信。2 - 表示连接正在进行关闭。3 - 表示连接已经关闭或者连接不能打开。

Socket.bufferedAmount:只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。

webSocket事件

事件事件处理程序描述
openSocket.onopen连接建立时触发
messageSocket.onmessage客户端收到消息时触发
closeSocket.onclose客户端关闭连接时触发
errorSocket.onerror客户端出现连接错误时触发

webSocket方法

方法描述
Socket.send()使用连接发送数据
Socket.close()关闭连接

客户端实例

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html> <html> <head> ????<title>Java后端WebSocket的Tomcat实现</title>      <meta content=‘width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no‘ name=‘viewport‘ />      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> ????Welcome<br/><input id="text" type="text"/> ????<button onclick="send()">发送消息</button> ????<hr/> ????<button onclick="closeWebSocket()">关闭WebSocket连接</button> ????<hr/> ????<div id="message"></div> </body> ?<script type="text/javascript"> ????var websocket = null; ????//判断当前浏览器是否支持WebSocket ????if (‘WebSocket‘ in window) { ????????websocket = new WebSocket("ws://localhost:8080/qingyingyong/websocket"); ????} ????else { ????????alert(‘当前浏览器 Not support websocket‘) ????} ?????//连接发生错误的回调方法 ????websocket.onerror = function () { ????????setMessageInnerHTML("WebSocket连接发生错误"); ????}; ?????//连接成功建立的回调方法 ????websocket.onopen = function () { ????????setMessageInnerHTML("WebSocket连接成功"); ????} ?????//接收到消息的回调方法 ????websocket.onmessage = function (event) { ????????setMessageInnerHTML(event.data); ????} ?????//连接关闭的回调方法 ????websocket.onclose = function () { ????????setMessageInnerHTML("WebSocket连接关闭"); ????} ?????//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 ????window.onbeforeunload = function () { ????????closeWebSocket(); ????} ?????//将消息显示在网页上 ????function setMessageInnerHTML(innerHTML) { ????????document.getElementById(‘message‘).innerHTML += innerHTML + ‘<br/>‘; ????} ?????//关闭WebSocket连接 ????function closeWebSocket() { ????????websocket.close(); ????} ?????//发送消息 ????function send() { ????????var message = document.getElementById(‘text‘).value; ????????websocket.send(message); ????} </script> </html>  

webSocket服务端

@ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端。
实例代码如下:
package qingyingyong;import java.io.IOException;import java.util.concurrent.CopyOnWriteArraySet;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.ServerEndpoint;@ServerEndpoint("/websocket") public class WebSocketTest { ????//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 ????private static int onlineCount = 0; ?????//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识 ????private static CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>(); ????//与某个客户端的连接会话,需要通过它来给客户端发送数据 ????private Session session; ?????/** ?????* 连接建立成功调用的方法 ?????* @param session ?可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 ?????*/ ????@OnOpen ????public void onOpen(Session session){ ???????this.session = session; ????????webSocketSet.add(this); ????//加入set中 ????????addOnlineCount(); ??????????//在线数加1 ????????System.out.println("有新连接加入!当前在线人数为" + getOnlineCount()); ????} ????/** ?????* 连接关闭调用的方法 ?????*/ ???@OnClose ????public void onClose(){ ????????webSocketSet.remove(this); ?//从set中删除 ??????subOnlineCount(); ??????????//在线数减1 ????????System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); ????} ???/** ?????* 收到客户端消息后调用的方法 ?????* @param message 客户端发送过来的消息 ?????* @param session 可选的参数 ?????*/ ????@OnMessage ????public void onMessage(String message, Session session) { ????????System.out.println("来自客户端的消息:" + message); ????????//群发消息 ????????for(WebSocketTest item: webSocketSet){ ????????????try { ????????????????item.sendMessage(message); ????????????} catch (IOException e) { ????????????????e.printStackTrace(); ????????????????continue; ????????????} ????????} ????} ?????/** ?????* 发生错误时调用 ?????* @param session ?????* @param error ?????*/ ????@OnError ????public void onError(Session session, Throwable error){ ????????System.out.println("发生错误"); ????????error.printStackTrace(); ????} ?????/** ?????* 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。 ?????* @param message ?????* @throws IOException ?????*/ ????public void sendMessage(String message) throws IOException{ ????????this.session.getBasicRemote().sendText(message); ????????//this.session.getAsyncRemote().sendText(message); ????} ?????public static synchronized int getOnlineCount() { ????????return onlineCount; ????} ?????public static synchronized void addOnlineCount() { ????????WebSocketTest.onlineCount++; ????} ?????public static synchronized void subOnlineCount() { ????????WebSocketTest.onlineCount--; ????} }

webSocket代理

如果把 WebSocket 的通信看成是电话连接,Nginx 的角色则像是电话接线员,负责将发起电话连接的电话转接到指定的客服。

Nginx 从 1.3 版开始正式支持 WebSocket 代理。如果你的 web 应用使用了代理服务器 Nginx,那么你还需要为 Nginx 做一些配置,使得它开启 WebSocket 代理功能。

以下为参考配置:

server { ?# this section is specific to the WebSockets proxying ?location /socket.io { ???proxy_pass http://app_server_wsgiapp/socket.io; ???proxy_redirect off; ???proxy_set_header Host $host; ???proxy_set_header X-Real-IP $remote_addr; ???proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; ???proxy_http_version 1.1; ???proxy_set_header Upgrade $http_upgrade; ???proxy_set_header Connection "upgrade"; ???proxy_read_timeout 600; ?}}

完整实例

1、聊天实例

在聊天时需要记录下好友的Session,在发送信息时,需要后台获取好友的Session,并通过Session进行推送。

后台代码:

package qingyingyong;import java.io.IOException;import java.util.Hashtable;import java.util.Map;import java.util.concurrent.CopyOnWriteArraySet;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.PathParam;import javax.websocket.server.ServerEndpoint;import net.sf.json.JSONObject;@ServerEndpoint("/websocketnew")public class WebSocketNew { ???//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 ???private static int onlineCount = 0; ???//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识 ???private static CopyOnWriteArraySet<WebSocketNew> webSocketSet = new CopyOnWriteArraySet<WebSocketNew>(); ???private static Map<String,Session> sessionMap = new Hashtable<String,Session>(); ???private Session session;//与某个客户端的连接会话,需要通过它来给客户端发送数据 ???private String userName;// 当前用户 ???/** ????* 连接建立成功调用的方法 ????* @param session ?可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据, ????*/ ???@OnOpen ???public void onOpen(Session session){ ??????this.session = session; ???????webSocketSet.add(this); ????//加入set中 ???????addOnlineCount(); ??????????//在线数加1 ???????System.out.println("有新连接加入!当前在线人数为" + getOnlineCount()); ???????System.out.println("+++++++++++++++"+session.getId()); ???} ??/** ????* 连接关闭调用的方法 ????*/ ??@OnClose ???public void onClose(){ ???????webSocketSet.remove(this); ?//从set中删除 ???????sessionMap.remove(userName);//关闭连接删除Session ?????subOnlineCount(); ??????????//在线数减1 ???????System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); ???} ??/** ????* 收到客户端消息后调用的方法 ????* @param message 客户端发送过来的消息 ????* @param session 可选的参数 ????*/ ???@OnMessage ???public void onMessage(String message, Session session) { ???????System.out.println("来自客户端的消息:" + message); ???????//群发消息 ???????JSONObject jsonObject = JSONObject.fromObject(message); ???????String mString = jsonObject.getString("msg"); ???????String name = jsonObject.getString("name"); ???????String status = jsonObject.getString("status"); ???????System.out.println("来自客2222户端的消息:" + status); ???????if(status!=null&&"1".equals(status)){ ???????sessionMap.put(name, session); ???????userName = name; ???????return; ???????} ???????Session session2 = sessionMap.get(name); ???????try ???????{ ???????session2.getBasicRemote().sendText(mString); ???????} catch (IOException e) { ???????e.printStackTrace(); ???????????} ???????} ???/** ????* 发生错误时调用 ????* @param session ????* @param error ????*/ ???@OnError ???public void onError(Session session, Throwable error){ ???????System.out.println("发生错误"); ???????error.printStackTrace(); ???} ???/** ????* 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。 ????* @param message ????* @throws IOException ????*/ ???public void sendMessage(String message) throws IOException{ ???????this.session.getBasicRemote().sendText(message); ???????//this.session.getAsyncRemote().sendText(message); ???} ???public static synchronized int getOnlineCount() { ???????return onlineCount; ???} ???public static synchronized void addOnlineCount() { ???????WebSocketNew.onlineCount++; ???} ???public static synchronized void subOnlineCount() { ???????WebSocketNew.onlineCount--; ???}}

前端代码

1、选择需要登录的账号和好友账号

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" ???pageEncoding="ISO-8859-1"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Insert title here</title></head><body><form action="index.jsp" method="post"> ?<table border="1"><tr> ?<td>??¨??·??????</td><td><input type="text" name="loginName"/></td> ?<td>?¥???????</td><td><input type="text" name="name"/></td> </tr> ?<tr> ?<td colspan="2"><input type="submit" value="??????"></td> ?</tr> ?</table> ?</form> ?</body></html>

2、进行聊天

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html> <html> <head> ????<title>Java后端WebSocket的Tomcat实现</title>      <meta content=‘width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no‘ name=‘viewport‘ />      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> ????Welcome<br/><input id="text" type="text"/> ????<button onclick="send()">发送消息</button> ????<hr/> ????<button onclick="closeWebSocket()">关闭WebSocket连接</button> ????<hr/> ????<div id="message"></div> </body> ?<script type="text/javascript"> var loginName = ‘<%=request.getParameter("loginName") %>‘; //获取登录账号 ?var name = ‘<%=request.getParameter("name") %>‘; //获取好友 ?????var websocket = null; ????//判断当前浏览器是否支持WebSocket ????if (‘WebSocket‘ in window) { ?????var wsUrl = "ws://localhost:8080/websocketdemo/websocketnew"; ????????websocket = new WebSocket(wsUrl); ????????alert(websocket.url); ????} ????else { ????????alert(‘当前浏览器 Not support websocket‘) ????} ?????//连接发生错误的回调方法 ????websocket.onerror = function () { ????????setMessageInnerHTML("WebSocket连接发生错误"); ????}; ?????//连接成功建立的回调方法 ????websocket.onopen = function () { ????var json = {"msg":"登陆成功","name":loginName,"status":1}; ????var message = JSON.stringify(json); ????????websocket.send(message); ????????setMessageInnerHTML("WebSocket连接成功"); ????} ?????//接收到消息的回调方法 ????websocket.onmessage = function (event) { ????????setMessageInnerHTML(event.data); ????} ?????//连接关闭的回调方法 ????websocket.onclose = function () { ????????setMessageInnerHTML("WebSocket连接关闭"); ????} ?????//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 ????window.onbeforeunload = function () { ????????closeWebSocket(); ????} ?????//将消息显示在网页上 ????function setMessageInnerHTML(innerHTML) { ????????document.getElementById(‘message‘).innerHTML += innerHTML + ‘<br/>‘; ????} ?????//关闭WebSocket连接 ????function closeWebSocket() { ????????websocket.close(); ????} ?????//发送消息 ????function send() { ????var json = ?{"msg":document.getElementById(‘text‘).value,"name":name,"status":0}; ????var message = JSON.stringify(json); ????????websocket.send(message); ????} </script> </html>

  

webSocket

原文地址:https://www.cnblogs.com/youzhongmin/p/8878219.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved