【问题标题】:Is it possible use the Socket API from Java with a Spring-Boot web application?是否可以将 Java 的 Socket API 与 Spring-Boot Web 应用程序一起使用?
【发布时间】:2020-01-22 20:00:36
【问题描述】:

当我用谷歌搜索这个主题时,我发现的只是与 websockets 相关的东西。我想使用 Java 的 Socket API 在客户端和服务器之间发送和接收数据(服务器始终是 spring-boot Web 应用程序,客户端可以是也可以不是)。

当我执行java -jar server.war 时,我将服务器应用程序设计为在端口 4444 上运行,而当我执行 java -jar client.war 时,我设计客户端在端口 3333 上运行。服务器应该监听 5555 端口。

到目前为止,我所拥有的服务器:

控制器

@Controller
public class Home {
  ServerSocket s;

  Integer PORT = 5555;

  @RequestMapping("/")
  public String index() {
    return "index";
  }

  @RequestMapping("/open_connection")
  @ResponseBody
  public void open_connection() throws Exception {
    s = new ServerSocket(PORT);
  }

  @RequestMapping("/close_connection")
  @ResponseBody
  public void close_connection() throws Exception {
    s.close();
  }

  @RequestMapping("/listen_connection")
  @ResponseBody
  public String listen_connection() throws Exception {
    Socket socket = s.accept();
    DataInputStream dis=new DataInputStream(socket.getInputStream());
    String  str = (String) dis.readUTF();
    socket.close();
    return str;
  }
}

通过这段 javascript 代码调用方法:

var isOpen = false;

function open_connection(e) {
  var url = e.dataset.url;
  var oReq = new XMLHttpRequest();

  oReq.onload = function(ev) {
    var responseText = oReq.response;
    isOpen = true;
    document.querySelector('.btn-success').style.display = 'none';
    document.querySelector('.btn-danger').style.display = 'block';
  }

  oReq.open("GET", url);
  oReq.send();
}

function close_connection(e) {
  var url = e.dataset.url;
  var oReq = new XMLHttpRequest();

  oReq.onload = function(ev) {
    var responseText = oReq.response;
    isOpen = false;
    document.querySelector('.btn-danger').style.display = 'none';
    document.querySelector('.btn-success').style.display = 'block';
  }

  oReq.open("GET", url);
  oReq.send();
}

function listen_connection(e) {
  var url = document.querySelector('.container').dataset.url;

  if(isOpen) {
    while(true) {
      var oReq = new XMLHttpRequest();

      oReq.onload = function(ev) {
        var responseText = oReq.response;
        if(responseText === 'quit') {
          break;
        } else {
          var item = document.createElement('li');
          item.setAttribute('class', 'list-group-item');
          item.innerText = responseText
          document.querySelector('.list-group').addChild(item);
        }
      }

      oReq.open("GET", url);
      oReq.send();
    }
  }
}

当我从 html 视图调用此方法时,打开连接和关闭连接不会给我任何错误。我不知道如何开始监听连接以接收来自客户端的数据(我尝试从 open_connection 调用 listen_connection,但是这样我在调用 open 连接方法时会导致浏览器崩溃)。

在客户端,我有这个:

控制器

@Controller
public class Home {
  String HOST = "localhost";

  Integer PORT = 5555;

  @RequestMapping("/")
  public String index() {
    return "index";
  }

  @RequestMapping(value="/send_data", method=RequestMethod.POST)
  @ResponseBody
  public void send_data(@RequestParam("data") String data) throws Exception {
    Socket socket = new Socket(HOST, PORT);
    DataOutputStream dout = new DataOutputStream(socket.getOutputStream());
    dout.writeUTF(data);
    dout.flush();
    dout.close();
    socket.close();
  }
}

这个方法是通过这个javascript代码调用的:

function send(e) {
  var url = e.dataset.url;
  var oReq = new XMLHttpRequest();

  oReq.onload = function(ev) {
    var responseText = oReq.response;
    document.querySelector('.form-control').value = '';

  }

  oReq.open("POST", url);
  var formData = new FormData();
  formData.append("data", document.querySelector('.form-control').value)
  oReq.send(formData);
}

这里的问题是,当我点击调用这个方法时,我得到了一个错误 403 (forbidden)。

谁能告诉我我在这里做错了什么?

【问题讨论】:

  • 为什么?如果您所做的只是发送一个字符串,那么三个 POST 和一个套接字是一种非常复杂的方式来完成它。
  • 以后我不会用它来发送单个字符串,这只是一个开始。

标签: java spring spring-boot sockets serversocket


【解决方案1】:

转到将使用 SpringIntegration ,可以在 here 找到 TCP 和 UDP 文档。但总而言之,您可以使用集成流将消息/通信从一种形式转换为另一种形式,并实现一堆标准的企业集成模式。

【讨论】:

    【解决方案2】:

    Spring boot 应用程序毕竟只是一个 java 应用程序,通常会公开一些 Http 接口,但并非总是如此(想想一些从消息系统等获取输入的应用程序)。

    所以从技术上讲,没有什么可以阻止您使用普通套接字。

    所以你可以创建(可能是 Singleton 范围,这样在应用程序上下文中只有一个这样的 bean)。这个 bean 在初始化期间会打开一个服务器套接字并接受连接。

    由于 spring boot 管理应用程序的生命周期,您甚至可以在应用程序宕机时优雅地关闭服务器套接字。

    只要服务器套接字端口可用并且您自己实现通信协议,所有这些都将起作用。这是基础。请记住,这种通信方式非常低级,因此您不会进行监控,必须处理线程池(如果并行运行的服务器上有太多请求怎么办)等等。

    Spring Integration 或 Camel 之类的框架可能会以一种您能够在生产中实际使用的方式将其封装起来,但我认为这超出了问题的范围。

    【讨论】:

      猜你喜欢
      • 2017-08-31
      • 1970-01-01
      • 2015-01-28
      • 2018-08-28
      • 2021-06-17
      • 1970-01-01
      • 1970-01-01
      • 2022-11-23
      • 1970-01-01
      相关资源
      最近更新 更多