websocket实战(3) 错误处理及配置管理

回顾

websocket实战(1) 入门

websocket实战(2) 信息处理发送、接收和编码

通过前面说明,已经轻松构建一个简单的websocket ServerEndPoint了。可以为EndPoint加上解码器,编码器,为EndPoint提供支持。但是,作为一个服务器,遇到错误怎么办?websocket作为一个简单的容器组件,也具备简单配置管理功能。

1.错误处理

[email protected]

其实很简单,就是在ServerEndPoint类中,添加一个方法,要求该方法被@onError修饰。

如下

@ServerEndpoint("/testendpoint")
public class TestEndpoint {
   ...
   @OnError
   public void error(Session session, Throwable t) {
      t.printStackTrace();
      ...
   }
}

代码片段(代码没有意义,纯属测试)

@ServerEndpoint("/echo")
public class EchoEndpoint {
    @OnMessage
    public String onMessage(String message,Session session) {
        System.out.println("Received : " + message);
        int random = new Random().nextInt(5);
        if(random==3){
            throw new RuntimeException("自定义异常");
        }else{
            System.out.println("random="+random);
        }
        return message+"-"+session.getId();
    }

    @OnOpen
    public void myOnOpen(Session session) {
        session.getUserProperties().put("startTime",new Date());
        System.out.println("WebSocket opened: " + session.getId());
    }

    @OnClose
    public void myOnClose(CloseReason reason) {
        System.out.println("Closing a WebSocket due to " + reason.getReasonPhrase());
    }

    @OnError
    public void error(Session session, Throwable t) {
        System.out.println("发生错误,请注意");
        t.printStackTrace();
    }
}

如果遇到错误,将抛异常如下

发生错误,请注意(error方法中输出)

java.lang.RuntimeException: 自定义异常
    at com.sample.websocket.endpoint.EchoEndpoint.onMessage(EchoEndpoint.java:21)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeBase.onMessage(PojoMessageHandlerWholeBase.java:80)
    at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:393)
    at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:494)
    at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:289)
    at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:130)
Closing a WebSocket due to An unrecoverable IOException occurred so the connection was closed(myOnClose调用输出)
    at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:56)
  ....

1.2 Error Handing

主要错误有3种。

Deployment Errors (部署期间,比如tomcat启动)
Errors Originating in Websocket Application Code(websocket endpoint 发生错误)
Errors Originating in the Container and/or Underlying Connection(连接peer内部错误)
javax.websocket. CloseReason

CloseReason.CloseCode

public enum CloseCodes implements CloseReason.CloseCode {
...
/**
 * 1006 is a reserved value and MUST NOT be set as a status code in a
 * Close control frame by an endpoint.  It is designated for use in
 * applications expecting a status code to indicate that the
 * connection was closed abnormally, e.g., without sending or
 * receiving a Close control frame.
 */
CLOSED_ABNORMALLY(1006),
...
}
//1006是一个比较特殊的错误码
//其他错误码,参照Enum CloseCodes

if the local
container determines the session has timed out, the local implementation must use the websocket protocol
close code 1006

2.配置管理

2.1 先从javax.websocket.Session说起

Session 代表一个有效连接。周期从(Open ->Close)

简单将Session的方法分为几类(当然你也许有更好的分类)

  1. 配置信息(其中有些配置信息来源于WebContainer)
  2. Session状态信息
  3. 自定义存储信息
  4. 请求信息
  5. Session的操作方法

测试代码

package com.sample.websocket.endpoint;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Set;

@ServerEndpoint("/config")
public class ReceiveEndpoint {
   @OnMessage
   public void textMessage(Session session, String msg) {
      System.out.println("Text message: " + msg);
      Set<Session> openSessions = session.getOpenSessions();
      System.out.println(" session.OpenSessions.size" + openSessions.size());
   }
   @OnMessage
   public void binaryMessage(Session session, ByteBuffer msg) {
      System.out.println("Binary message: " + msg.toString());
   }
   @OnMessage
   public void pongMessage(Session session, PongMessage msg) {
      System.out.println("Pong message: " +  msg.getApplicationData().toString());
   }

   @OnClose
   public void nClose(Session session, CloseReason reason) {
      System.out.println("Pong message: " +  reason.getReasonPhrase()+"-->"+reason.getCloseCode());
   }

   @OnError
   public void onError(Throwable t){
      t.printStackTrace();
   }
   @OnOpen
   public void onOpen(Session session){
      System.out.println("session.getId()=" + session.getId());

      Set<Session> openSessions = session.getOpenSessions();
      System.out.println(" session.OpenSessions.size=" + openSessions.size());
      session.getUserProperties().put("userName","Guest"+session.getId());

      Iterator<Session> iterator = openSessions.iterator();
      System.out.println("open session list===========");
      while(iterator.hasNext()){
         Session s = iterator.next();
         String sid = s.getId();
         System.out.println("session.id==>"+ sid);
         Object user = s.getUserProperties().get("userName");
         System.out.println("session."+sid+"username==>"+user);
      }
      System.out.println();
      System.out.println();

      WebSocketContainer wsc = session.getContainer();
      System.out.println("WebSocketContainer Info==========");
      System.out.println("webSocketContainer=" + wsc);
      System.out.println("defaultAsyncTimeout->"+wsc.getDefaultAsyncSendTimeout());
      System.out.println("defaultMaxBinaryMessageBufferSize-->"+wsc.getDefaultMaxBinaryMessageBufferSize());
      System.out.println("defaultMaxSessionIdleTimeout-->"+wsc.getDefaultMaxSessionIdleTimeout());
      System.out.println("installedExtensions.size==>" + wsc.getInstalledExtensions().size());
      System.out.println();
      System.out.println();
      System.out.println("session parameter");
      System.out.println("session.getMaxBinaryMessageBufferSize()==>"+session.getMaxBinaryMessageBufferSize());
      System.out.println("session.getMaxIdleTimeout()==>"+session.getMaxIdleTimeout());
      System.out.println("session.getNegotiatedSubprotocol()==>"+session.getNegotiatedSubprotocol());
      System.out.println("session.getProtocolVersion()==>"+session.getProtocolVersion());
      System.out.println("session.getRequestURI()==>" + session.getRequestURI());
      System.out.println();
      System.out.println();
      Set<MessageHandler> messageHandlers = session.getMessageHandlers();
      Iterator<MessageHandler> messageHandlerIterator = messageHandlers.iterator();
      System.out.println("MessageHandlers");
      while(messageHandlerIterator.hasNext()){
         MessageHandler handler = messageHandlerIterator.next();
         System.out.println(handler.toString());
      }
      System.out.println("session.getUserPrincipal().getName()==>"+session.getUserPrincipal());
   }
}

输出结果如下

session.getId()=0
 session.OpenSessions.size=0
open session list===========

WebSocketContainer Info==========
webSocke[email protected]4d3de8ab
defaultAsyncTimeout->-1
defaultMaxBinaryMessageBufferSize-->8192
defaultMaxSessionIdleTimeout-->0
installedExtensions.size==>0

session parameter
session.getMaxBinaryMessageBufferSize()==>8192
session.getMaxIdleTimeout()==>0
session.getNegotiatedSubprotocol()==>
session.getProtocolVersion()==>13
session.getRequestURI()==>/wsexample/config

MessageHandlers
[email protected]10882
[email protected]ee5c773
[email protected]9b445
session.getUserPrincipal().getName()==>null
Text message: Hello WebSocket!
 session.OpenSessions.size=1

下面是我分析结果

1.session.id是从0递增的

2.session.getOpenSessions(),API定义是获取连接EndPoint的Session的数目,但实际上永远返回1

3.session.getOpenSessions() 在@OnOpen方法中调用返回0,在@OnMessage方法中调用返回1,即便打开了多个连接也是如此。在Tomcat7.72中如此。

4.定义了3个OnMessage修饰的方法,MessageHandler也是三个

5.几个参数从WebSocketContainer中的参数,与Session的参数一致。比如MaxBinaryMessageBufferSize等

6.即使在方法中修改了WebSocketContainer的配置参数值,session中对应的值也不会变。

session.getOpenSessions() API

Return a copy of the Set of all the open web socket sessions that represent connections to the same endpoint to which this session represents a connection. The Set includes the session this method is called on.

调整Session中的若干参数值

    @OnOpen 
    public void onOpen(final Session session) { 
        session.setMaxIdleTimeout(TIMEOUT); 
        ... 
    }
时间: 2024-10-12 20:39:27

websocket实战(3) 错误处理及配置管理的相关文章

websocket实战(4) websocket版贪食蛇游戏(tomcat官方自带)

websocket实战(1) 入门 websocket实战(2) 信息处理发送.接收和编码 websocket实战(3) 错误处理及配置管理 通过前面3篇的阐述,相信可以构建一个简单的socket应用了.当然,也会遗漏了许多知识点,相信会在以后分享的实例中捎带说明下. 本文的主要是分析下tomcat官方自带的贪食蛇游戏.为什么选择分析这个项目呢. 贪食蛇游戏规则,人人明白,业务方面不需要过多解释(当然这款websocket版的游戏规则也有一定特色). 游戏设计简单,一个对象足以完成游戏,但不涉及

[Teamcenter 2007 开发实战] 获取错误或提示信息

前言 TC 的开发分为CF 端开发和Web 端开发. CF端和Web 端各自有自己的错误信息提示方式. 两种方式是否可以有一些整合? 整合的好处即统一了显示, 又减少了重复 CF 端错误信息 CF 端错误一般是给OMF 端来使用的. OMF是一个富客户端的程序. 错误方式就是弹出一个窗口. 代码开发方式如下: CheckDstat(uiShowText("errText001", NULL, UI_ATTENTION_TEXT, *mfail, WHERE)); *mfail = 11

C# WebApi+Task+WebSocket实战项目演练(四)

一.课程介绍 本次分享课程属于<C#高级编程实战技能开发宝典课程系列>中的第四部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享出来给大家进行学习,不断的收集.整理和完善此系列课程!本高级系列课程适合人群如下: 1.有一定的NET开发基础并对WebApi.Task.WebSocket技术有一定了解和认识. 2.喜欢阿笨的干货分享课程的童鞋们. 希望大家在选择阿笨的 C#高级编程实战技能开发宝典课程系列的时候,根据自身的情况进行选择,由于本次课程不是零基础教学课程系列,所

signalr使用websocket报500错误

signalr使用websocket报500错误,WebSocket connection to 'ws://localhost:22862/signalr/connect?transport=webSockets&clientProtocol=1.5&connectionToken=Ab7SuqLggw%2BJL5kWeWcdv%2FI%2FdnRcikASgBnVNnsJu1qtIGq5tV7iXvQkDim%2FYFCJ9RNJvWTe9Zgjte2siJz2KXHX3n8ERyw4

websocket实战(1) 入门

1.WebSocket介绍 1.1 概念 WebSocket是HTML5中一系列新的API,或者说新规范,新技术.支持页面上使用Web Socket协议与远程主机进行全双工的通信.它引入了WebSocket接口并且定义了一个全双工的通信通道,通过一个单一的套接字在Web上进行操作. 1.2 websocket vs HTTP 首先,web技术发展经历了以下阶段. 静态页面(html) 动态页面(cgi,j2ee,php...) Ajax技术 comet技术(轮询) 1.2.1 实现方案对比 举个

WebSocket实战之——携带Token验证绑定clientId到uid(微信)

HTML代码:通过为. <!DOCTYPE> <html> <meta charset="utf-8"/> <title>WebSocket Test</title> <script src="http://cdn.bootcss.com/jquery/2.1.3/jquery.min.js" type="text/javascript"></script> &l

WebSocket 实战

http://www.ibm.com/developerworks/cn/java/j-lo-WebSocket/ 本文介绍了 HTML5 WebSocket 的由来,运作机制及客户端和服务端的 API 实现,重点介绍服务端(基于 Tomcat7)及客户端(基于浏览器原生 HTML5 API)实现的详细步骤:并通过实际客户案例描述了客户端如何在 WebSocket 架构下使用 HTTP 长连接与服务器实现实时通信及消息推送的功能,读者通过阅读本文中案例示例代码的实现,能够更深刻理解 WebSoc

websocket实战(2) 信息处理发送、接收和编码

websocket 和传统意义上的socket编程虽然存在差别,但也存在相通概念,也分服务端和客户端. 主要区别 对于websocket,客户端的编写方式是通过JS编写回调函数完成交互:而传统socket,则需要连接端口,通过输入输出流来传递信息,完成交互: 传统的socket,服务端则需要绑定端口,通过accept 方法,等待客户端的连接.websocket 规范则把处理细节由web服务器来完成. 数据处理是websocket的一项主要工作.按工作阶段划分,主要包括以下方面. 信息发送 信息解

WebSocket实战之——JavaScript例子

源码地址:https://github.com/Tinywan/PHP_Experience 一.详细代码案例 详细解读一个简单html5 WebSocket的Js实例教程,附带完整的javascript websocket实例源码,以及实例代码效果演示页面,并对本实例的核心代码进行了深入解读.从WebSocket通讯三个阶段(打开握手.数据传递.关闭握手)进行了探讨,各阶段中浏览器和服务器做了些什么事情也有所涉及. //检查浏览器是否支持WebSocket if(window.WebSocke