Java API实现WebSocket客户端

上一篇是说浏览器与服务器建立WebSocket通信,而这篇来通过WebSocket-api提供的接口来实现客户端的功能。

客户端主要也是通过注解的方式来实现,但是创建的方式会用到其他类,注解为@ClientEndpoint,其他注解一样,WebSocketClient.java具体代码如下:

@ClientEndpoint
public class WebSocketClient {

    private Logger logger = Logger.getLogger(WebSocketServer.class);
    private Session session;

    @OnOpen
    public void open(Session session){
        logger.info("Client WebSocket is opening...");
        this.session = session;
    }

    @OnMessage
    public void onMessage(String message){
        logger.info("Server send message: " + message);
    }

    @OnClose
    public void onClose(){
        logger.info("Websocket closed");
    }


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

    public void send(String message){
        this.session.getAsyncRemote().sendText(message);
    }

    public void close() throws IOException{
        if(this.session.isOpen()){
            this.session.close();
        }
    }
}

另外添加两个方法sendclose,可以主动发送消息和关闭连接。只要可以获取到建立连接的session,就可以进行相关的操作,如消息发送、状态判断等等。
以上为客户端的简单实现,接下来,来看看@ClientEndpoint注解的代码:

@Retention(RetentionPolicy.RUNTIME)
@Target({java.lang.annotation.ElementType.TYPE})
public @interface ClientEndpoint
{
  String[] subprotocols() default {};

  Class[] decoders() default {};

  Class[] encoders() default {};

  Class configurator() default ClientEndpointConfig.Configurator.class;
}

可以看见,有四个配置参数,接下来分别对这些配置进行实现:

subprotocols: 为字符串数组,表示支持的子协议名称列表

无特别

Decoder的实现:

public class SampleDecoder implements Decoder.Text<String>{

    public void init(EndpointConfig paramEndpointConfig) {
        // Auto-generated method stub
    }

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

    public String decode(String paramString) throws DecodeException {
        // Auto-generated method stub
        return paramString.toLowerCase();
    }

    public boolean willDecode(String paramString) {
        // Auto-generated method stub
        return true;
    }

}

Encoder实现


public class SimpleEncoder implements javax.websocket.Encoder.Text<String> {

    public void init(EndpointConfig paramEndpointConfig) {
        //Auto-generated method stub
        System.out.println("Encoder init: " + paramEndpointConfig.getUserProperties());
    }

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

    public String encode(String paramT) throws EncodeException {
        //Auto-generated method stub
        return paramT.toUpperCase();
    }

}

encode方法是接收到数据进行解码操作,如对字符串解码,对json格式转换为对象等等;

Configurator实现

public class SampleConfigurator extends Configurator {

    @Override
    public void beforeRequest(Map> headers) {
        //Auto-generated method stub
        System.out.println(headers);
    }

    @Override
    public void afterResponse(HandshakeResponse handshakeResponse) {
        //Auto-generated method stub
        System.out.println(handshakeResponse);
    }

}

可以通过打印来查看这些参数是什么,我们通过函数名称就可以知道,beforeRequest是在请求之前调用,可以对请求头进行修改或者查看;afterResponse是在握手成功后调用的,handshakeResponse为握手响应头;

而现在的客户端配置如下:

@ClientEndpoint(
        configurator=SampleConfigurator.class,
        decoders={SampleDecoder.class},
        encoders={SimpleEncoder.class},
        subprotocols={"subprotocol1"})
public class WebSocketClient {

    private Logger logger = Logger.getLogger(WebSocketServer.class);
    private Session session;

    ......
}

添加主程序AppMain.java:

public class AppMain {

    public static void main(String[] args) 
            throws DeploymentException, IOException, URISyntaxException, InterruptedException {
        // Auto-generated method stub
        WebSocketContainer conmtainer = ContainerProvider.getWebSocketContainer();
        WebSocketClient client = new WebSocketClient();
        conmtainer.connectToServer(client, 
                new URI("ws://localhost:8080/websocket/chat?query=Picasso"));

        int turn = 0;
        while(turn++ < 10){
            client.send("send text: " + turn);
            Thread.sleep(1000);
        }
        client.close();
    }

}

先启动服务器,之后启动客户端的应用程序,查看控制台

服务端控制台:

2015-12-21 23:28:10,673  INFO (cc.eabour.websocket.filter.DispatcherFilter:30) - Request URL: http://localhost:8080/websocket/chat
2015-12-21 23:28:10,684  INFO (cc.eabour.websocket.WebSocketServer:23) - WebSocket is opening...
2015-12-21 23:28:10,685  INFO (cc.eabour.websocket.WebSocketServer:25) - Sesson id: 1a
2015-12-21 23:28:10,685  INFO (cc.eabour.websocket.WebSocketServer:26) - Query string: query=Picasso
2015-12-21 23:28:10,731  INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: B
2015-12-21 23:28:11,734  INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: C
2015-12-21 23:28:12,739  INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: D
2015-12-21 23:28:13,743  INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: E
2015-12-21 23:28:14,746  INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: F
2015-12-21 23:28:15,751  INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: G
2015-12-21 23:28:16,753  INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: H
2015-12-21 23:28:17,756  INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: I
2015-12-21 23:28:18,758  INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: J
2015-12-21 23:28:19,761  INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: K
2015-12-21 23:28:20,764  INFO (cc.eabour.websocket.WebSocketServer:42) - Websocket closed

客户端控制台:

{Sec-WebSocket-Version=[13], Upgrade=[websocket], Host=[localhost:8080], Sec-WebSocket-Key=[Wwy8SvU9vSmJClaLPw+z1w==], Connection=[upgrade]}
org.apache.tomcat.websocket.WsHandshakeResponse@dd550c
Encoder init: {}
2015-12-21 23:28:10,700  INFO (cc.eabour.websocket.WebSocketServer:31) - Client WebSocket is opening...
2015-12-21 23:28:10,731  INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:11,735  INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:12,740  INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:13,744  INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:14,748  INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:15,752  INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:16,754  INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:17,757  INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:18,759  INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:19,762  INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server

仔细一看,在注解中配置的Encoder和Decoder没有起作用,分别在encode和decode方法中添加打印语句,都没有生效:

    public String decode(String paramString) throws DecodeException {
        // Auto-generated method stub
        return "MESS:" + paramString.toLowerCase();
    }

    .....

    public String encode(String paramT) throws EncodeException {
        //Auto-generated method stub
        System.out.println("encode: " + paramT);
        return "mess:" + paramT.toUpperCase();
    }

最后通过查看encode和decode方法的调用堆栈,而得知调用这些方法的方法为sendObject,这时才恍然大悟,当客户端发送的为Object类型的时候,才会去调用Encoder和Decoder,所以修改方法:

//WebSocketClient.java

    public void send(Object message){
        this.session.getAsyncRemote().sendObject(message);
    }

到此,大功告成:

--服务器
2015-12-21 23:37:47,637  INFO (cc.eabour.websocket.WebSocketServer:23) - WebSocket is opening...
2015-12-21 23:37:47,638  INFO (cc.eabour.websocket.WebSocketServer:25) - Sesson id: 1b
2015-12-21 23:37:47,638  INFO (cc.eabour.websocket.WebSocketServer:26) - Query string: query=Picasso
2015-12-21 23:37:47,670  INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: mess:SEND TEXT: B
2015-12-21 23:37:48,671  INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: mess:SEND TEXT: C
2015-12-21 23:37:49,673  INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: mess:SEND TEXT: D
2015-12-21 23:37:50,683  INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: mess:SEND TEXT: E
......
--客户端
{Sec-WebSocket-Version=[13], Upgrade=[websocket], Host=[localhost:8080], Sec-WebSocket-Key=[NGvTXYipeBUGuMn9SpwZWg==], Connection=[upgrade]}
org.apache.tomcat.websocket.WsHandshakeResponse@1d28d39
Encoder init: {}
2015-12-21 23:37:47,639  INFO (cc.eabour.websocket.WebSocketServer:31) - Client WebSocket is opening...
encode: send text: B
2015-12-21 23:37:47,670  INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
encode: send text: C
......

Java API WebSocket客户端基本实现,可以参照,实现更复杂的功能。

不吝赐教

项目Github地址:https://github.com/FlowerBirds/WebSocketExplorer

参考资料:

  • https://tools.ietf.org/html/rfc6455#section-11.5
  • https://tyrus.java.net/documentation/1.12/index/websocket-api.html

你可能感兴趣的:(websocket)