`
CshBBrain
  • 浏览: 642934 次
  • 性别: Icon_minigender_1
  • 来自: 成都
博客专栏
B7d9bf34-126e-301f-819e-81f2615b5a2a
开源WebSocket服务...
浏览量:143131
Group-logo
HTML5移动开发
浏览量:136470
社区版块
存档分类
最新评论

开源WebSocket服务器项目CshBBrain客户端超时检查机制剖析

阅读更多

  WebSocket要求服务器与客户端之间要保持连接状态,当然当客户端或服务器端关闭了连接对方是有办法检测到的,这个无需我们关心;可以通过发送心跳保持2者之间连接的有效性。从另外一个方面来看,如果是客户端和服务器之间有交互的应用,客户端长时间没有发送业务数据到服务器则说明用户可能在短时间内不会再使用客户端了,这时服务器端可以将这些闲置的连接关闭以达到减少资源的开销。

  为了达到这个目的,首先我们需要知道的是客户端是否已经闲置超过了指定的时限,那我们怎样知道呢。最初考虑的方案是这样的,每次客户端发送业务数据到服务器端时,我们就调用System.currentTimeMillis 函数获取到当前系统的毫秒数并在连接对应的Client对象中记录下这个数量preReceiveTimestamp。在系统中创建一个线程遍历每个客户端连接,取出preReceiveTimestamp 和系统当前的毫秒数System.currentTimeMillis  进行比较,如果 System.currentTimeMillis  - preReceiveTimestamp 之差超过了设置的超时限制 则说明客户端已经闲置超时 可以关闭了。

  但是System.currentTimeMillis 函数的调用需要从 应用线程 切换 到系统内核线程 然后再切换到应用线程中,他们之间的切换如果太过频繁对系统的性能还是有一定的影响。有人测试过在一般的PC服务器上1000w次System.currentTimeMillis调用大概需要12秒左右,平均每次1.3毫秒。这对于大并发量的服务器来说性能上的影响不得不考虑。

  为了避免频繁的调用System.currentTimeMillis,而又要达到检查客户端闲置是否超过时限,在开源WebSocket服务器CshBBrain中进行了优化。优化后的方案为当客户端有发送数据到服务器端时,将连接对应的Client对象中的数据接收标识设置为true;在系统中创建一个线程,线程遍历每个客户端连接,检测客户端Client对象中的数据接收标识是否为true,如果不为true则说明客户端闲置超时可以关闭了,如果数据接收标识为true则说明客户端没有闲置超时,并将客户端Client对象中的数据接收标识设置为false,线程没隔系统设置的超时时限对客户端进行是否闲置超时检查一次。这样就避免了频繁的调用System.currentTimeMillis函数,将影响降低到最低。

 

客户端闲置检查线程核心代码,截取的MasterServer类中对应代码:

 

private void startClientMonitor(){

while(noStopRequested){

try {

if(this.timeOut > 0){// 超时阀值

Iterator<Integer> it = clients.keySet().iterator();

while(it.hasNext()){

Integer key = it.next();

Client client = clients.get(key);

if(!client.isReadDataFlag()){// 超时没有收到数据

client.close();// 关闭连接

clients.remove(key);// 从映射表中删除连接

}else{

client.setReadDataFlag(false);// 将读取数据标识设置为false

}

}

this.clientMonitor.sleep(this.timeOut * 60 * 1000);// 隔指定时限检测一次

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

 

服务接收到客户端发送的业务数据处理将数据读取标识设置为true,截取的Client类中对应的代码:

 

private boolean readRequest(ByteBuffer byteBuffer){

SocketChannel socketChannel = (SocketChannel) this.key.channel();

boolean readSuccess = false;// 是否读取到数据标识

boolean returnValue = false;// 返回值

try{

int dataLength = 0;

do{// 读取客户端请求的数据并解码

dataLength = socketChannel.read(byteBuffer);

if(dataLength > 0){

byteBuffer.flip();

this.decoderHandler.process(byteBuffer,this);// 解码处理

byteBuffer.clear();

readSuccess = true;

this.readDataFlag = true;// 将读取数据标识设置为真

this.preBlank = false;// 上次不为空读

}else{

if(this.preBlank){

++this.readCount;

}

this.preBlank = true;

break;

}

}while(dataLength > 0);

if(this.readCount >= zoreFetchCount){// 空读超过指定次数,关闭链接,返回

log.info("the max count read: " + this.readCount);

this.close();

returnValue = false;

return returnValue;

}

}catch(IOException e){

e.printStackTrace();

this.close();

returnValue = false;

return returnValue;

}

if(readSuccess){// 如果读取到数据

if(requestWithFile.isReadFile()){// 是否读取文件

if(requestWithFile.readFinish()){// 是否读取完毕文件

//if(requestWithFile.getFileReceiver().finishWrite()){// 是否读取完毕文件

returnValue = true;

if(MasterServer.keepConnect){//长连接

this.registeRead();

}

}else{// 没有读取完毕文件,注册通道,继续读取

if(MasterServer.keepConnect){//长连接

this.registeRead();

}else{

try{

this.inputMonitorWorker.registeRead(key);

}catch(Exception e){

e.printStackTrace();

this.close();

returnValue = false;

this.requestWithFile.getFileReceiver().close();// 关闭文件

return returnValue;

}

this.inRead.compareAndSet(true, false);

}

returnValue = false;// 将文件内容读取完后再进行处理

}

}else{// 普通请求,没有上传文件

returnValue = true;

if(MasterServer.keepConnect){//长连接

this.registeRead();

}

}

}else{

returnValue = false;

if(MasterServer.keepConnect){//长连接

this.registeRead();

}

}

if(returnValue){// 读取完毕放入处理队列

HashMap<String, String> requestData = requestWithFile.getRequestData();

if(requestData != null){

this.getBizObjects().add(requestData);

}

}

return returnValue;

}

分享到:
评论
2 楼 CshBBrain 2012-10-15  
文库虫 写道
楼主可以采用这个博客里面的机制来实现性能会更高一点http://www.cppblog.com/Solstice/archive/2011/05/04/145691.html

谢谢,我参考参考
1 楼 文库虫 2012-10-15  
楼主可以采用这个博客里面的机制来实现性能会更高一点http://www.cppblog.com/Solstice/archive/2011/05/04/145691.html

相关推荐

    dotnet-NetSockets是一个开源库旨在使服务器和客户端设置更容易和更简洁

    《.NET开发中的NetSockets开源库:简化服务器与客户端通信》 在.NET开发领域,高效、便捷地实现服务器和客户端的通信是至关重要的。针对这一需求,开发者们创造了一个名为NetSockets的开源库,它极大地简化了网络...

    Jmeterwebsocket插件包最新.rar

    WebSocket是Web应用中一种先进的通信协议,它允许在客户端和服务器之间建立持久的、低延迟的连接,从而实现双向通信。在传统的HTTP协议下,每次请求-响应都需要重新建立连接,而WebSocket则在初次握手后维持长连接,...

    websocket依赖包

    WebSocket是一种在客户端和服务器之间建立持久连接的网络通信协议,它允许双向实时通信,极大地提升了Web应用程序的性能和效率。在IT行业中,WebSocket已经成为实时Web应用程序的重要支柱,尤其是在需要低延迟、高...

    websocket-samplers-1.2.2.zip

    WebSocket是一种在客户端和服务器之间建立长连接的通信协议,广泛应用于实时通信、游戏、聊天应用等场景。这个插件的出现,使得测试工程师可以方便地模拟WebSocket客户端的行为,对服务器端的WebSocket服务进行压力...

    Jmeter websocket测试完整插件包

    WebSocket是一种在客户端和服务器之间建立持久连接的协议,它允许双方进行双向通信,极大地提高了实时交互性。在IT行业中,特别是在Web应用性能测试领域,WebSocket的测试变得越来越重要。Apache JMeter,作为一款...

    jmeter websocket sample jar.zip

    在现代Web应用程序中,WebSocket已经成为实时通信的重要协议,它提供了双向全双工通信,使得服务器与客户端可以实时交换数据。为了对WebSocket服务进行性能测试和负载测试,我们可以利用Apache JMeter工具,特别是...

    JAVA上百实例源码以及开源项目源代码

    Tcp服务端与客户端的JAVA实例源代码 2个目标文件 摘要:Java源码,文件操作,TCP,服务器 Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多...

    JAVA上百实例源码以及开源项目

     基于JAVA的UDP服务器模型源代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 ...

    java开源包8

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包1

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包6

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包9

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包10

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    JMeter安装包以及JMeterWebSocketSampler-1.0.2-SNAPSHOT和依赖包

    WebSocket是一种在客户端和服务器之间建立持久连接的协议,广泛应用于实时通信场景,如在线游戏、聊天应用和股票交易等。JMeterWebSocketSampler是JMeter的一个扩展,使得测试WebSocket服务成为可能。它的主要特性...

    java开源包2

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包3

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包11

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包5

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包7

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

Global site tag (gtag.js) - Google Analytics