java websocket高并发测试_Websocket全讲解。跨平台的通讯协议 !!基于websocket的高并发即时通讯服务器开发。...

本博文,保证不用装B的话语和太多专业的语言,保证简单易懂,只要懂JAVAEE开发的人都可以看懂。 本博文发表目的是,目前网上针对Websocket的资料太散乱,导致初学者的知识体系零零散散,学习困难加大。本博加以整理,并且实践。

所用核心技术选型:

Tomcat + Spring 4.0.3 + Mongodb(高并发数据库)

+ SpringQueue(消息队列)+ ActiveMQ (消息队列)

+ Spring-data-Mongo + Servlet 3.0

+Spring-Websocket

+ Maven

注:以下Websocket 均省略成 WB

先说Websocket 的原理。 Websocket 是全双工通讯(说白了就是俩都可以通讯,服务器也可以给客户端发消息,客户端也能给服务器发消息)。也是基于TCP的,效率是很高的,首先这个技术的底层选用,就决定了完全可以用wb这个技术做高并发应用,而且开发非常快!!代码非常简单!!最重要的是稳定性,扩展性等等都有保证,等会儿说为什么说都有保证。

WB 不同于TCP的三次握手。  WB是先进行一次HTTP请求,这个请求头不同于普通HTTP请求,等会贴出来讲解。然后服务器开始辨认请求头,如果是WB的请求头,则开始进行普通的TCP连接,即三次握手(不懂的TCP的,出门百度)。如果不是WB的HTTP请求头,那就是按普通的HTTP请求处理。

流程梳理: HTTP特殊请求(有个特殊的头) ---- 》 服务请接收判断 ----- 》 认出来了,确实是WB请求头,开启TCP 三次握手,建立连接后,和TCP一样了就------》没有认出来,不是WB的请求头,按普通HTTP请求处理。

很清楚了吧。这是个基础,先理解了,下面写程序才好搞。下面这段是Webscoket的请求头。 GET请求

GET ws://localhost:12345/websocket/test.html HTTP/1.1

Origin: http://localhost

Connection: Upgrade

Host: localhost:12345

Sec-WebSocket-Key: JspZdPxs9MrWCt3j6h7KdQ== //主要这个字段,这个叫“梦幻字符串”,这个加密规则可以去百度,是有规则的。这个也是个密钥,只有有这个密钥 服务器才能通过解码 认出来,哦~这是个WB的请求,我要建立TCP连接了!!!如果这个字符串没有按照加密规则加密,那服务端就认不出来,就会认为这整个协议就是个HTTP请求。更不会开TCP。其他的字段都可以随便设置,但是这个字段是最重要的字段,标识WB协议的一个字段。

Upgrade: websocket

Sec-WebSocket-Version: 13

下面这段是服务端回应消息:

HTTP/1.1 101 Web Socket Protocol Handshake

WebSocket-Location: ws://localhost:12345/websocket/test.php

Connection: Upgrade

Upgrade: websocket

Sec-WebSocket-Accept: zUyzbJdkVJjhhu8KiAUCDmHtY/o= //这个字段,叫“梦幻字符串”,和上面那个梦幻字符串作用一样。不同的是,这个字符串是要让客户端辨认的,客户端拿到后自动解码。并且辨认是不是一个WB请求。然后进行相应的操作。这个字段也是重中之重,不可随便修改的。加密规则,依然是有规则的,可以去百度一下。

WebSocket-Origin: http://localhost

好了,一去一回的HTTP请求, 如果他们的梦幻字符串都对上了,客户端服务端都确定是一次WB请求了。。那就开始建立TCP连接了。

关于Tcp编程,为什么没有选用Netty或者Mina框架,而选用以上的技术。 其实我感觉还是他们太复杂。并且,我们用Netty的话,集群规则,负载均衡,JVM优化都需要自己做。集群规则,负载均衡这块儿,就是另一个大的研究方向,一个人根本搞不下来。

不如放在容器里。比如Tomcat,你要真嫌弃Tomcat太低端。换Jboss也不是不行,他们都做了N年的优化和开发,稳定性绝对OK,集群规则,负载均衡,JVM等等都有现成的解决方案,还有其他的一些优化 ,可以说世界顶尖。满足你的高并发一点问题都没。

不要重复造轮子!!别人(JBoss)的集群规则好,负载均衡稳定,就用就是了!!!!所以,小的WB应用推荐tomcat,高并发的WB应用,推荐Jboss。并且合理设置集群规则,合理配置负载均衡,合理优化JVM,我保证,满足你的高并发websocket需求完全不是问题。。

加上我们的数据库选型和消息队列,都是为高并发添火的技术,所以代码写的干净的话,高并发完全不是问题。不用纠结,WB的效率如何,集群怎么做~负载均衡是不是要自己写。。答案是NO。 解决方案是 用高端点的应用容器!!

这就是WB和TCP比的优势!!他可以在容器里搞~ 集群方案,负载均衡方案都是人家做好的。

原生的TCP协议,你必须自己去解决这些问题。这真是一个大问题,想想就知道了,单单集群这块儿,有几个能做的好的。。

先贴pom.xml

4.0.0

com.mendao

websocket

war

1.0.0

门道的即时通讯服务器

1.1.39

3.1.0

4.0.3.RELEASE

3.6.10.Final

5.1.30

1.1.2

2.0.0

5.7.0

2.23.0

8.0.5

com.esotericsoftware.kryo

kryo

${kryo.version}

org.apache.activemq

activemq-core

${activemq.version}

org.apache.xbean

xbean-spring

3.17

javax.servlet

javax.servlet-api

${servlet.version}

provided

javax.annotation

jsr250-api

1.0

provided

javax.persistence

persistence-api

1.0.2

provided

org.aspectj

aspectjweaver

1.7.4

xerces

xercesImpl

2.11.0

antlr

antlr

2.7.7

dom4j

dom4j

1.6.1

org.springframework

spring-aop

${spring.version}

org.springframework

spring-context

${spring.version}

org.springframework

spring-beans

${spring.version}

org.springframework

spring-core

${spring.version}

org.springframework

spring-tx

${spring.version}

org.springframework

spring-web

${spring.version}

org.springframework

spring-webmvc

${spring.version}

org.springframework

spring-jdbc

${spring.version}

org.springframework

spring-expression

${spring.version}

org.springframework

spring-orm

${spring.version}

org.springframework

spring-websocket

${spring.version}

org.springframework

spring-jms

${spring.version}

org.springframework.data

spring-data-mongodb

1.4.1.RELEASE

org.springframework.data

spring-data-redis

1.2.1.RELEASE

mysql

mysql-connector-java

${mysql.version}

com.alibaba

fastjson

${fastjson.version}

ch.qos.logback

logback-classic

${logback.version}

ch.qos.logback

logback-core

${logback.version}

com.googlecode.xmemcached

xmemcached

${xmemcached.version}

commons-lang

commons-lang

2.6

commons-fileupload

commons-fileupload

1.3

commons-codec

commons-codec

1.9

commons-httpclient

commons-httpclient

3.1

org.apache.tomcat

tomcat-websocket

${tomcat.version}

test

org.apache.tomcat

tomcat-coyote

${tomcat.version}

provided

ROOT

org.apache.maven.plugins

maven-compiler-plugin

2.3.2

1.7

1.7

UTF-8

org.apache.maven.plugins

maven-resources-plugin

2.5

UTF-8

org.apache.maven.plugins

maven-war-plugin

2.2

false

然后,开始进入正题。web.xml配置。我贴上我的配置。

welcome.html

springmvc

org.springframework.web.servlet.DispatcherServlet

contextClass

org.springframework.web.context.support.AnnotationConfigWebApplicationContext

contextConfigLocation

com.mendao.config.WebConfig

springmvc

/

org.springframework.web.context.ContextLoaderListener

org.springframework.web.context.request.RequestContextListener

encodingFilter

org.springframework.web.filter.CharacterEncodingFilter

encoding

UTF-8

forceEncoding

true

encodingFilter

/*

org.springframework.web.util.IntrospectorCleanupListener

web.xml没什么可说的了。主要点已经标注。然后贴上

com.mendao.config.WebConfig

这个类让大家一看究竟!!完全可以直接复制下来

/*** WebSocket 配置类*/@Configuration//一定不能少

@ImportResource("classpath*:/applicationContext.xml") //重要!!加载spring的其他的xml配置文件,这种方式是注解方式+xml方式 相结合的配置方式!!

@EnableWebSocket //不能少

public class WebConfig extends WebMvcConfigurerAdapter implementsWebSocketConfigurer {

@Resourceprivate BootstrapHandler clientHandler; //注入实例

@Resourceprivate Bootstrapnterceptor interceptor; //注入实例

@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {//重要!处理器 URL地址 拦截器!! 都在这里加入!!//等会儿帖 处理器和 拦截器的代码//你需要更多处理器 或者URL 都在这里填就是了。其实一般一个就够了,一个核心处理器做请求中转。

registry.addHandler(clientHandler, "/bootstrap").addInterceptors(interceptor);

}//Allow serving HTML files through the default Servlet//完全可以无视下面的代码 @Override

public voidconfigureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {

configurer.enable();

}

}

下面是BootstrapHandler 的代码!都有注释

@Servicepublic class BootstrapHandler implementsWebSocketHandler {private final Logger logger = LoggerFactory.getLogger(BootstrapHandler.class);

@ResourceprivateBootstrapHandlerService bootstrapHandlerService;

@ResourceprivateCached cached;/*** 双工通讯 连接后 并且在这里心跳

*

*@paramsession

*@throwsException*/@Overridepublic void afterConnectionEstablished(WebSocketSession session) throwsException {

TextMessage textMessage;try{

HttpHeaders headers=session.getHandshakeHeaders();

String userAgent= headers.get("user-agent").get(0);

logger.info("LOGIN : " +userAgent);

//构造回应的消息,每次连接成功后要回应消息吖!告诉客户端已经连接成功了!消息就在这里面构造

textMessage= new TextMessage(“连接成功”);

}catch(Exception e) {

e.printStackTrace();

textMessage= new TextMessage(“连接失败”);

}

//这样就发送给客户端了~ 很简单!!

session.sendMessage(textMessage);

}/*** 处理发送过来的消息

*

*@paramsession

*@parammessage

*@throwsException*/@Overridepublic void handleMessage(WebSocketSession session, WebSocketMessage message) throwsException {try{

//如果连接成功!!这里面会不停的接收到心跳包!! 怎么处理~看你的了!!! 总之这个方法就是接受客户端发来消息的方法!!!

// message.getPayload()得到的是客户端发来的消息,比如“你好啊!” 之类的。得到后转成String就能处理了!

StringBuffer sb= newStringBuffer((String) message.getPayload());

//这个是我自己写的一个处理业务逻辑。你可以实现自己的业务逻辑

bootstrapHandlerService.handleMessage(session, sb);

}catch(Exception e) {

e.printStackTrace();

logger.error(e.getMessage());

}

}/*** 客户端 异常断开

*

*@paramsession

*@paramthrowable

*@throwsException*/@Overridepublic void handleTransportError(WebSocketSession session, Throwable throwable) throwsException {

logger.info(session.getId()+ " - 异常断开连接");

//所谓异常断开,例如:突然关闭HTML页面等等,总之不是用户正常关闭的!

//这个也是我自己实现的 异常处理的业务逻辑,你可以自己写

bootstrapHandlerService.handleError(session, throwable);

}/*** 连接已经断 开

*

*@paramsession

*@paramstatus

*@throwsException*/@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throwsException {

//只要是断开连接!不管是异常断开,还是普通正常断开,一定会进入这个方法。

String reason=status.getReason();if (reason == null) {

reason= "客户端 按指令正常退出";

}

logger.info(session.getId()+ " - 已经主动关闭连接 - 关闭码 - " + status.getCode() + " - 缘由 -" +reason);

//其实这里面封装了个session.close()释放了一些资源, 也是我自己实现的业务逻辑,你也可以自己写!

bootstrapHandlerService.connectionClose(session);

}/*** 握手成功 初始化操作在这里面进行

*

*@return

*/@Overridepublic booleansupportsPartialMessages() {

//一旦HTTP认证成功 这个方法先被调用 如果返回true 则进行上面那么N多方法的流程。如果返回的是false就直接拦截掉了。不会调用上面那些方法了!!

//就好像个构造器一样。这个是处理器 BootstrapHandler的构造器~return true;

}

}

然后贴上 Interceptor 拦截器的代码!! 实现的接口不能变!!里面没代码的原因是 我实在不知道在这里面做什么操作,感觉我的业务是用不到这两个方法。

@Servicepublic class Bootstrapnterceptor implementsHandshakeInterceptor {/*** 握手前

*

*@paramrequest

*@paramresponse

*@paramwebSocketHandler

*@paramstringObjectMap

*@return*@throwsException*/@Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler webSocketHandler, Map stringObjectMap) throwsException {return true;

}/*** 握手成功后

*

*@paramrequest

*@paramresponse

*@paramhandler

*@parame*/@Overridepublic voidafterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler, Exception e) {

}

}

然后我上一个HTML版的客户端测试程序!!

w

varheartbeat_timer= 0;varlast_health= -1;varhealth_timeout= 3000;

$(function(){//ws = ws_conn( "ws://211.100.41.186:9999" );

ws=ws_conn("ws://127.0.0.1:12345/bootstrap");

$("#send_btn").click(function(){varmsg=$("#mysendbox").val();

alert(msg);

alert(ws);

ws.send(msg);

$("#mysendbox").val("");

});

});functionkeepalive( ws ){vartime= newDate();if( last_health!= -1 &&( time.getTime()-last_health>health_timeout ) ){//此时即可以认为连接断开,可是设置重连或者关闭

$("#keeplive_box").html("服务器没有响应.").css({"color":"red"});//ws.close();

}else{

$("#keeplive_box").html("连接正常").css({"color":"green"});if( ws.bufferedAmount== 0){

ws.send('1'); }

}

}//websocket function

functionws_conn( to_url ){

to_url=to_url|| "";if( to_url== ""){return false;

}

clearInterval( heartbeat_timer );

$("#statustxt").html("Connecting...");varws= newWebSocket( to_url );

ws.onopen=function(){

$("#statustxt").html("connected.");

$("#send_btn").attr("disabled",false);

heartbeat_timer=setInterval(function(){keepalive(ws)},5000);

}

ws.οnerrοr=function(){

$("#statustxt").html("error.");

$("#send_btn").attr("disabled",true);

clearInterval( heartbeat_timer );

$("#keeplive_box").html("连接出错.").css({"color":"red"});

}

ws.onclose=function(){

$("#statustxt").html("closed.");

$("#send_btn").attr("disabled",true);

clearInterval( heartbeat_timer );

$("#keeplive_box").html("连接已关闭.").css({"color":"red"});

}

ws.onmessage=function(msg){vartime= newDate();if( msg.data==('1') ){

last_health=time.getTime();return;

}

$("#chatbox").val( $("#chatbox").val()+msg.data+ "\n");

$("#chatbox").attr("scrollTop",$("#chatbox").attr("scrollHeight"));

}returnws;

}

web socket连接状态:  连接中...

心跳状态:检测中...

发送文本到Websocket服务器

核心的就这么多。

这些方法理解了,其他的,靠自己发挥想象~

对了,每个不同的连接都会有一个不同的WebSocketSession session   你可以把这个session存入一个全局的ConcurrentHashMap中!!作为连接池!!

用的时候 用 map.get(key); 然后就能用sendMessage(); 发送给他消息了!!!

什么时候存这个session,这就看你的业务需要了。总之每个WebSocketSession 标识一个完全不同的新的连接。客户句柄来形容,也可以~

然后虽然你用上了WB 但是还是要自己做出来。心跳包~ 数据分割处理~ 等等一些基本的业务逻辑~ 什么地方用消息队列分发,那就要看你业务怎么设计了。

离线消息怎么做,可以找我私聊QQ。631768417 有不懂的也可以私聊我QQ

最后!!最有用的!!websocket可以做移动端 (安卓IOS等)即时通讯服务器。但是需要用到一个jar包。在github上搜索 websocket client (websocket的客户端) 有java的实现也有object-c的实现

这个思路提供出来之后,你就知道websocket 的强大了吧。不但敏捷开发!而且跨平台!!可以做android推送解决方案!! 当然也可以整合ios做即时通讯!!当然!!HTML更可以!因为原生的就是HTML!!! 强大的websocket为企业即时通讯方案提供了更好的出路!!!

核心已经讲解!更多的发挥想象吧!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/267377.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#实现文件下载代码

提供个C#实现文件下载代码  一.概述: 本文通过一个实例向大家介绍用Visual C#进行Internet通讯编程的一些基本知识。我们知道.Net类包含了请求/响应层、应用协议层、传输层等层次。在本程序中,我们运用了位于请求/响应层的WebRequest类以及W…

Cookie 与Session 的区别

Cookie 与Session 的区别(转载) 原地址: http://www.cnblogs.com/shiyangxt/archive/2008/10/07/1305506.html 两个都可以用来存私密的东西,同样也都有有效期的说法。 区别在于:session是放在服务器上的,过期与否取决于…

voyage java_GitHub - yezilong9/voyage: 采用Java实现的基于netty轻量的高性能分布式RPC服务框架...

VoyageOverview采用Java实现的基于netty轻量的高性能分布式RPC服务框架。实现了RPC的基本功能,开发者也可以自定义扩展,简单,易用,高效。Features服务端支持注解配置客户端实现Filter机制,可以自定义Filter基于netty3.…

产品架构开发方法(2011中国软件技术大会)

上周末在国家会议中心举办的2011中国软件技术大会上我做了一个分享:产品架构开发方法。很高兴能在不同的大会上做演讲,但更高兴的是能够结交更多的朋友。 这个演讲内容包括了企业架构、业务分析、软件产品线、产品管理等内容,知识量有点大哦。…

IOS 调用系统照相机和相册

/** * 调用照相机 */ - (void)openCamera { UIImagePickerController *picker [[UIImagePickerController alloc] init]; picker.delegate self; picker.allowsEditing YES; //可编辑 //判断是否可以打开照相机 if ([UIImagePickerController isSourceTypeAvailable:UIImag…

IDC机房KVM应用案例分析

IDC机房KVM应用案例分析<?xml:namespace prefix"o">?xml:namespace>一、背景介绍随着信息技术的发展&#xff0c;各行各业都在马不停蹄的开展着各自的信息化建设步伐。对于设计制造创新科技产品为运行主业的设计院而言&#xff0c;内部IT基础设备与机房管…

java跟踪会话_JavaWeb会话跟踪

cookie和session是常用的会话跟踪技术cookie机制1、web应用程序是使用HTTP协议传输数据的&#xff0c;HTTP协议是无状态的协议&#xff0c;一旦数据交换完毕就会关闭链接。Cookie可以弥补HTTP协议无状态的不足。位于&#xff1a;javax.servlet.http.Cookie2、Cookie具有不可跨域…

Uva 1625 - Color Length(DP)

题目链接 https://cn.vjudge.net/problem/UVA-1625 【题意】 输入两个长度分别为n和m的颜色序列&#xff08;n&#xff0c;m<5000&#xff09;&#xff0c;要求按一定规则合并成一个序列&#xff0c;规则是每次可以把一个序列开头的颜色放到新序列的尾部。例如对于序列GBBY…

教你用身份证号查社保卡号 个人电脑号

适用前提&#xff1a;在广东省内交社保 用身份证查社保号第一步 登录广东社保局网站 广东社保局网站 在“全省个人养老保险信息查询“框输入你的身份证号码 这时要密码&#xff0c;面此要注册&#xff0c;注册时那红星星不用理会&#xff0c;除了姓名其他乱填即可&#xff0c;这…

X3D.Studio编辑器界面介绍

2019独角兽企业重金招聘Python工程师标准>>> X3DStudio编辑器的界面可分为【菜单栏】、【属性栏】、【显示栏】和【对象信息栏】四大部分。如下图所示。 X3D.Engine 通用虚拟现实引擎安装包下载地址&#xff1a;http://www.x3dengine.cn/Download.aspx 技术支持QQ群…

浏览器BOM模型

百度百科&#xff1a;浏览器对象模型(BrowserObjectModel) 主要功能 1. 弹出新浏览器窗口的能力&#xff1b;2. 移动、关闭和更改浏览器窗口大小的能力&#xff1b;3. 可提供WEB浏览器详细信息的导航对象&#xff1b;4.可提供浏览器载入页面详细信息的本地对象&#xff1b;5 .可…

java map的理解_java中的hashmap理解

Asp&period;net Boilerplate之AbpSession扩展当前Abp版本1.2,项目类型为MVC5. 以属性的形式扩展AbpSession,并在"记住我"后,下次自动登录也能获取到扩展属性的值,版权归"角落的白板报"所 ...使用Mavne生成可以执行的jar文件到目前为之,还没有运行Hello…

Asp.net中DataBinder.Eval用法的总结

Asp.net中DataBinder.Eval用法的总结 缩短的Eval语法与DataBinder.Eval的不同点在于&#xff0c;Eval会根据最近的容器对象&#xff08;例如DataListItem&#xff09;的DataItem属性来自动地解析字段&#xff0c;而DataBinder.Eval需要使用参数来指定容器 Eval 和 Bind绑定的数…

php 三方即时通讯_php即时通讯解决方案-请问PHP能否实现即时通讯?

最简单的说&#xff0c;它可以定期刷新&#xff0c;比如10秒的间隔。新数据&#xff0c;反馈到前台&#xff0c;没有新数据等待下次刷新。但实际上在应用中需要考虑消息的及时性、服务器压力等。php即时通讯。可以用comet来设计节点。js、socketphp即时通讯系统。总之&#xff…

保存、删除配置文件

保存&#xff1a;write <> copy running-config startup-config 删除&#xff1a;erase startup-config转载于:https://blog.51cto.com/jackcyc/756029

javascript 中文与Unicode相互转化

javascript 中文与Unicode相互转化 CreateTime--2018年3月30日11:26:50 Author:Marydon /*** 中文与Unicode的相互转换*/ var chineseUnicodeConverter {toUnicode:function(chinese){// 自定义String去除左右空格方法 var str chinese || "";str str.tri…

php fopen插入文本_PHP 文件创建/写入

在项目中&#xff0c;我们在服务器上面操作文件&#xff0c;是一件非常频繁的事情。比如用户的投票的数据写入到txt文档中&#xff0c;缩略图上传&#xff0c;文件上传&#xff0c;及文件移动等等操作都离不开PHP 文件创建/读写/上传(上传我将会在下一节中讲到)。PHP 创建文件 …

【原译】在amazon kindle上安装Metasploit

免责申明&#xff08;必读&#xff01;&#xff09;&#xff1a;本博客提供的所有教程的翻译原稿均来自于互联网&#xff0c;仅供学习交流之用&#xff0c;切勿进行商业传播。同时&#xff0c;转载时不要移除本申明。如产生任何纠纷&#xff0c;均与本博客所有人、发表该翻译稿…

java实现将一个正整数分解质因数,Java将一个正整数分解质因数

import java.io.*;public class Factorization{public void division(int input){for(int i 2; i < input / 2; i){if(input % i 0){System.out.print(i "*");division(input / i);}}System.out.print(input);System.exit(0);//不能没有这句&#xff0c;否则结…

这就是搜索引擎:核心技术详解

这就是搜索引擎&#xff1a;核心技术详解张俊林 著ISBN 978-7-121-14865-12012年1月出版定价&#xff1a;45.00 元16开320页宣传语&#xff1a;改变全世界人们生活方式的“信息之门”内 容 简 介搜索引擎作为互联网发展中至关重要的一种应用&#xff0c;已经成为互联网各个领域…