简体   繁体   English

使用Spring Integration将消息发送到套接字端口并接收响应

[英]Sending messages to a socket port and receiving response with Spring Integration

Current Situation 现在的情况

  • On the linux server several jars are running with sockets - listening and responding with string messages 在linux服务器上,有几个jar正在通过套接字运行-监听和响应字符串消息
  • A new war running in an wildfly application server is delegating requests to these sockets 在Wildfly应用程序服务器中运行的新战争将请求委托给这些套接字
  • The WAR is using spring and especially spring integration with annotations WAR正在使用spring,尤其是spring与注释集成

I have a configuration class holding the services @Configuration / @EnableIntegration /@IntegrationComponentScan 我有一个配置类,其中包含服务@Configuration / @EnableIntegration / @ IntegrationComponentScan

I've created a messaging gateway 我创建了一个消息传递网关

@MessagingGateway(defaultRequestChannel = "testGateway")
public interface TestGateway{
    public Future<String> sendMessage(String in);
}

The application should sending requests and receiving it as a client. 应用程序应该发送请求并将其作为客户端接收。 I've created a null event handler since the application should just send the string and wait for the answer 我创建了一个空事件处理程序,因为应用程序应该只发送字符串并等待答案

@Bean
public MessageChannel testChannel() {
    return new DirectChannel();
}

@Bean
@ServiceActivator(inputChannel = "testGateway")
public MessageHandler testGate() {
    final TcpOutboundGateway gate = new TcpOutboundGateway();
    gate.setConnectionFactory(connectionFactory());
    gate.setReplyChannel(docServerChannel());
    return gate;
}

@Bean
public AbstractClientConnectionFactory connectionFactory() {
    final AbstractClientConnectionFactory connectionFactory = new TcpNetClientConnectionFactory("localhost", 5959);
    connectionFactory.setSoTimeout(300000);
    connectionFactory.setApplicationEventPublisher(new NullEventPublisher());
    connectionFactory.setSerializer(new DefaultSerializer());
    connectionFactory.setDeserializer(new DefaultDeserializer());
    return connectionFactory;
}

The messages should be converted to Strings when receiving data and to bytes when sending them 消息在接收数据时应转换为字符串,在发送消息时应转换为字节

@MessageEndpoint
public static class TestMessage {

    @Transformer(inputChannel = "testChannel")
    public String convert(final byte[] bytes) {
        return new String(bytes);
    }

    @Transformer(inputChannel = "testGateway")
    public String convertResult(final byte[] bytes) {
        return new String(bytes);
    }

}

The application is deployed but the response is always timing out. 应用程序已部署,但响应始终超时。 The socket is running. 套接字正在运行。 I just want a simple direct bidirectional connection: WAR <-> JAR. 我只想要一个简单的直接双向连接:WAR <-> JAR。

Can someone help or give me a hint? 有人可以帮忙还是可以给我提示吗?

------UPDATE-1---------- ------ UPDATE-1 ----------

The socket is receiving the message but then response cannot be read beacuse the socket is closed after sending the message. 套接字正在接收消息,但是由于发送消息后套接字已关闭,因此无法读取响应。

------UPDATE-2---------- ------ UPDATE-2 ----------

  • It was a typo. 这是一个错字。 The system is return a MessageHandler 系统正在返回一个MessageHandler
  • I've added the factory as a spring managed bean 我已经将工厂添加为春季托管的bean
  • I've added '\\r\\n' to the legacy code 我已经在旧版代码中添加了“ \\ r \\ n”
  • The application is still complaining "Timed out waiting for response" 该应用程序仍在抱怨“超时等待响应”

The legacy server is opening up a server socket and sending messages to socket 旧版服务器正在打开服务器套接字并将消息发送到套接字

final OutputStream os = serverSocket.getOutputStream();
final PrintWriter pw = new PrintWriter(os, true);
final BufferedReader br = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
final String incoming = br.readLine();
final String response= "ok\r\n";
pw.println(response);
pw.flush();
Thread.sleep(5000);
pw.close();
serverSocket.close();

------UPDATE-3---------- ------ UPDATE-3 ----------

The TcpOutboundGateway from Spring is getting no response Spring的TcpOutboundGateway没有响应

        connection.send(requestMessage);
        Message<?> replyMessage = reply.getReply();
        if (replyMessage == null) {

The connection factory needs to be a @Bean so that Spring can manage it. 连接工厂必须是@Bean以便Spring可以对其进行管理。

public TcpInboundGateway testGate() {
    final AbstractClientConnectionFactory connectionFactory = new TcpNetClientConnectionFactory("localhost", 5959); // already running socket
    connectionFactory.setApplicationEventPublisher(new NullEventPublisher());
    final TcpOutboundGateway gate = new TcpOutboundGateway();
    gate.setConnectionFactory(connectionFactory);
    gate.setOutputChannelName("testChannel");
    return gate;
}

This won't compile; 这不会编译; the return type doesn't match what you are returning. 返回类型与您返回的内容不匹配。

Assuming this is just a typo here and the bean is in fact an outbound gateway, with this configuration, the reply must be terminated with \\r\\n (CRLF). 假设这里只是一个错字,并且实际上Bean是出站网关,使用此配置,必须用\\r\\n (CRLF)终止回复。

See the documentation ; 参见文档 ; scroll down to... 向下滚动到...

TCP is a streaming protocol; TCP是一种流协议。 this means that some structure has to be provided to data transported over TCP, so the receiver can demarcate the data into discrete messages. 这意味着必须为通过TCP传输的数据提供某种结构,以便接收器可以将数据划分为离散的消息。 Connection factories are configured to use (de)serializers to convert between the message payload and the bits that are sent over TCP. 连接工厂配置为使用(反)序列化器在消息有效负载和通过TCP发送的位之间进行转换。 This is accomplished by providing a deserializer and serializer for inbound and outbound messages respectively. 通过分别为入站和出站消息提供解串器和序列化器,可以实现此目的。 A number of standard (de)serializers are provided. 提供了许多标准(反)序列化器。

...and read about the standard deserializers. ...并阅读有关标准解串器的信息。 With your configuration, the standard deserializer is waiting for the terminaing \\r\\n (CRLF). 使用您的配置,标准解串器正在等待终止\\r\\n (CRLF)。

What does the server code do? 服务器代码做什么?

EDIT 编辑

@SpringBootApplication
public class So49046888Application {

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext ctx = SpringApplication.run(So49046888Application.class, args);
        String reply = ctx.getBean(TestGateway.class).sendMessage("foo").get();
        System.out.println(reply);
        Thread.sleep(10_000);
        ctx.close();
    }

    @Bean
    public ServerSocket serverSocket() throws IOException {
        return ServerSocketFactory.getDefault().createServerSocket(5959);
    }

    @Bean
    public ApplicationRunner runner(TaskExecutor exec) {
        return args -> {
            exec.execute(() -> {
                try {
                    while (true) {
                        Socket socket = serverSocket().accept();
                        final OutputStream os = socket.getOutputStream();
                        final PrintWriter pw = new PrintWriter(os, true);
                        final BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                        final String incoming = br.readLine();
                        System.out.println(incoming);
                        final String response= "ok\r\n";
                        pw.print(response);
                        pw.flush();
                        Thread.sleep(5000);
                        pw.close();
                        socket.close();
                    }
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            });
        };
    }

    @Bean
    public TaskExecutor exec() {
        return new ThreadPoolTaskExecutor();
    }

    @Bean
    @ServiceActivator(inputChannel = "testGateway")
    public MessageHandler testGate() {
        final TcpOutboundGateway gate = new TcpOutboundGateway();
        gate.setConnectionFactory(connectionFactory());
        gate.setReplyChannelName("toString");
        gate.setRemoteTimeout(60_000);
        return gate;
    }

    @Transformer(inputChannel = "toString")
    public String transform(byte[] bytes) {
        return new String(bytes);
    }

    @Bean
    public AbstractClientConnectionFactory connectionFactory() {
        final AbstractClientConnectionFactory connectionFactory = new TcpNetClientConnectionFactory("localhost", 5959);
        connectionFactory.setSoTimeout(300000);
        return connectionFactory;
    }

    @MessagingGateway(defaultRequestChannel = "testGateway")
    public static interface TestGateway {
        public Future<String> sendMessage(String in);
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM