• netty-socketio 示例代码


    socket.io是一个不错的websocket项目,github上有它的java实现:netty-socketio 及 示例项目 netty-socketio-demo,基本上看看demo示例项目就能很快上手了,但是demo中的示例代码场景为js做客户端,如果需要在java中连接websocket server,可以参考下面的示例:

    一、服务端代码

    package com.corundumstudio.socketio.demo.server;
    
    import com.corundumstudio.socketio.AckRequest;
    import com.corundumstudio.socketio.Configuration;
    import com.corundumstudio.socketio.SocketIOClient;
    import com.corundumstudio.socketio.SocketIOServer;
    import com.corundumstudio.socketio.listener.ConnectListener;
    import com.corundumstudio.socketio.listener.DataListener;
    import io.socket.client.Socket;
    
    /**
     * Created by yangjunming on 2017/1/13.
     */
    public class DemoSocketServer {
    
    
        public static void main(String[] args) throws InterruptedException {
    
            Configuration config = new Configuration();
            config.setHostname("localhost");
            config.setPort(9092);
    
            final SocketIOServer server = new SocketIOServer(config);
    
            server.addConnectListener(new ConnectListener() {
                @Override
                public void onConnect(SocketIOClient client) {
                    String token = client.getHandshakeData().getUrlParams().get("token").get(0);
                    if (!token.equals("87df42a424c48313ef6063e6a5c63297")) {
                        client.disconnect();//校验token示例
                    }
                    System.out.println("sessionId:" + client.getSessionId() + ",token:" + token);
                }
            });
    
    
            server.addEventListener(Socket.EVENT_MESSAGE, String.class, new DataListener<String>() {
                @Override
                public void onData(SocketIOClient client, String data, AckRequest ackSender) throws Exception {
                    System.out.println("client data:" + data);
                    server.getBroadcastOperations().sendEvent(Socket.EVENT_MESSAGE, "hi");
                }
            });
    
            server.start();
            Thread.sleep(Integer.MAX_VALUE);
            server.stop();
        }
    
    }
    

    服务端的主要工作,就是添加各种事件的监听,然后在监听处理中,做相应的处理即可。

    注:添加事件监听时,如果重复添加监听,会导致事件被处理多次,所以最好在添加事件监听前,先移除之前已经存在的监听,类似下面这样

            chat1namespace.removeAllListeners(Socket.EVENT_MESSAGE);
            chat1namespace.addEventListener(Socket.EVENT_MESSAGE, String.class,...
    

      

    二、客户端代码

    java连接netty-socketio,还要借助另一个开源项目:socket.io-client-java

    package com.corundumstudio.socketio.demo.client;
    
    import io.socket.client.IO;
    import io.socket.client.Socket;
    import io.socket.emitter.Emitter;
    
    import java.net.URISyntaxException;
    
    /**
     * Created by yangjunming on 2017/1/13.
     */
    public class DemoSocketClient {
    
        public static void main(String[] args) throws URISyntaxException, InterruptedException {
            IO.Options options = new IO.Options();
            options.transports = new String[]{"websocket"};
            options.reconnectionAttempts = 2;
            options.reconnectionDelay = 1000;//失败重连的时间间隔
            options.timeout = 500;//连接超时时间(ms)
    
    //        final Socket socket = IO.socket("http://localhost:9092/?token=123456", options);//错误的token值连接示例
            final Socket socket = IO.socket("http://localhost:9092/?token=87df42a424c48313ef6063e6a5c63297", options);
    
            socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    socket.send("hello");
                }
            });
    
            socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    System.out.println("连接关闭");
                }
            });
    
            socket.on(Socket.EVENT_MESSAGE, new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    System.out.println("sessionId:" + socket.id());
                    for (Object obj : args) {
                        System.out.println(obj);
                    }
                    System.out.println("收到服务器应答,将要断开连接...");
                    socket.disconnect();
                }
            });
            socket.connect();
        }
    }
    

    客户端类似,也是加一些事件监听,然后做相应处理即可。

    上面的例子,演示了client向server连接时,如何做基本的连接认证(基于token),以及基本的消息收发。

    运行效果:

    服务端输出

    sessionId:f52e9fa3-6216-4742-87de-3228a74469f9,token:87df42a424c48313ef6063e6a5c63297
    client data:hello

    客户端输出

    sessionId:f52e9fa3-6216-4742-87de-3228a74469f9
    hi
    收到服务器应答,将要断开连接...
    连接关闭

    注:框架已经自带了一些预设的事件,见下面的代码片段

        /**
         * Called on a successful connection.
         */
        public static final String EVENT_OPEN = "open";
    
        /**
         * Called on a disconnection.
         */
        public static final String EVENT_CLOSE = "close";
    
        public static final String EVENT_PACKET = "packet";
        public static final String EVENT_ERROR = "error";
    
        /**
         * Called on a connection error.
         */
        public static final String EVENT_CONNECT_ERROR = "connect_error";
    
        /**
         * Called on a connection timeout.
         */
        public static final String EVENT_CONNECT_TIMEOUT = "connect_timeout";
    
        /**
         * Called on a successful reconnection.
         */
        public static final String EVENT_RECONNECT = "reconnect";
    
        /**
         * Called on a reconnection attempt error.
         */
        public static final String EVENT_RECONNECT_ERROR = "reconnect_error";
    
        public static final String EVENT_RECONNECT_FAILED = "reconnect_failed";
    
        public static final String EVENT_RECONNECT_ATTEMPT = "reconnect_attempt";
    
        public static final String EVENT_RECONNECTING = "reconnecting";
    
        public static final String EVENT_PING = "ping";
    
        public static final String EVENT_PONG = "pong";
    

    如果不够的话,可以自行扩展,无非就是一些字符串常量。  

    三、广播消息隔离

    前面的示例,没有"域"的概念,所有连到socket server上的client,如果收发广播的话,全都能收到,如果只希望将消息发到指定的某一"批"用户,可以让这些client归到某个域(或组织机构)里,这样在指定的域范围内广播,只有在这个域内的client才能接受广播,详见下面的示例:(其实变化很小)

    server端:

    package com.corundumstudio.socketio.demo.server;
    
    import com.corundumstudio.socketio.*;
    import com.corundumstudio.socketio.listener.ConnectListener;
    import com.corundumstudio.socketio.listener.DataListener;
    import io.socket.client.Socket;
    
    /**
     * Created by yangjunming on 2017/1/13.
     */
    public class DemoSocketServer {
    
    
        public static void main(String[] args) throws InterruptedException {
            SocketIOServer server = getServer();
            addRoom(server);
            startServer(server);
        }
    
        private static Configuration getConfig() {
            Configuration config = new Configuration();
            config.setHostname("localhost");
            config.setPort(9092);
            return config;
        }
    
        private static void handleConn(SocketIOServer server) {
            server.addConnectListener(new ConnectListener() {
                @Override
                public void onConnect(SocketIOClient client) {
                    String token = client.getHandshakeData().getUrlParams().get("token").get(0);
                    if (!token.equals("87df42a424c48313ef6063e6a5c63297")) {
                        client.disconnect();//校验token示例
                    }
                    System.out.println("sessionId:" + client.getSessionId() + ",token:" + token);
                }
            });
        }
    
        private static void addRoom(SocketIOServer server) {
            final SocketIONamespace chat1namespace = server.addNamespace("/room1");
            chat1namespace.addEventListener(Socket.EVENT_MESSAGE, String.class, new DataListener<String>() {
                @Override
                public void onData(SocketIOClient client, String data, AckRequest ackRequest) {
                    chat1namespace.getBroadcastOperations().sendEvent(Socket.EVENT_MESSAGE, "ack:" + data);
                }
            });
        }
    
        private static SocketIOServer getServer() throws InterruptedException {
            final SocketIOServer server = new SocketIOServer(getConfig());
            handleConn(server);
    
            server.addEventListener(Socket.EVENT_MESSAGE, String.class, new DataListener<String>() {
                @Override
                public void onData(SocketIOClient client, String data, AckRequest ackSender) throws Exception {
                    System.out.println("client data:" + data);
                    server.getBroadcastOperations().sendEvent(Socket.EVENT_MESSAGE, "hi");
                }
            });
            return server;
        }
    
        private static void startServer(SocketIOServer server) throws InterruptedException {
            server.start();
            Thread.sleep(Integer.MAX_VALUE);
            server.stop();
        }
    
    }
    

    客户端:

    package com.corundumstudio.socketio.demo.client;
    
    import io.socket.client.IO;
    import io.socket.client.Socket;
    import io.socket.emitter.Emitter;
    
    import java.net.URISyntaxException;
    
    /**
     * Created by yangjunming on 2017/1/13.
     */
    public class DemoSocketClient {
    
        public static void main(String[] args) throws URISyntaxException, InterruptedException {
            IO.Options options = new IO.Options();
            options.transports = new String[]{"websocket"};
            options.reconnectionAttempts = 2;
            options.reconnectionDelay = 1000;//失败重连的时间间隔
            options.timeout = 500;//连接超时时间(ms)
    
            //错误的token值连接示例
    //        final Socket socket = IO.socket("http://localhost:9092/?token=123456", options);
    
            //常规连接
    //        final Socket socket = IO.socket("http://localhost:9092/?token=87df42a424c48313ef6063e6a5c63297", options);
    
            //连接到指定的聊天室
            final Socket socket = IO.socket("http://localhost:9092/room2?token=87df42a424c48313ef6063e6a5c63297", options);
    
            socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    socket.send("hello");
                }
            });
    
            socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    System.out.println("连接关闭");
                }
            });
    
            socket.on(Socket.EVENT_MESSAGE, new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    System.out.println("sessionId:" + socket.id());
                    for (Object obj : args) {
                        System.out.println(obj);
                    }
                    System.out.println("收到服务器应答,将要断开连接...");
                    socket.disconnect();
                }
            });
            socket.connect();
        }
    }
    

    注意上面连接时,room1的指定,其它就不多说了,代码就是最好的注释:)

  • 相关阅读:
    微信带参数二维码保存至本地
    合并图片添加水印并压缩文件提供下载
    C#压缩文件夹坑~
    JS中Float类型加减乘除 修复
    JQ 操作 radio、checkbox 、select
    jquery.uploadifive 解决上传限制图片或文件大小
    2017好好写博客咯
    LINQ to SQL Count/Sum/Min/Max/Avg Join
    LINQ to SQL:Where、Select/Distinct
    微信开发那点事(No.001)
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/netty-socketio-demo.html
Copyright © 2020-2023  润新知