一篇文章让你学习使用websocket

2017-05-01  本文已影响0人  flykyle

学习教程

跟着下面两篇教程的任意一篇写一遍,WebSocket基本上就算掌握了。

WebSocket介绍

web应用的出现需要客户端和服务端更多的交互,http只能在客户端每次请求服务端的时候建立短暂的连接,已经不能满足需求。虽然long-poll和Ajax也可以实现服务端向浏览器发送数据,但它们这种轮询的方式存在一些弊端,比如请求延迟和http过度请求。在需要实时连接(real-time)的应用中,这种弊端更加明显。

websocket是HTML5中新加入的内容。通过websocket(协议),每个浏览器(客户端)和服务端建立一个长连接,双方都可以随时主动地向对方发送消息。

Java EE 7 中已经集成了websocket,通过使用注解,可以很方便地创建一个websocket应用,主要有下面五个注解:

@ServerEndpoint:定义websocket的地址;

@OnOpen:服务端和客户端建立连接时调用;

@OnMessage:发送数据时调用;

@OnClose:关闭连接时调用;

@OnError:出错时调用。

教程主要内容

下面是第一篇教程的主要内容,你可以到这里下载源码。

创建websocket服务

@ServerEndpoint定义了websocket的服务端地址,还定义了编译发送出去的信息和解析收到的信息的类。

package com.ws.sticker;

import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.websocket.EncodeException;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint(
  value="/story/notifications",
  encoders={StickerEncoder.class}, 
  decoders={StickerDecoder.class})
public class StoryWebSocket {
    // 保存所有的 sticker
    private static final List<Sticker> stickers = Collections.synchronizedList(new LinkedList<Sticker>()); 
    // 保存所有客户端的 session
    private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>()); 
    
    @OnMessage
    public void onMessage(Session session, Sticker sticker){
        // 有消息从客户端发送过来,保存到列表中,然后通知所有的客户端
        stickers.add(sticker);
        for(Session openSession : sessions){
            try {
                openSession.getBasicRemote().sendObject(sticker);
            } catch (IOException | EncodeException e) {
                sessions.remove(openSession); 
            }
        }
    }
    
    @OnOpen
    public void onOpen(Session session) throws IOException, EncodeException{
        // 有新的客户端连接时,保存此客户端的session,并且把当前所有的sticker发送给它
        sessions.add(session);
        for(Sticker sticker : stickers){
            session.getBasicRemote().sendObject(sticker);
        }
    }
    
    @OnClose
    public void onClose(Session session){
        // 有客户端断开连接时 ,从session列表中移除此客户端的session
        sessions.remove(session);
    }
}

定义编译类

StickerEncoder.class编译将要发送出去的信息:将要发送的Sticker对象转化成JsonObject对象,然后通过JsonWriter发送到客户端。

package com.ws.sticker;

import java.io.IOException;
import java.io.Writer;

import javax.json.JsonObject;
import javax.json.JsonWriter;
import javax.json.spi.JsonProvider;
import javax.websocket.EncodeException;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;

public class StickerEncoder implements Encoder.TextStream<Sticker> {

    @Override
    public void init(EndpointConfig config) {
        // TODO Auto-generated method stub
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }

    @Override
    public void encode(Sticker sticker, Writer writer) throws EncodeException, IOException {
        JsonProvider provider = JsonProvider.provider();
        JsonObject jsonSticker = provider.createObjectBuilder()
                .add("action", "add")
                .add("x", sticker.getX())
                .add("y", sticker.getY())
                .add("sticker", sticker.getImage())
                .build();
        JsonWriter jsonWriter = provider.createWriter(writer);
        jsonWriter.write(jsonSticker);
    }

}

定义解析类

StickerDecoder.class解析服务端收到的信息:通过Reader获得接收到的信息JsonObject,然后转化成Sticker对象。

package com.ws.sticker;

import java.io.IOException;
import java.io.Reader;

import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.json.spi.JsonProvider;
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;

public class StickerDecoder implements Decoder.TextStream<Sticker> {

    // Do not create a JsonReader object. To create readers and writes, use the
    // JsonProvider class.

    @Override
    public void init(EndpointConfig config) {
        // TODO Auto-generated method stub
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }

    @Override
    public Sticker decode(Reader reader) throws DecodeException, IOException {
        JsonProvider provider = JsonProvider.provider();
        JsonReader jsonReader = provider.createReader(reader);
        JsonObject jsonSticker = jsonReader.readObject();
      
        Sticker sticker = new Sticker();
        sticker.setX(jsonSticker.getInt("x"));
        sticker.setY(jsonSticker.getInt("y"));
        sticker.setImage(jsonSticker.getString("sticker"));
        return sticker;
    }

}

创建websocket客户端

var socket = null;

function initialize() {
    ...
    // 连接到websocket服务端
    socket = new WebSocket('ws://localhost:8080/learn/story/notifications');
    // 定义接收消息时执行的方法
    socket.onmessage = onSocketMessage;
}

function onSocketMessage(event) {
    if(event.data){
        var receivedSticker = JSON.parse(event.data);
        log("Received Object: " + JSON.stringify(receivedSticker));
        
        ...
    }
}

window.onload = initialize;

观察现象

运行Java web程序,在多个浏览器中打开 http://localhost:8080/learn/story/notifications ,当其中一个浏览器的内容改变的时候,其他浏览器也会相应地改变。

总结

通过上面的练习,主要学到了:

上一篇下一篇

猜你喜欢

热点阅读