使用带有Express和nodejs的socket.io-client将查询发送到java服务器

时间:2015-06-12 12:54:33

标签: node.js express socket.io

我有一个基于Express的网络应用程序。 nodejs后端使用java服务器执行一些繁重的操作。 Express和java服务器之间的对话是使用socketio完成的。 nodejs服务器是客户端,使用socket.io-client向java服务器发送查询。 javaserver基于netty-socketio。

以下是我在我的nodejs app中所做的事情:

    var io = require('socket.io-client')
    var socket = io.connect('http://localhost:8080');

    socket.on('connect', function () {

        console.log('0 Connected!');

        socket.emit('myEvent', ['0' ,'here is the query'], function (data) {
          console.log('\tSending query ... waiting for ACK0');
          console.log(data); 
        });

        socket.on('serverResponse', function (data) {
            console.log('\tserverResponse event triggered, data:');
            console.log(data);
        });

    });

在我的网络应用程序之外调用此脚本时,一切都像魅力一样,但当我从express调用此代码时,我的客户端无法连接(我没有到达'0 Connected!'行)。没有错误消息。

奇怪的是,如果我第一次运行我的Web应用程序,抛出一个查询,然后启动我的java服务器,客户端连接到java服务器,一切正常(仅针对该查询)。关于如何解决这个问题的任何线索?

编辑1

这是我想要实现的模式:

client                      javascript backend                   java server
via browser         <--->   node/Express/socketio-client  <--->  netty-socketio           
@client's machine     |     @my server                      |    @my server (the same)
                      |                                     |
                   myDNS:80                           localhost:8080

java服务器上的更多精度。这是squeleton:

public class App {

    public static void main(String[] args) throws InterruptedException, UnsupportedEncodingException {

        Configuration config = new Configuration();
        config.setHostname("localhost");
        config.setPort(8080);

        final SocketIOServer server = new SocketIOServer(config);

        server.addEventListener("myEvent", String[].class, new DataListener<String[]>() {

            @Override
            public void onData(final SocketIOClient client, String[] data, final AckRequest ackRequest) {

              //Id of the client
              String id = data[0];

              //Acknowledge the request:
              ackRequest.sendAckData("ACK_"+id);

              //doing some calculations ...
              // ... ... ...
              // ... ... ...

              client.sendEvent("serverResponse", new VoidAckCallback(){
                  @Override
                  protected void onSuccess() {}
              }, "I am the answer from the server");
           }
        });

        server.start();
        System.out.println("[JAVA SERVER INFO] Java server started.");

        Thread.sleep(60000*3);//Integer.MAX_VALUE);

        server.stop();
        System.out.println("[JAVA SERVER INFO] Java server stopped.");
    }

}

我的网络应用程序nodejs后端和我的java服务器在同一台机器上运行,与socket.io的通信是通过localhost:8080完成的。再一次,奇怪的是客户端的脚本在快速框架之外使用时工作,这让我觉得它可能是socket.io-client和Express之间的兼容性问题。

编辑2

我修改了socket.io-client代码以查看更多详细信息,我补充道:

  socket.on('connect_error', function(err){
    console.log(err);
  });

  socket.on('connect_timeout', function(){
    console.log("connect_timeout");
  });

  socket.on('reconnect_attempt', function(){
    console.log("reconnect_attempt");
  });

当我关闭java服务器运行客户端时,我收到'connect_error'事件。当java服务器打开时,我根本没有任何消息。似乎连接既没有失败也没有成功,没有任何事情发生......关于如何更好地调试它的任何想法?

编辑3

以下是我用来处理来自浏览器的请求的代码:

  • index.js:

      var express = require('express');
      var router = express.Router();
      var controller = require('../controllers/myController.js');
    
      /* GET home page. */
      router.get('/', function(req, res, next) {
        res.render('index', { title: 'Express' });
      });
    
      module.exports = router;
    
      router.post('/api/getProcessedData', function(req, res, next){
        var text = req.body.text;
        controller.get_processed_data(text, res);
      });
    
  • myController.js:

      var socket = require('socket.io-client')('http://localhost:8080');
    
      module.exports.get_processed_data = function(text, res) {
        var timestamp = new Date().getTime();
        console.log('starting client');
    
        socket.on('connect', function () {
    
          console.log("client connected.");
    
          socket.emit('myEvent', [timestamp ,text], function (data) {
            console.log('\tSending query ... waiting for ACK');
            console.log(data); 
          });
    
          socket.on('serverResponse', function (data) {
            console.log('\tserverResponse' event trigged, data:');
            res.send(data);
          });
    
        });
    
        socket.on('connect_error', function(err){
          console.log(err);
        });
    
        socket.on('connect_timeout', function(){
          console.log("connect_timeout");
        });
    
        socket.on('reconnect_attempt', function(){
          console.log("reconnect_attempt");
        });
    
        socket.on('reconnecting', function(){
          console.log("reconnecting");
        });
      }
    

1 个答案:

答案 0 :(得分:1)

控制器的结构有点混乱。以下是一些错误的事情:

  1. 您在加载模块时连接到Java服务器,但是在路由被命中之前,您不会分配connect事件处理程序。这意味着您通常会错过连接事件,除非服务器尚未运行。所以,这完全解释了你所观察到的。如果启动Express服务器时java服务器已启动,则会错过connect事件,因此您永远不会执行get_processed_data()函数中的任何逻辑。

  2. 每次启动路径时都会安装一个新的连接处理程序,这意味着您将分配多个事件处理程序,但由于第一个问题,它们都不会被命中。

  3. 如果你想连续连接socket.io连接,这将是重写控制器的一种方法:

    var socket = require('socket.io-client')('http://localhost:8080');
    
    socket.on('connect', function () {
      console.log("client connected.");
    });
    
    socket.on('connect_error', function(err){
      console.log(err);
    });
    
    socket.on('connect_timeout', function(){
      console.log("connect_timeout");
    });
    
    socket.on('reconnect_attempt', function(){
      console.log("reconnect_attempt");
    });
    
    socket.on('reconnecting', function(){
      console.log("reconnecting");
    });
    
    var transactionCntr = 0;
    
    
    module.exports.get_processed_data = function(text, res) {
        var timestamp = new Date().getTime();
        var transactionId = transactionCntr++;
        console.log('sending data to client');
    
        function onResponse(data) {
            // for concurrency reasons, make sure this is the right
            // response.  The server must return the same
            // transactionId that it was sent
            if (data.transactionId === transactionId) {
                console.log('\tserverResponse' event trigged, data:');
                res.send(data);
                socket.off('serverResponse', onResponse);
            }
        }
    
        socket.on('serverResponse', onResponse);
    
        // send data and transactionId
        socket.emit('myEvent', [timestamp ,text, transactionId], function (data) {
            console.log('\tSending query ... waiting for ACK');
            console.log(data); 
        });
    }
    

    您当前的结构存在一个问题,即它似乎没有办法确定哪个响应与哪个请求有关,并且可能存在并发问题。每次只使用单独的http请求会更简单,因为响应将与适当的请求唯一配对。

    使用socket.io连接,您可以在请求/响应中使用某种ID,这样您就可以知道哪个响应属于哪个请求。我已经展示了它在快递服务器中的工作原理。从Java服务器,您必须在对Express服务器的响应中回显transactionId,以便它可以跟踪响应哪个请求。

    正如您的代码所示,如​​果'/api/getProcessedData'路由的多个请求同时发生,则来自不同请求的响应很容易混淆。这是你做事的方式的架构问题。

    我不是Java专家,但它看起来像这一行:

    Thread.sleep(60000*3);
    

    将使您的线程休眠180,000毫秒(3分钟),然后在您的代码调用server.stop()之后。因此,您的Java服务器会在3分钟后自行关闭。

    因此,您只能在启动后的前3分钟内连接到Java服务器。

    这里的逻辑问题是你为什么要停止服务器?