java对于websocket java demo大于65535,发送数据怎么样做处理不会使websocket链接断掉

之前用Java的Socket模拟HTTP传输实现了WebSocket的服务端,并成功与客户端握手http://shuxiayeshou./2152服务端和客户端握手成功后就可以开始交互了。客户端发来个信息,服务端接收,再反回个信息。服务端向客户端发数据用byte[]型,且UTF-8编码,比如字符串就是 str.getBytes("UTF-8");但是有个要求,在发送数据之前要发一个头数据。这个头数据当然也是byte[]型数组。头数据包含啥呢?比如这个头数据我们定义byte[]&pushHead=new&byte[2];长度为2的byte数组。第一个元素pushHead[0]存的是接收到来自客户端byte[]的第一个元素比如客户端传来的数据我们用一个byte[]&buff=new&byte[3072];那么pushHead[0]=buff[0];而头数据的第二个元素pushHead[1]存的是服务端要发给客户端数据的长度但是有个问题,就是从Server传输数据超过126字节就不行,连接自动断开还报错InputStream&in=socket.getInputStream();
OutputStream&out=socket.getOutputStream();
byte[]&buff=new&byte[3072];
int&hasRead=0;
while((hasRead=in.read(buff)&0){
&&&&byte[]&pushHead=new&byte[2];&&&&//在传递数据前要传递这个数据头
&&&&String&x="要传输的数据......";
&&&&pushHead[0]=buff[0];&&&&&&&&&&&&//数据头数组的第一个字节是接收到的数据的第一个字节
&&&&//第二个字节是要传输数据的字节数组长度转化成的字节
&&&&pushHead[1]=(byte)x.getBytes("UTF-8").
&&&&out.write(pushHead);&&&&&&&&&&&&//先传递数据头
&&&&out.write(x.getBytes("UTF-8");&&//再传递数据
}上面的代码在传递的数据转化成的字节数组长度小于126时是OK的,但是&=126时就报错。因为字节的范围是-128~127,所以传输数据长度大于125就报错那就要另外的处理方法传输跟据数据长度分三种情况,即有三种范围小于126,那么上面的代码就OK了大于125 小于65536 &那么数据头的第二个字节存的是(byte)126,第三第四个字节存的是数据长度大于65535 & 数据头第二个字节存的是(byte)127,后面再有8个字节存数据长度这样说过于平面,看代码吧(代码也是平面的好不&(╯°Д°)╯( ┻━┻ & &)
上一篇: 下一篇:随笔 - 41&
trackbacks - 0
303112345678910111213141516171819202122232425262728293031123456789
阅读排行榜
评论排行榜
原文:学习如何在你的应用程序中集成WebSockets.Published April 2013对于许多基于客户端-服务器程序来说,老的HTTP 请求-响应模型已经有它的局限性. 信息必须通过多次请求才能将其从服务端传送到客户端.过去许多的黑客使用某些技术来绕过这个问题,例如:长轮询(long polling)、基于 HTTP 长连接的服务器推技术(Comet).&然而,基于标准的、双向的、客户端和服务器之间全双工的信道需求再不断增加。在2011年, IETF发布了标准WebSocket协议-RFC 6455. 从那时起,大多数Web浏览器都实现了支持WebSocket协议的客户端APIs.同时,许多Java 包也开始实现了WebSocket协议.WebSocket协议利用HTTP升级技术来将HTTP连接升级到WebSocket. 一旦升级后,连接就有了在两个方向上相互独立(全双式)发送消息(数据桢)的能力.&不需要headers 或cookies,这大大降低了所需的带宽.&通常,WebSockets来周期性地发送小消息&(例如,几个字节).&额外的headers常常会使开销大于有效负载(payload)。JSR 356JSR 356, WebSocket的Java API, 明确规定了API,当Java开发者需要在应用程序中集成WebSocket时,就可以使用此API—服务端和客户端均可. 每个声明兼容JSR 356的WebSocket协议,都必须实现这个API.&因此,开发人员可以自己编写独立于底层WebSocket实现的WebSocket应用。这是一个巨大的好处,因为它可以防止供应商锁定,并允许更多的选择、自由的库、应用程序服务器。JSR&356是即将到来的java&EE&7标准的一部分,因此,所有与Java EE 7兼容的应用服务器都有JSR 365标准WebSocket的实现.一旦建立,WebSocket客户端和服务器节点已经是对称的了。客户端API与服务器端API的区别是很小的,JSR 356定义的Java client API只是Java EE7完整API的子集.客户段-服务器端程序使用WebSockets,通常会包含一个服务器组件和多个客户端组件, 如图1所示:图1在这个例子中,server application 是通过Java编写的,WebSocket 协议细节是由包含在Java EE 7容器中JSR 356 实现来处理的.JavaFX 客户端可依赖任何与JSR 356兼容的客户端实现来处理WebSocket协议问题.&其它客户端(如,iOS 客户端和HTML5客户端)可使用其它 (非Java)与RFC6455兼容的实现来与server application通信.编程模型JSR 356定义的专家小组,希望支持Java EE开发人员常用的模式和技术。因此,JSR 356使用了注释和注入。一般来说,支持两种编程模型:注解驱动(annotation-driven). 通过使用注解POJOs, 开发者可与WebSocket生命周期事件交互.接口驱动(interface-driven). 开发者可实现Endpoint接口和与生命周期交互的方法.生命周期事件典型的WebSocket 交互生命周期如下:一端 (客户端) 通过发送HTTP握手请求来初始化连接.其它端(服务端) 回复握手响应.建立连接.从现在开始,连接是完全对称的.两端都可发送和接收消息.其中一端关闭连接.大部分WebSocket生命周期事件都与Java方法对应,不管是 annotation-driven 还是interface-driven.Annotation-Driven 方式接受WebSocket请求的端点可以是以&@ServerEndpoint&注解的POJO.&此注解告知容器,此类应该被认为是WebSocket端点.&必须的value&元素指定了WebSocket端点的路径.考虑下面的代码片断:@ServerEndpoint("/hello")
public class MyEndpoint { } 此代码将会以相对路径hello来发布一个端点.在后续方法调用中,此路径可携带路径参数,如:&/hello/{userid}是一个有效路径,在这里{userid}&的值,可在生命周期方法使用@PathParam&注解获取.在GlassFish中,如果你的应用程序是用上下文mycontextroot&部署的,且在localhost的8080端口上监听, WebSocket可通过使用ws://localhost:8080/mycontextroot/hello来访问.初始化WebSocket连接的端点可以是以&@ClientEndpoint&注解的POJO.@ClientEndpoint&和 @ServerEndpoint的主要区别是ClientEndpoint&不接受路径路值元素,因为它监听进来的请求。@ClientEndpoint
public class MyClientEndpoint {} Java中使用注解驱动POJO方式来初始化WebSocket连接,可通过如下代码来完成:javax.websocket.WebSocketContainer container = javax.websocket.ContainerProvider.getWebSocketContainer();
container.conntectToServer(MyClientEndpoint.class, new URI("ws://localhost:8080/tictactoeserver/endpoint")); 此后,以&@ServerEndpoint&或@ClientEndpoint&注解的类都称为注解端点.一旦建立了WebSocket连接 ,就会创建&Session,并且会调用注解端点中以@OnOpen注解的方法.&此方法包含了几个参数:javax.websocket.Session&参数, 代表创建的SessionEndpointConfig&实例包含了关于端点配置的信息0个或多个以&@PathParam注解的字符串参数,指的是端点路径的path参数下面的方法实现了当打开WebSocket时,将会打印session的标识符:@OnOpen public void myOnOpen (Session session) {
System.out.println ("WebSocket opened: "+session.getId()); } Session实例只要WebSocket未关闭就会一直有效.&Session类中包含了许多有意思的方法,以允许开发者获取更多关于的信息。同时,Session&也包含了应用程序特有的数据钩子,即通过getUserProperties()&方法来返回&Map&String, Object&.&这允许开发者可以使用session-和需要在多个方法调用间共享的应用程序特定信息来填充Session实例.i当WebSocket端收到消息时,将会调用以@OnMessage注解的方法.以@OnMessage&注解的方法可包含下面的参数:javax.websocket.Session&参数.0个或多个以&@PathParam注解的字符串参数,指的是端点路径的path参数消息本身. 下面有可能消息类型描述.当其它端发送了文本消息时,下面的代码片断会打印消息内容:@OnMessage public void myOnMessage (String txt) {
System.out.println ("WebSocket received message: "+txt); }
如果以@OnMessage&i注解的方法返回值不是void, WebSocket实现会将返回值发送给其它端点.下面的代码片断会将收到的文本消息以首字母大写的形式发回给发送者:@OnMessage public String myOnMessage (String txt) {
return txt.toUpperCase(); }
另一种通过WebSocket连接来发送消息的代码如下:RemoteEndpoint.Basic other = session.getBasicRemote(); other.sendText ("Hello, world"); 在这种方式中,我们从Session&对象开始,它可以从生命周期回调方法中获取(例如,以&@OnOpen注解的方法).session实例上getBasicRemote()&方法返回的是WebSocket其它部分的代表RemoteEndpoint.&RemoteEndpoint&实例可用于发送文本或其它类型的消息,后面有描述.当关闭WebSocket连接时,将会调用@OnClose&注解的方法。此方法接受下面的参数:javax.websocket.Session&参数. 注意,一旦WebSocket真正关闭了,此参数就不能被使用了,这通常发生在@OnClose&注解方法返回之后.A&javax.websocket.CloseReason&参数,用于描述关闭WebSocket的原因,如:正常关闭,协议错误,服务过载等等.0个或多个以&@PathParam注解的字符串参数,指的是端点路径的path参数下面的代码片段打印了WebSocket关闭的原因:@OnClose public void myOnClose (CloseReason reason) {
System.out.prinlnt ("Closing a WebSocket due to "+reason.getReasonPhrase()); } 完整情况下,这里还有一个生命周期注解:如果收到了错误,将会调用&@OnError&注解的方法。Interface-Driven 方式annotation-driven 方式允许我们注解一个Java类,以及使用生命周期注解来注解方法.&使用interface-driven方式,开发者可继承javax.websocket.Endpoint&并覆盖其中的onOpen,&onClose, 以及onError&方法:public class myOwnEndpoint extends javax.websocket.Endpoint {
public void onOpen(Session session, EndpointConfig config) {...}
public void onClose(Session session, CloseReason closeReason) {...}
public void onError (Session session, Throwable throwable) {...} } 为了拦截消息,需要在onOpen实现中注册一个javax.websocket.MessageHandler:public void onOpen (Session session, EndpointConfig config) {
session.addMessageHandler (new MessageHandler() {...}); } MessageHandler&接口有两个子接口:&MessageHandler.Partial和&MessageHandler.Whole.&MessageHandler.Partial&接口应该用于当开发者想要收到部分消息通知的时候,MessageHandler.Whole的实现应该用于整个消息到达通知。下面的代码片断会监听进来的文件消息,并将文本信息转换为大小版本后发回给其它端点:public void onOpen (Session session, EndpointConfig config) {
final RemoteEndpoint.Basic remote = session.getBasicRemote();
session.addMessageHandler (new MessageHandler.Whole&String&() {
public void onMessage(String text) {
remote.sendString(text.toUpperCase());
} catch (IOException ioe) {
// handle send failure here
}); } 消息类型,编码器,解码器WebSocket的JavaAPI非常强大,因为它允许发送任或接收任何对象作为WebSocket消息.基本上,有三种不同类型的消息:基于文本的消息二进制消息Pong 消息,它是WebSocket连接自身当使用interface-driven模式,每个session最多只能为这三个不同类型的消息注册一个MessageHandler.当使用annotation-driven模式,针对不同类型的消息,只允许出现一个@onMessage&注解方法. 在注解方法中,消息内容中允许的参数依赖于消息类型。&明确指定了消息类型上允许出现的消息参数:"如果方法用于处理文本消息:&&用于接收整个消息Java 原型或等价的类用于接收整个消息并将其转换为此类型String&和 boolean 对用于部分接收消息&用于以阻塞流的方式接收整个消息端点的任何对象参数存在文本解码器 (&或&).如果方法用于处理二进制消息:&byte[]&或&&用于接收整个消息byte[]&和 boolean 对, 或者&&和boolean对用于部分接收消息&用于按阻塞流的方式接收整个消息端点的任何对象参数存在二进制解码器(&or&).如果方法是用于处理pong消息:&&用于处理pong消息"任何Java对象使用编码器都可以编码为基于文本或二进制的消息.这种基于文本或二进制的消息将转输到其它端点,在其它端点,它可以解码成Java对象-或者被另外的WebSocket 包解释.&通常情况下,XML或JSON用于来传送WebSocket消息, 编码/解码然后会将Java对象编组成XML或JSON并在另一端解码为Java对象.encoder是以javax.websocket.Encoder&接口的实现来定义,decoder是以javax.websocket.Decoder&接口的实现来定义的.&有时,端点实例必须知道encoders和decoders是什么.使用annotation-driven方式, 可向@ClientEndpoint&和&@ServerEndpoint&l注解中的encode和decoder元素传递 encoders和decoders的列表。Listing 1 中的代码展示了如何注册一个&MessageEncoder&类(它定义了MyJavaObject实例到文本消息的转换).&MessageDecoder&是以相反的转换来注册的.@ServerEndpoint(value="/endpoint", encoders = MessageEncoder.class, decoders= MessageDecoder.class) public class MyEndpoint { ... }
class MessageEncoder implements Encoder.Text&MyJavaObject& {
@override
public String encode(MyJavaObject obj) throws EncodingException {
class MessageDecoder implements Decoder.Text&MyJavaObject& {
@override
public MyJavaObject decode (String src) throws DecodeException {
@override
public boolean willDecode (String src) {
// return true if we want to decode this String into a MyJavaObject instance
} } Listing 1Encoder&接口有多个子接口:Encoder.Text&用于将Java对象转成文本消息Encoder.TextStream&用于将Java对象添加到字符流中Encoder.Binary&用于将Java对象转换成二进制消息Encoder.BinaryStream&用于将Java对象添加到二进制流中类似地,Decoder&接口有四个子接口:Decoder.Text&用于将文本消息转换成Java对象Decoder.TextStream&用于从字符流中读取Java对象Decoder.Binary&用于将二进制消息转换成Java对象Decoder.BinaryStream&用于从二进制流中读取Java对象结论WebSocket Java API为Java开发者提供了标准API来集成IETF WebSocket标准.通过这样做,Web 客户端或本地客户端可使用任何WebSocket实现来轻易地与Java后端通信。Java Api是高度可配置的,灵活的,它允许java开发者使用他们喜欢的模式。也可参考966,690 七月 独立访问用户
语言 & 开发
架构 & 设计
文化 & 方法
您目前处于:
WebSocket与Java
WebSocket与Java
日. 估计阅读时间:
不到一分钟
智能化运维、Serverless、DevOps......2017年有哪些最新运维技术趋势?!
Author Contacted
相关厂商内容
相关赞助商
CNUTCon全球运维技术大会,9月10日-9月11日,上海&光大会展中心大酒店,
告诉我们您的想法
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
Re: 向各位请教这篇文章中的一个概念
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
赞助商链接
架构 & 设计
文化 & 方法
<及所有内容,版权所有 &#169;
C4Media Inc.
服务器由 提供, 我们最信赖的ISP伙伴。
北京创新网媒广告有限公司
京ICP备号-7
找回密码....
InfoQ账号使用的E-mail
关注你最喜爱的话题和作者
快速浏览网站内你所感兴趣话题的精选内容。
内容自由定制
选择想要阅读的主题和喜爱的作者定制自己的新闻源。
设置通知机制以获取内容更新对您而言是否重要
注意:如果要修改您的邮箱,我们将会发送确认邮件到您原来的邮箱。
使用现有的公司名称
修改公司名称为:
公司性质:
使用现有的公司性质
修改公司性质为:
使用现有的公司规模
修改公司规模为:
使用现在的国家
使用现在的省份
Subscribe to our newsletter?
Subscribe to our industry email notices?
我们发现您在使用ad blocker。
我们理解您使用ad blocker的初衷,但为了保证InfoQ能够继续以免费方式为您服务,我们需要您的支持。InfoQ绝不会在未经您许可的情况下将您的数据提供给第三方。我们仅将其用于向读者发送相关广告内容。请您将InfoQ添加至白名单,感谢您的理解与支持。标题更新:[用Node实现WebSocket协议] - 原:[WebSocket在高并发和大数据情况下的传输问题] - CNode技术社区
这家伙很懒,什么个性签名都没有留下。
下面是之前遇到的问题:
上周在班里做了关于WebSocket协议的技术分享,因为当时演示的是小数据、间歇性数据发送。所以很成功,并没有遇到啥问题。
不过回去之后发现用一个10000次的循环不断向服务器发送数据时,不论数据的大小,后几千次的数据都变成了乱码:
for (i = 0; i & 10000; i++) ws.send(&#x27;a&#x27;);
另外一个问题是,当我发送了一次长度为65535 byte的数据(也就是Payload_len = 126, Payload length = Math.pow(2, 16) - 1),服务器却得到了两次的数据请求:
第一次是FIN = 1, Opcode = 0, Payload length为65535的F
第二次是FIN = 1, Opcode为随机, MASK也是随机的, Payload length还是随机。。。
可是经过查看发现第一次数据的实际长度往往是Payload length值的一半左右,第二次的数据全是乱码。
下面是WebSocket握手结束后数据解码部分的代码:
function decodeFrame(frame) {
var counter = 0;
var fin_offset = 7,
opcode_offset = parseInt(1111, 2),
mask_offset = 7,
payload_len_offset = parseInt();
var FIN = frame[counter] && fin_offset,
Opcode = frame[counter++] & opcode_offset,
MASK = frame[counter] && mask_offset,
Payload_len = frame[counter++] & payload_len_
Payload_len === 126 &&
(Payload_len = frame.readUInt16BE(counter)) &&
counter += 2;
Payload_len === 127 &&
(Payload_len = frame.readUInt32BE(counter + 4)) &&
counter += 8;
var Payload_data = [];
if (MASK) {
var Masking_key = frame.slice(counter, counter + 4);
counter += 4;
for (var i = 0; i & Payload_ i++) {
var j = i % 4;
frame[counter + i] ^= Masking_key[j];
&#x2F;&#x2F; 这里得到上面说的测试结果
Opcode: Opcode,
MASK: MASK,
Payload_len: Payload_len,
Payload_data: frame.slice(counter, Payload_len)
WebSocket协议还有什么细节需要处理还是Buffer无法瞬间接受过大的数据吗?
一直没想明白这两种情况下乱码究竟是怎么产生的。。
求社区神牛指导啊~~
问题终于解决~
实现WebSocket真够让人纠结的,正确的代码已上传至github :
在这方面遇到麻烦的同学可以参考参考啦~
WebSocket协议本身定义是没有问题的,应该是你的发送端处理或接收端的处理有问题。
恩,已解决,不过这个问题产生的原因确实很蛋疼。。
的确是读取的问题。要在读取时循环调用解码函数。
有现成的的不用:
的确有现成的,后来也读了部分源码,不过还是想自己写个玩玩
CNode 社区为国内最专业的 Node.js 开源技术社区,致力于 Node.js 的技术研究。
服务器赞助商为
,存储赞助商为
,由提供应用性能服务。
新手搭建 Node.js 服务器,推荐使用无需备案的

我要回帖

更多关于 java websocket客户端 的文章

 

随机推荐