热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

WebSocket理论+实践

2019独角兽企业重金招聘Python工程师标准1.理论1.1Http和WebSocket1.1.1HTTPhttp协议在通信过程中存在一个巨大的缺陷,通信只能

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

1. 理论

1.1 Http和WebSocket

1.1.1 HTTP

http协议在通信过程中存在一个巨大的缺陷,通信只能由客户端发起,服务器只能根据响应返回响应的结果。也就说,服务器端无法主动给客户端发送消息。

对于服务器端连续的状态变化,http协议就显得有些力不从心了,当然也可以通过其他的方式实现。比如:

  1. 轮询(每隔一段时候,就发出一个询问,了解服务器有没有新的信息)
  2. long poll(采用阻塞模式,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始)。

虽然这样也可以实现我们的要求,但是资源就在轮询的过程中被大量浪费。

1.1.1 WebSocket

WebSocket协议,2008年诞生,2011年称为国际标准,其最大的特点就是服务器端可以主动向客户端发送消息,实现真正的双向平等对话。主要特点:

  1. 建立在tcp协议之上,服务器端的实现比较容易
  2. 与http协议有很好的兼容性,握手阶段采用http协议
  3. 数据格式比较轻量,性能开销小,通信高效
  4. 可以发送文本,也可以发送二进制
  5. 没有同源策略(htpp的同源策略主要是出于安全考虑)
  6. 协议标识是ws,如ws://127.0.0.1:8080/myHandler/{Id}"

理论没看懂的可以戳这 故事描述型

1.2 WebSocket工作方式

1.2.1 WebSocket 客户端

创建WebSocket

var Socket = new WebSocket(url, [protocol] );//协议可以为空

属性

Socket.readyState//连接状态
Socket.bufferedAmount //队列中等待传输,但是还没有发出的 UTF-8 文本字节数。

事件,编写的时候要加上on 比如onOpen

open //连接建立时触发
message //客户端接收服务端数据时触发
error //通信发生错误时触发
close //连接关闭时触发

方法

Socket.send() //使用连接发送数据
Socket.close() //关闭连接

实例:

// 初始化一个 WebSocket 对象
var ws = new WebSocket("ws://localhost:9998/echo");
// 建立 web socket 连接成功触发事件
ws.onopen = function () {// 使用 send() 方法发送数据ws.send("发送数据");alert("数据发送中...");
};
// 接收服务端数据时触发事件
ws.onmessage = function (evt) {var received_msg = evt.data;alert("数据已接收...");
};
// 断开 web socket 连接成功触发事件
ws.onclose = function () {alert("连接已关闭...");
};

1.2.2 WebSocket 服务器端

服务器端的就主要用代码来实现吧

2. 实践篇

源码地址 密码:f28e

服务端获取消息很简单,主要是向服务器端发送消息。需要向客户端发送消息,那么我们需要知道客户端的某个唯一标识,那么这个标识用什么来表示呢,那就是session。

2.1 普通javaEE方式

直接贴码,里面注释很清晰 需要的依赖

javaxjavaee-api7.0provided

java源码

package me.gacl.websocket;import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;/*** @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端*/
@ServerEndpoint("/websocket")
public class WebSocketTest {//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。private static int onlineCount = 0;//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet();//与某个客户端的连接会话,需要通过它来给客户端发送数据private Session session;/*** 连接建立成功调用的方法* @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据*/@OnOpenpublic void onOpen(Session session){this.session = session;webSocketSet.add(this); //加入set中addOnlineCount(); //在线数加1System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());}/*** 连接关闭调用的方法*/@OnClosepublic void onClose(){webSocketSet.remove(this); //从set中删除subOnlineCount(); //在线数减1System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());}/*** 收到客户端消息后调用的方法* @param message 客户端发送过来的消息* @param session 可选的参数*/@OnMessagepublic 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*/@OnErrorpublic 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--;}
}

2.2 spring boot集成

这里通过重新写一个controller,直接给客户端发送消息,先贴这里的代码,应该大部分人都是想实现这个功能。这里的目的是,在处理一个其他请求之后,需要给原来的客户端发送消息,告诉它我已经处理完了,收到消息之后再处理后续的逻辑(扫码场景比较普遍)。

@GetMapping("/")public WebsocketResponse sendSuccess(){MyHandler send = new MyHandler();TextMessage msg = new TextMessage("发给客户端");send.sendMessageToUser("888",msg);return new WebsocketResponse(1);}

有需要的直到源码中拉取代码吧,服务器端的原理都类似

2.2.1 代码注意问题

  1. 这里的session一定是需要回调的那个客户端的session,所以第一次请求是需要保存客户端的session,公司一般放在redis中缓存。

转:https://my.oschina.net/u/2615530/blog/1853494



推荐阅读
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • mac php错误日志配置方法及错误级别修改
    本文介绍了在mac环境下配置php错误日志的方法,包括修改php.ini文件和httpd.conf文件的操作步骤。同时还介绍了如何修改错误级别,以及相应的错误级别参考链接。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 延迟注入工具(python)的SQL脚本
    本文介绍了一个延迟注入工具(python)的SQL脚本,包括使用urllib2、time、socket、threading、requests等模块实现延迟注入的方法。该工具可以通过构造特定的URL来进行注入测试,并通过延迟时间来判断注入是否成功。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 一、什么是闭包?有什么作用什么是闭包闭包是定义在一个函数内部的函数,它可以访问父级函数的内部变量。当一个闭包被创建时,会关联一个作用域—— ... [详细]
  • 本文讨论了读书的目的以及学习算法的重要性,并介绍了两个算法:除法速算和约瑟夫环的数学算法。同时,通过具体的例子和推理,解释了为什么x=x+k序列中的第一个人的位置为k,以及序列2和序列3的关系。通过学习算法,可以提高思维能力和解决问题的能力。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
author-avatar
mobiledu2502882333
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有