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

java网络高级编程_JavaWeb高级编程(四)

WebSocket一、WebSocket的产生用户希望Web页面可以进行交互,用于解决这个问题的技术是JavaScript,现在Web上有许多的可用的J

WebSocket

一、WebSocket的产生

用户希望Web页面可以进行交互,用于解决这个问题的技术是Javascript,现在Web上有许多的可用的Javascript框架,在使用极少的Javascript的情况下就可以创建出丰富的单页面Web——Ajax技术(异步Javascript和XML)。

在采用了Ajax之后,浏览器中的Web应用程序可以与服务器端的组件进行通信,而不需要改变浏览器页面或者刷新。这个通信过程不需要用户知道,并且它可以用于向服务器发送新数据或者从服务器获得新数据。

但是,浏览器只可以从服务器专区新的数据,但是浏览器并不知道数据什么时候使用,只有服务器知道什么时候有新数据发送到浏览器,而浏览器并不知道。

解决方法1,频繁轮询

频繁轮询服务器获取新数据,以一个固定的频率,通常是每秒一次,浏览器将发送Ajax请求到服务器查询新数据。如果浏览器有新的数据发送到服务器,数据将被添加到轮询请求中一同发送给浏览器(但是大量请求会被浪费)。

解决方法2,长轮询

服务器只有在发送数据时才会响应浏览器(如果浏览器在服务器响应之前有新数据要发送,浏览器就必须要创建一个新的并行请求,或者终止当前的请求;TCP和HTTP规定了连接超时的情况;HTTP存在着强制的连接限制)。

解决方法3,分块编码

服务器可以在不声明内容长度的情况下响应请求。在响应中,每个块的开头一次是:一个用于表示块长度的数字、一系列表示块扩展的可选字符和一个CRLF(回车换行)序列。接着是块包含的数据和另一个CRLF。浏览器将创建一个连接到“下游端点”的长生命连接,并且服务器将使用该连接以块的方式向浏览器发送更新。

解决方法4,Applet和Adobe Flash

创建连接到服务器的普通TCP套接字连接,当浏览器有了新的数据要发送到服务器,它将由浏览器插件暴露出的Javascript DOM函数调用Java或Flash方法,然后该方法吧数据转发到服务器上。

解决方法5,WebSocket

WebSocket连接首先将使用非正常的HTTP请求以特定的模式访问一个URL,WebSocket是持久的全双工通信协议。在握手完成之后,文本和二进制消息将可以同时在两个方向上进行发送,而不需要关闭和重新连接。

WebSocket的优点:

连接端口在80(ws)和433(wss),所以不会被防火墙阻塞。

使用HTTP握手,可以自然地集成到网络浏览器和HTTP服务器上。

使用ping和pong保持WebSocket一直处于活跃状态。

当消息启动和它的内容到达时,服务器和客户端都可以知道。

WebSocket在关闭连接时会发送特殊的关闭消息。

可以支持跨区域连接。

二、WebSocket API

WebSocket并不只是在浏览器和服务器的通信,两个以任何框架编写、支持WebSocket的应用程序都可以创建WebSocket连接进行通信。

WebSocket的Java API包含在javax.websocket中,并指定了一组类和接口包含所有的常见功能。

客户端API

客户端API基于ContainerProvider类和WebSocketContainer、RemoteEndpoint和Session接口构建。

WebSocketContainer提供了对所有WebSocket客户端特性的访问,而ContainerProvider类听了静态的getWebSocketContainer方法用来获取底层WebSocket客户端的实现。

WebSocketContainer提供了4个重载的connectToServer方法,它们都将接受一个URI,用于连接远程终端和初始化握手。

标注了@ClientEndpoint的任意类型的POJO

标注了@ClientEndpoint的任意类型的POJO的Class

Endpoint类的实例或者一个Class extends EndPoint>。

当握手完成是,connectToServer方法将返回一个Session。

其中WebSocket的Endpoint有3个方法,onOpen、onClose和onError,它们将在这些时间发生时进行调用。

而@ClientEndpoint类标注了@onOpen、@onClose和@onError的方法。

@OnOpen方法可以有:一个可选的Session参数,一个可选的EndpointConfig参数。

@OnClose方法可以有:一个可选的Session参数,一个可选的CloseReason参数。

@OnError方法可以有:一个可选的Session参数,一个可选的Throwable参数。

@OnMessage方法可以有:一个可选的Session参数,其它参数的组合。

这是一个WebSocket创建多人游戏的服务器终端代码:

public classTicTacToeServer

{private static Map games &#61; new Hashtable<>();private static ObjectMapper mapper &#61; newObjectMapper();

&#64;OnOpenpublic void onOpen(Session session, &#64;PathParam("gameId") longgameId,

&#64;PathParam("username") String username)

{try{

TicTacToeGame ticTacToeGame&#61;TicTacToeGame.getActiveGame(gameId);if(ticTacToeGame !&#61; null)

{

session.close(newCloseReason(

CloseReason.CloseCodes.UNEXPECTED_CONDITION,"This game has already started."));

}

List actions &#61; session.getRequestParameterMap().get("action");if(actions !&#61; null && actions.size() &#61;&#61; 1)

{

String action&#61; actions.get(0);if("start".equalsIgnoreCase(action))

{

Game game&#61; newGame();

game.gameId&#61;gameId;

game.player1&#61;session;

TicTacToeServer.games.put(gameId, game);

}else if("join".equalsIgnoreCase(action))

{

Game game&#61;TicTacToeServer.games.get(gameId);

game.player2&#61;session;

game.ticTacToeGame&#61;TicTacToeGame.startGame(gameId, username);this.sendJsonMessage(game.player1, game,newGameStartedMessage(game.ticTacToeGame));this.sendJsonMessage(game.player2, game,newGameStartedMessage(game.ticTacToeGame));

}

}

}catch(IOException e)

{

e.printStackTrace();try{

session.close(newCloseReason(

CloseReason.CloseCodes.UNEXPECTED_CONDITION, e.toString()

));

}catch(IOException ignore) { }

}

}

&#64;OnMessagepublic voidonMessage(Session session, String message,

&#64;PathParam("gameId") longgameId)

{

Game game&#61;TicTacToeServer.games.get(gameId);boolean isPlayer1 &#61; session &#61;&#61;game.player1;try{

Move move&#61; TicTacToeServer.mapper.readValue(message, Move.class);

game.ticTacToeGame.move(

isPlayer1?TicTacToeGame.Player.PLAYER1 :

TicTacToeGame.Player.PLAYER2,

move.getRow(),

move.getColumn()

);this.sendJsonMessage((isPlayer1 ?game.player2 : game.player1), game,newOpponentMadeMoveMessage(move));if(game.ticTacToeGame.isOver())

{if(game.ticTacToeGame.isDraw())

{this.sendJsonMessage(game.player1, game,newGameIsDrawMessage());this.sendJsonMessage(game.player2, game,newGameIsDrawMessage());

}else{boolean wasPlayer1 &#61; game.ticTacToeGame.getWinner() &#61;&#61;TicTacToeGame.Player.PLAYER1;this.sendJsonMessage(game.player1, game,newGameOverMessage(wasPlayer1));this.sendJsonMessage(game.player2, game,new GameOverMessage(!wasPlayer1));

}

game.player1.close();

game.player2.close();

}

}catch(IOException e)

{this.handleException(e, game);

}

}

&#64;OnClosepublic void onClose(Session session, &#64;PathParam("gameId") longgameId)

{

Game game&#61;TicTacToeServer.games.get(gameId);if(game &#61;&#61; null)return;boolean isPlayer1 &#61; session &#61;&#61;game.player1;if(game.ticTacToeGame &#61;&#61; null)

{

TicTacToeGame.removeQueuedGame(game.gameId);

}else if(!game.ticTacToeGame.isOver())

{

game.ticTacToeGame.forfeit(isPlayer1?TicTacToeGame.Player.PLAYER1 :

TicTacToeGame.Player.PLAYER2);

Session opponent&#61; (isPlayer1 ?game.player2 : game.player1);this.sendJsonMessage(opponent, game, newGameForfeitedMessage());try{

opponent.close();

}catch(IOException e)

{

e.printStackTrace();

}

}

}

服务器API

服务器API依赖于完整的客户端API&#xff0c;它只添加了少数的类和接口&#xff0c;ServerContainer集成了WebSocketContainer&#xff0c;在Servlet环境中调用ServletContext.getAttribute("javax.websocket.server.ServerCOntainer")可以获得ServerContainer实例&#xff0c;在独立运行的应用程序中&#xff0c;需要按照特定的WebSocket实现的指令获取ServerContainer实例。

不过&#xff0c;其实可以使用&#64;ServerEndPoint标注服务器终端类即可&#xff0c;WebSocket实现可以扫描类的注解&#xff0c;并自动选择和注册服务器终端&#xff0c;容器在每次收到WebSocket连接时创建对应终端的实例&#xff0c;在连接关闭之后在销毁实例。

在使用&#64;ServerEndPoint&#xff0c;至少需要制定必须的value特性目标是该终端可以做出像的应用程序相对应的URL&#xff1a;

&#64;ServerEndpoint("/ticTacToe/{gameId}/{username}")

如果应用程序部署到的地址为&#xff1a;http://www.example.org/app&#xff0c;那么该服务器终端会响应地址&#xff1a;ws://www.example.org/app/ticTacToe/1/andre等&#xff0c;然后服务器终端中所有的&#64;OnOpen、&#64;OnClose、&#64;OnError和&#64;OnMessage方法都可以只用&#64;PathParam(“{gameId}/{username}”)标注出一个可选的额外参数&#xff0c;并且其内容为改参数的值(1/andre)。

服务器终端中的时间处理方法将和客户端中的时间处理方法一样工作&#xff0c;区别只存在于握手阶段&#xff0c;之后并没有服务器和客户端的差别。



推荐阅读
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了在使用Python中的aiohttp模块模拟服务器时出现的连接失败问题,并提供了相应的解决方法。文章中详细说明了出错的代码以及相关的软件版本和环境信息,同时也提到了相关的警告信息和函数的替代方案。通过阅读本文,读者可以了解到如何解决Python连接服务器失败的问题,并对aiohttp模块有更深入的了解。 ... [详细]
  • WebSocket与Socket.io的理解
    WebSocketprotocol是HTML5一种新的协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 网络请求模块选择——axios框架的基本使用和封装
    本文介绍了选择网络请求模块axios的原因,以及axios框架的基本使用和封装方法。包括发送并发请求的演示,全局配置的设置,创建axios实例的方法,拦截器的使用,以及如何封装和请求响应劫持等内容。 ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
author-avatar
手机用户2502911627_202
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有