WebSocket 的一些东东

HTML5 WebSocket
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
在这里插入图片描述
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。

当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。

以下 API 用于创建 WebSocket 对象。

var Socket = new WebSocket(url, [protocol] );

Javax.websocket.server包含注解,类,接口用于创建和配置服务端点
Javax.websocket包则包含服务端点和客户端点公用的注解,类,接口,异常
创建一个编程式的端点,需要继承Endpoint类,重写它的方法。
创建一个注解式的端点,将自己的写的类以及类中的一些方法用前面提到的包中的注解装饰(@EndPoint,@OnOpen等等)。

@ServerEndpoint注解的类被注解的类将被注册成为一个WebSocket端点,所有的配置项都在这个注解的属性中 ( 如:@ServerEndpoint(“/ws”)
有打了@ServerEndpoint注解的,都会被ServerEndpointExporter发现并注册

备注:如果使用war包部署,就不必做此步骤,因为它将由容器自己提供和管理

@Configuration
@ConditionalOnWebApplication
public class WebSocketAutoConfig {
    @Bean
    public ServerEndpointExporter endpointExporter() {
        return new ServerEndpointExporter();
    }

    @Bean
    public MySpringConfigurator mySpringConfigurator() {
        return new MySpringConfigurator();
    }
}
@OnOpen

 当有新的WebSocket连接进入时,对该方法进行回调
 注入参数的类型:

  1. Session

  2. HttpHeaders

  3.ParameterMap

 @OnClose

当有WebSocket连接关闭时,对该方法进行回调 注入参数的类型

  1.Session

@OnError

 当有WebSocket抛出异常时,对该方法进行回调  
  注入参数的类型:

  1.Session

  2.Throwable

 @OnMessage
   当接收到字符串消息时,对该方法进行回调
   注入参数的类型:

  1.Session

  2.String  

@OnBinary
  当接收到二进制消息时,对该方法进行回调
  注入参数的类型:

  1.Session

  2.byte[]

@OnEvent
  当接收到Netty的事件时,对该方法进行回调
  注入参数的类型:

  1.Session

  2.Object

调用
webSocketClient.sendMessage(socketMessageReq);

/**
     * 向客户端发送消息
     * @param socketMessageReq
     */
    @PostMapping(value = "send")
    public void sendMessage(@RequestBody SocketMessageReq socketMessageReq){
        log.info("向客户端发送消息,SocketController.sendMessage, socketMessageReq  : {}",socketMessageReq);

        if(socketMessageReq.getAppType() == null){
            log.info("sendMessage appType is null");
            return;
        }

       StringBuffer sessionKey = new StringBuffer().append(socketMessageReq.getAppType()).append(":");

        if(socketMessageReq.getEnterpriseId() != null && !StringUtils.isEmpty(socketMessageReq.getUserCode())){
            sessionKey.append(socketMessageReq.getEnterpriseId()).append(":").append(socketMessageReq.getUserCode());
        }else if(socketMessageReq.getEnterpriseId() != null && StringUtils.isEmpty(socketMessageReq.getUserCode())){
            sessionKey.append(socketMessageReq.getEnterpriseId());
        }else if(socketMessageReq.getEnterpriseId() == null && !StringUtils.isEmpty(socketMessageReq.getUserCode())){
            sessionKey.append(socketMessageReq.getUserCode());
        }

        Session session = NewlinkWebSocket.sessionMap.get(sessionKey.toString());
        log.info("向客户端发送消息 key为:{},-- session为 : {}",sessionKey,session);
        if(session != null && session.isOpen()) {
            session.sendText(socketMessageReq.getMessage());
        }
    }
@ServerEndpoint(path = "/ws/{arg}" )
@Slf4j
public class NewlinkWebSocket {

    public static Map<String, Session> sessionMap = new ConcurrentHashMap<>();


    @BeforeHandshake
    public void handshake(Session session, HttpHeaders headers, @RequestParam Integer enterpriseId, @RequestParam String userCode, @RequestParam Integer appType, @RequestParam MultiValueMap reqMap, @PathVariable String arg, @PathVariable Map pathMap) {
        session.setSubprotocols("stomp");
        if (appType == null || (enterpriseId == null && StringUtils.isEmpty(userCode))) {
            session.sendText("{\n" +
                    "\n" +
                    "  \"code\": \"320\",\n" +
                    "  \"message\" : \"连接失败!\"\n" +
                    "  \"data\" : \n" +
                    "}");
            session.close();
        }
        StringBuffer sessionKey = new StringBuffer().append(appType).append(":");
        if (enterpriseId != null && !StringUtils.isEmpty(userCode)) {
            sessionKey.append(enterpriseId).append(":").append(userCode);
        } else if (enterpriseId != null && StringUtils.isEmpty(userCode)) {
            sessionKey.append(enterpriseId);
        } else if (enterpriseId == null && !StringUtils.isEmpty(userCode)) {
            sessionKey.append(userCode);
        }

        log.info("建立连接成功:key: {}", sessionKey);
        if(sessionKey != null ) {
            sessionMap.put(sessionKey.toString(), session);
            session.setAttribute("key",sessionKey.toString());
        }

    }


    @OnOpen
    public void onOpen(Session session, HttpHeaders headers, @RequestParam Integer enterpriseId, @RequestParam String userCode, @RequestParam Integer appType, @RequestParam MultiValueMap reqMap, @PathVariable String arg, @PathVariable Map pathMap) {
        if(appType == null){
            session.sendText("failed");
            session.close();
        }

        log.info("new connection,session size: {}", sessionMap.size());
    }


    @OnClose
    public void onClose(Session session) throws IOException {
       String key = session.getAttribute("key");
       log.info(key);
       if(!StringUtils.isEmpty(key)) {
           sessionMap.remove(key);
       }

       log.info("one connection closed ,session size: {}", sessionMap.size());

    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        throwable.printStackTrace();
    }

    @OnMessage
    public void onMessage(Session session, String message) {
        log.info("收到客户端消息:{}",message);
        session.sendText("ok");
    }

    @OnBinary
    public void onBinary(Session session, byte[] bytes) throws UnsupportedEncodingException {
        for (byte b : bytes) {
            System.out.println(b);
        }
        log.info(new String(bytes, "utf-8"));
        session.sendBinary(bytes);
    }

    @OnEvent
    public void onEvent(Session session, Object evt) {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            switch (idleStateEvent.state()) {
                case READER_IDLE:
                    System.out.println("read idle");
                    break;
                case WRITER_IDLE:
                    System.out.println("write idle");
                    break;
                case ALL_IDLE:
                    System.out.println("all idle");
                    break;
                default:
                    break;
            }
        }
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值