首页 文章 精选 留言 我的

精选列表

搜索[即时通讯工具],共10011篇文章
优秀的个人博客,低调大师

如何使用Tomcat实现WebSocket即时通讯服务服务端

摘要:HTTP协议是“请求-响应”模式,浏览器必须先发请求给服务器,服务器才会响应该请求。即服务器不会主动发送数据给浏览器。 本文分享自华为云社区《Tomcat支持WebSocket吗?》,作者: JavaEdge 。 HTTP协议是“请求-响应”模式,浏览器必须先发请求给服务器,服务器才会响应该请求。即服务器不会主动发送数据给浏览器。 实时性要求高的应用,如在线游戏、股票实时报价和在线协同编辑等,浏览器需实时显示服务器的最新数据,因此出现Ajax和Comet技术: Ajax本质还是轮询 Comet基于HTTP长连接做了一些hack 但它们实时性不高,频繁请求也会给服务器巨大压力,也浪费网络流量和带宽。于是HTML5推出WebSocket标准,使得浏览器和服务器之间任一方都可主动发消息给对方,这样服务器有新数据时可主动推给浏览器。 WebSocket原理 网络上的两个程序通过一个双向链路进行通信,这个双向链路的一端称为一个Socket。一个Socket对应一个IP地址和端口号,应用程序通常通过Socket向网络发出或应答网络请求。 Socket不是协议,是对TCP/IP协议层抽象出来的API。 WebSocket跟HTTP协议一样,也是应用层协议。为兼容HTTP协议,它通过HTTP协议进行一次握手,握手后数据就直接从TCP层的Socket传输,与HTTP协议再无关。 这里的握手指应用协议层,不是TCP层,握手时,TCP连接已建立。即HTTP请求里带有websocket的请求头,服务端回复也带有websocket的响应头。 浏览器发给服务端的请求会带上跟WebSocket有关的请求头,比如Connection: Upgrade和Upgrade: websocket 若服务器支持WebSocket,同样会在HTTP响应加上WebSocket相关的HTTP头部: 这样WebSocket连接就建立好了。 WebSocket的数据传输以frame形式传输,将一条消息分为几个frame,按先后顺序传输出去。为何这样设计? 大数据的传输可以分片传输,无需考虑数据大小问题 和HTTP的chunk一样,可边生成数据边传输,提高传输效率 Tomcat如何支持WebSocket WebSocket聊天室案例 浏览器端核心代码: var Chat = {}; Chat.socket = null; Chat.connect = (function(host) { //判断当前浏览器是否支持WebSocket if ('WebSocket' in window) { // 若支持,则创建WebSocket JS类 Chat.socket = new WebSocket(host); } else if ('MozWebSocket' in window) { Chat.socket = new MozWebSocket(host); } else { Console.log('WebSocket is not supported by this browser.'); return; } // 再实现几个回调方法 // 回调函数,当和服务器的WebSocket连接建立起来后,浏览器会回调这个方法 Chat.socket.onopen = function () { Console.log('Info: WebSocket connection opened.'); document.getElementById('chat').onkeydown = function(event) { if (event.keyCode == 13) { Chat.sendMessage(); } }; }; // 回调函数,当和服务器的WebSocket连接关闭后,浏览器会回调这个方法 Chat.socket.onclose = function () { document.getElementById('chat').onkeydown = null; Console.log('Info: WebSocket closed.'); }; // 回调函数,当服务器有新消息发送到浏览器,浏览器会回调这个方法 Chat.socket.onmessage = function (message) { Console.log(message.data); }; }); 服务器端Tomcat实现代码: Tomcat端的实现类加上**@ServerEndpoint**注解,value是URL路径 @ServerEndpoint(value = "/websocket/chat") public class ChatEndpoint { private static final String GUEST_PREFIX = "Guest"; // 记录当前有多少个用户加入到了聊天室,它是static全局变量。为了多线程安全使用原子变量AtomicInteger private static final AtomicInteger connectionIds = new AtomicInteger(0); //每个用户用一个CharAnnotation实例来维护,请你注意它是一个全局的static变量,所以用到了线程安全的CopyOnWriteArraySet private static final Set<ChatEndpoint> connections = new CopyOnWriteArraySet<>(); private final String nickname; private Session session; public ChatEndpoint() { nickname = GUEST_PREFIX + connectionIds.getAndIncrement(); } //新连接到达时,Tomcat会创建一个Session,并回调这个函数 @OnOpen public void start(Session session) { this.session = session; connections.add(this); String message = String.format("* %s %s", nickname, "has joined."); broadcast(message); } //浏览器关闭连接时,Tomcat会回调这个函数 @OnClose public void end() { connections.remove(this); String message = String.format("* %s %s", nickname, "has disconnected."); broadcast(message); } //浏览器发送消息到服务器时,Tomcat会回调这个函数 @OnMessage public void incoming(String message) { // Never trust the client String filteredMessage = String.format("%s: %s", nickname, HTMLFilter.filter(message.toString())); broadcast(filteredMessage); } // WebSocket连接出错时,Tomcat会回调这个函数 @OnError public void onError(Throwable t) throws Throwable { log.error("Chat Error: " + t.toString(), t); } // 向聊天室中的每个用户广播消息 private static void broadcast(String msg) { for (ChatAnnotation client : connections) { try { synchronized (client) { client.session.getBasicRemote().sendText(msg); } } catch (IOException e) { ... } } } } 根据Java WebSocket规范的规定,Java WebSocket应用程序由一系列的WebSocket Endpoint组成。Endpoint是一个Java对象,代表WebSocket连接的一端,就好像处理HTTP请求的Servlet一样,你可以把它看作是处理WebSocket消息的接口。 跟Servlet不同的地方在于,Tomcat会给每一个WebSocket连接创建一个Endpoint实例。 可以通过两种方式。 定义和实现Endpoint 编程式 编写一个Java类继承javax.websocket.Endpoint,并实现它的onOpen、onClose和onError方法。这些方法跟Endpoint的生命周期有关,Tomcat负责管理Endpoint的生命周期并调用这些方法。并且当浏览器连接到一个Endpoint时,Tomcat会给这个连接创建一个唯一的Session(javax.websocket.Session)。Session在WebSocket连接握手成功之后创建,并在连接关闭时销毁。当触发Endpoint各个生命周期事件时,Tomcat会将当前Session作为参数传给Endpoint的回调方法,因此一个Endpoint实例对应一个Session,我们通过在Session中添加MessageHandler消息处理器来接收消息,MessageHandler中定义了onMessage方法。在这里Session的本质是对Socket的封装,Endpoint通过它与浏览器通信。 注解式 实现一个业务类并给它添加WebSocket相关的注解。 @ServerEndpoint(value = "/websocket/chat") 注解,它表明当前业务类ChatEndpoint是个实现了WebSocket规范的Endpoint,并且注解的value值表明ChatEndpoint映射的URL是/websocket/chat。ChatEndpoint类中有@OnOpen、@OnClose、@OnError和在@OnMessage注解的方法,见名知义。 我们只需关心具体的Endpoint实现,比如聊天室,为向所有人群发消息,ChatEndpoint在内部使用了一个全局静态的集合CopyOnWriteArraySet维护所有ChatEndpoint实例,因为每一个ChatEndpoint实例对应一个WebSocket连接,即代表了一个加入聊天室的用户。 当某个ChatEndpoint实例收到来自浏览器的消息时,这个ChatEndpoint会向集合中其他ChatEndpoint实例背后的WebSocket连接推送消息。 Tomcat主要做了哪些事情呢? Endpoint加载和WebSocket请求处理。 WebSocket加载 Tomcat的WebSocket加载是通过SCI,ServletContainerInitializer,是Servlet 3.0规范中定义的用来接收Web应用启动事件的接口。 为什么要监听Servlet容器的启动事件呢?这样就有机会在Web应用启动时做一些初始化工作,比如WebSocket需要扫描和加载Endpoint类。 将实现ServletContainerInitializer接口的类增加HandlesTypes注解,并且在注解内指定的一系列类和接口集合。比如Tomcat为了扫描和加载Endpoint而定义的SCI类如下: 定义好SCI,Tomcat在启动阶段扫描类时,会将HandlesTypes注解指定的类都扫描出来,作为SCI的onStartup参数,并调用SCI#onStartup。 WsSci#HandlesTypes注解定义了ServerEndpoint.class、ServerApplicationConfig.class和Endpoint.class,因此在Tomcat的启动阶段会将这些类的类实例(不是对象实例)传递给WsSci#onStartup。 WsSci的onStartup方法做了什么呢? 构造一个WebSocketContainer实例,你可以把WebSocketContainer理解成一个专门处理WebSocket请求的Endpoint容器。即Tomcat会把扫描到的Endpoint子类和添加了注解@ServerEndpoint的类注册到这个容器,并且该容器还维护了URL到Endpoint的映射关系,这样通过请求URL就能找到具体的Endpoint来处理WebSocket请求。 WebSocket请求处理 Tomcat连接器的组件图 Tomcat用ProtocolHandler组件屏蔽应用层协议的差异,ProtocolHandler两个关键组件:Endpoint和Processor。 这里的Endpoint跟上文提到的WebSocket中的Endpoint完全是两回事,连接器中的Endpoint组件用来处理I/O通信。WebSocket本质是个应用层协议,不能用HttpProcessor处理WebSocket请求,而要用专门Processor,在Tomcat就是UpgradeProcessor。 因为Tomcat是将HTTP协议升级成WebSocket协议的,因为WebSocket是通过HTTP协议握手的,当WebSocket握手请求到来时,HttpProtocolHandler首先接收到这个请求,在处理这个HTTP请求时,Tomcat通过一个特殊的Filter判断该当前HTTP请求是否是一个WebSocket Upgrade请求(即包含Upgrade: websocket的HTTP头信息),如果是,则在HTTP响应里添加WebSocket相关的响应头信息,并进行协议升级。 就是用UpgradeProtocolHandler替换当前的HttpProtocolHandler,相应的,把当前Socket的Processor替换成UpgradeProcessor,同时Tomcat会创建WebSocket Session实例和Endpoint实例,并跟当前的WebSocket连接一一对应起来。这个WebSocket连接不会立即关闭,并且在请求处理中,不再使用原有的HttpProcessor,而是用专门的UpgradeProcessor,UpgradeProcessor最终会调用相应的Endpoint实例来处理请求。 Tomcat对WebSocket请求的处理没有经过Servlet容器,而是通过UpgradeProcessor组件直接把请求发到ServerEndpoint实例,并且Tomcat的WebSocket实现不需要关注具体I/O模型的细节,从而实现了与具体I/O方式的解耦。 总结 WebSocket技术实现了Tomcat与浏览器的双向通信,Tomcat可以主动向浏览器推送数据,可以用来实现对数据实时性要求比较高的应用。这需要浏览器和Web服务器同时支持WebSocket标准,Tomcat启动时通过SCI技术来扫描和加载WebSocket的处理类ServerEndpoint,并且建立起了URL到ServerEndpoint的映射关系。 当第一个WebSocket请求到达时,Tomcat将HTTP协议升级成WebSocket协议,并将该Socket连接的Processor替换成UpgradeProcessor。这个Socket不会立即关闭,对接下来的请求,Tomcat通过UpgradeProcessor直接调用相应的ServerEndpoint来处理。 还可以通过Spring来实现WebSocket应用。 点击关注,第一时间了解华为云新鲜技术~

优秀的个人博客,低调大师

Netty 入门与实战:仿写微信 IM 即时通讯系统

作为一个学 Java 的,如果没有研究过 Netty,那么你对 Java 语言的使用和理解仅仅停留在表面水平,如果你要进阶,想了解 Java 服务器的深层高阶知识,Netty 绝对是一个必须要过的门槛。 有了 Netty,你可以实现自己的 HTTP 服务器,FTP 服务器,UDP 服务器,RPC 服务器,WebSocket 服务器,Redis 的 Proxy 服务器,MySQL 的 Proxy 服务器等等。 如果你想知道Nginx是怎么写出来的,如果你想知道 Tomcat 和 Jetty 是如何实现的,如果你也想实现一个简单的 Redis 服务器,那都应该好好理解一下 Netty,它们高性能的原理都是类似的。 Netty 是互联网中间件领域使用最广泛最核心的网络通信框架。掌握它是作为一名初中级工程师迈向高级工程师最重要的技能之一,同时, Netty 也是中高级后端工程师技术面试中,面试官最喜欢问的问题之一。 然而,绝大部分工程师学习的 Netty 知识点都比较零散,不成系统,无法串成一条线。 于是,一位有情怀的架构师,某大型互联网公司基础架构部技术专家闪电侠(闪电侠Github 地址:github.com/lightningMa…),撰写了一本小册子,梳理了自己多年 Netty 实践经验,以帮助更多工程师更快,更轻松的了解 Netty 。 闪电侠所在的公司,使用 Netty 的长连集群数为几十规模,机器数为数百规模,线上 QPS 为几十万级别的规模,日吞吐为百亿规模,如此大的并发量,仅使用了 Netty 就能够轻松应对,而这些知识点在小册子中都会毫无保留得奉献给大家。 小册通过一个仿微信 IM 系统,来演示如何使用 Netty 一步一步进行服务端和客户端长连通信的开发,其中所涉及的代码将会按照小节的顺序放置到 Github 上,每小节对应一个分支,方便读者由浅入深地学习。 此本小册会通过控制台来进行用户操作的模拟,包括: ●客户端登录验证 ●客户端之间收发消息 ●群的创建 ●群聊成员管理 ●群内成员收发消息 ●客户端退出登陆 这本册子作者使用了大量的图来展示程序逻辑结构,这些图示直观易懂,相信广大工程师们学习 Netty 会更加轻松有趣。 原文发布时间为:2018-10-17 本文来自云栖社区合作伙伴“Java架构沉思录”,了解相关信息可以关注“Java架构沉思录”。

优秀的个人博客,低调大师

印度以安全为由封禁开源即时通讯应用

印度政府以国家安全为由禁止了 14 种消息应用程序,其中包括一些开源软件。被封锁的应用程序有 Wickrme、Mediafire、Briar、BChat、Nandbox、Conion、IMO、Element、Second line、Zangi、Threema、Crypviser、Enigma 和 Safeswiss。 据当地媒体援引政府消息来源称,此举是采取了印度内政部的建议,他们认为这些应用被查谟和克什米尔地区(印度和巴基斯坦在此存在领土争端)的恐怖分子及支持者所使用。敌对势力可能会利用这些应用程序来策划袭击,但当局无法对他们的谈话进行拦截。“这些应用程序在印度没有任何代表,无法按照印度法律的规定与之联系以寻求信息。” 消息人士指出,最初拟封禁的有 15 个移动应用程序;其中包括一个头部Messenger移动应用,但后来只对 14 个应用程序采取了行动。目前,这些应用程序已根据印度 2000 年《信息技术法》第 69A 条被封锁。 对此,印度自由软件社区提出了异议。并指出,FOSS 主要依赖于分散的协作,因为“没有代表”而禁用相关的软件,属实是一个有点荒谬的立场。“部分政府似乎对这些 P2P 软件以及联合应用程序的工作方式缺乏了解。这些应用程序对于灾难期间的通信至关重要,并且经常用作工作场所的通信媒介。” 该社区认为,这一禁令不会使印度达到目的,因为敌对势力可以使用更多的匿名应用程序来进行替代。相反,他们认为更应该推广Element 和 Briar 等自由软件的使用;并举例称 Element 已被法国政府、德国政府和瑞典政府所接受。且FOSS 项目的源代码获取并非难事,因此这一封禁的举措可能只会是徒劳无功,并不能成为有效的执法手段。 值得一提的是,Briar 项目日前刚在博客中详细介绍了其有关互联网中断期间通过 Android 设备构建网状网络的工作 —— 即使互联网中断,信息可以继续流动。 “当 Android 设备认为其互联网连接不起作用时,无论是由于 captive portal 还是由于无法访问某些 Google 域,设备上的应用程序仍然能够连接到仍然可以访问的 IP 地址,并且设备仍然可以解析其他域的 DNS 查询。尽管 UI 的各个部分表明系统认为 Wi-Fi 连接处于离线状态,但系统似乎并未因为这一评估而阻止任何流量。 对于我们的项目来说,这是个好消息:这意味着即使全球互联网的访问都被阻止,应该仍然可以与本地网络或互联网国家子集中的其他设备进行通信。虽然其他机制仍可能影响形成网状网络的能力,但 Android 操作系统本身似乎并没有妨碍我们。”

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册