2

我正在使用 java 的 socketio 和 netty ,我对他们都是新手。

我的客户端代码如下所示。

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <title >webSocket test</title>
    <script src="http://code.jquery.com/jquery-1.12.4.min.js"></script>
    <script src="https://cdn.socket.io/3.1.3/socket.io.min.js" integrity="sha384-cPwlPLvBTa3sKAgddT6krw0cJat7egBga3DJepJyrLl4Q9/5WLra3rrnMcyTyOnh" crossorigin="anonymous"></script>
    < !-- New Bootstrap core CSS file-->
    <!-- Optional Bootstrap theme file (generally not necessary to import) -->
    <!- -jQuery file. Be sure to introduce before bootstrap.min.js -->

    <!-- The latest Bootstrap core JavaScript file-->
    <script type=" text/javascript">
        $(function(){
            /**
             * The socket.emit("event name", "parameter data") method of the
             front-end js is used when triggering the back-end custom message event, * front-end js The socket.on("event name", anonymous function (data sent by the server to the client)) for monitoring server-side events
             **/

            //io({path: 'ws://localhost:9099/', transports: ['websocket'] ,upgrade: false});

            var socket = io.connect("ws://localhost:9099",{transports: ['websocket'] ,upgrade: false});
            var firstconnect = true;
            if(firstconnect) {
                console.log("First connection initialization");
                //Monitor server connection event
                socket.on('connect',function(){
                    socket.emit('messageEvent', 'Hello server');
                    console.log("First connection success");
                    $("#tou").html("Connect to the server successfully!");
                     });

                //Monitor server shutdown service event

                socket.on('disconnect', function(){
                    $("#tou").html("Disconnected from the server!");
                    });
                //Monitor server Send message event
                socket.on('responseEvent', function(data) {
                    console.log('data');
                    $("#msg").html($("#msg").html() + "<br/>" + data);
                } );
                firstconnect = false;
            } else {
                console.log("why?");
                socket.socket.reconnect();
            }

            $('#send').bind('click', function() {
                send();
            });

            function send(){
                if (socket != null) {
                    var message = document.getElementById('message').value;
                    var title = "message";
                    var obj = {message:message,title:title};
                    var str = JSON.stringify(obj);
                    socket.emit("messageEvent",str);
                    console.log("message event" , str);

                } else {
                    alert('Send');
                }
            }
        });
    </script>

</head>
<body>
<div class="page-header" id="tou">
    webSocket Demo
</div>
<div class="well" id="msg">
</div>
<div class="col-lg">
    <div class="input-group">
        <input type="text" class="form-control" placeholder="send Message..." id="message">
        <span class="input-group-btn">
        <button class="btn btn-default" type="button" id="send" >send</button>
      </span>
    </div><!-- /input-group -->
</div><!-- /.col-lg-6 -->
</div><!-- /.row --><br><br>

</body>
</html>

事件处理程序如下所示。

@Component
public class MessageEventHandler {

    private static final Logger logger  = LoggerFactory.getLogger(MessageEventHandler.class);

    public static ConcurrentMap<String, SocketIOClient> socketIOClientMap = new ConcurrentHashMap<>();


    @Autowired
    private RedissonClient redisson;

    @Resource
    private SocketIOServer socketIOServer;

    @OnConnect
    public void  onConnect(SocketIOClient client){
        Map<String,Object> clientMap = new HashMap<>(16);

        client.sendEvent("responseEvent", client.getSessionId().toString()+": "+ "hello");

        if(client!=null){
            String room = client.getHandshakeData().getSingleUrlParam("room");
            String nameSpace = client.getNamespace().getName();
            logger.info("namespace {} ",nameSpace);

            String sessionId = client.getSessionId().toString();
            logger.info("namespace, room={}, sessionId={},namespace={}",room,sessionId,nameSpace);
            if(StringUtils.isEmpty(room)){
                //client.joinRoom(room);
                clientMap.put("rooms",room);
            }
            clientMap.put("createTime", LocalDateTime.now().toString());
            redisson.getBucket("room"+sessionId).trySet(clientMap);

        }

        return;
    }

    /**
     * Triggered when the client closes the connection
     *
     * @param client
     */
    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
        logger.info("client:" + client.getSessionId() + "disconnected");
    }

    /**
     * Client events
     *
     * @param client   
     * @param request
     * @param msg     
     */
    @OnEvent(value = "messageEvent")
    public void onMessageEvent(SocketIOClient client, AckRequest request, String msg) {

        System.out.println("haha");
        logger.info("message :&quot; + msg);

        //Post the message back
        JSONObject jsonObject = JSON.parseObject(msg);
        String message = jsonObject.getString("message");
        Collection<SocketIOClient> clients = socketIOServer.getBroadcastOperations().getClients();
        for (SocketIOClient clientByRoom : clients) {
            clientByRoom.sendEvent("responseEvent", client.getSessionId().toString()+":   "+message);
        }
    }

}

服务器启动代码如下所示。


@Component
@Order(1)
public class SocketServerRunner implements CommandLineRunner {

    private static Logger logger = LoggerFactory.getLogger(SocketServerRunner.class);

    @Resource
    private SocketIOServer socketIOServer;

    @Resource
    private PubSubStore pubSubStore;

    @Autowired
    private RedissonClient redisson;

    @Override
    public void run(String... args) throws Exception {
        logger.info("socketIOServer ");
        socketIOServer.start();

        pubSubStore.subscribe(PubSubType.DISPATCH, data -> {
            Collection<SocketIOClient> clients = null;
            String room = data.getRoom();
            String namespace = data.getNamespace();
            Packet packet = data.getPacket();
            String jsonData = packet.getData();
            if(!StringUtils.isEmpty(namespace)){
                SocketIONamespace socketIONamespace = socketIOServer.getNamespace(namespace);
                if(StringUtils.isEmpty(room)){
                    clients = socketIONamespace.getRoomOperations(room).getClients();
                }
            }else{
                clients = socketIOServer.getBroadcastOperations().getClients();
            }

            if(!CollectionUtils.isEmpty(clients)){
                for (SocketIOClient client : clients) {
                    client.sendEvent("messageEvent",jsonData);
                }
            }
        }, DispatchMessage.class);
       // addNameSpace(socketIOServer);
    }

我在OnConnect注释的方法上获得了连接注册,但该方法似乎运行了两次,因为我在套接字连接时获得了两次日志。我不知道为什么会这样。

但更糟糕的是,用客户端 javascript 编写的 emit 方法不起作用。没有错误。执行发射下方的日志。但是OnEventjava EventHandler 中的注释方法似乎没有检测到它。

有人可以帮我理解这一点吗?

4

1 回答 1

2

显然,问题似乎出在图书馆上。较新版本的 socketio 客户端库与 java 的 netty 依赖项存在一些兼容性问题,这导致了奇怪的问题。

我对 netty socketio 的依赖如下所示,这显然是回答这个问题时最新的。

        <dependency>
            <groupId>com.corundumstudio.socketio</groupId>
            <artifactId>netty-socketio</artifactId>
            <version>1.7.19</version>
        </dependency>

为了让客户端库顺利运行,我不得不将库从 3.XX 降级到 2.XX 。

在我的情况下

<script src="https://cdn.socket.io/3.1.3/socket.io.min.js" integrity="sha384-cPwlPLvBTa3sKAgddT6krw0cJat7egBga3DJepJyrLl4Q9/5WLra3rrnMcyTyOnh" crossorigin="anonymous"></script>

<script src="https://cdn.bootcss.com/socket.io/2.1.1/socket.io.js"></script>
于 2021-07-02T06:13:29.893 回答