如何在 spring boot 中创建一个有效的 TCP Server 套接字以及如何处理传入的消息? [英] How to create a working TCP Server socket in spring boot and how to handle the incoming message?

查看:122
本文介绍了如何在 spring boot 中创建一个有效的 TCP Server 套接字以及如何处理传入的消息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试在现有的 Spring Boot 应用程序中实现一个带有 spring 集成的 TCP 服务器套接字,但我面临一个问题,这个问题让我发疯......客户端正在向服务器发送消息(字节数组)并超时.就是这样.我没有收到来自服务器的任何异常.我似乎提供了错误的端口或其他东西,但在检查端口后,我确定它是正确的.

这是我基于注解的配置类:

import home.brew.server.socket.ServerSocketHandler;导入 lombok.extern.log4j.Log4j2;导入 org.springframework.beans.factory.annotation.Value;导入 org.springframework.context.annotation.Bean;导入 org.springframework.context.annotation.Configuration;导入 org.springframework.integration.config.EnableIntegration;导入 org.springframework.integration.dsl.IntegrationFlow;导入 org.springframework.integration.dsl.IntegrationFlows;导入 org.springframework.integration.ip.dsl.Tcp;@Log4j2@配置@启用集成公共类 TcpServerSocketConfiguration {@Value("${socket.port}")私有 int serverSocketPort;@豆角,扁豆公共集成流服务器(ServerSocketHandler serverSocketHandler){TcpServerConnectionFactorySpec connectionFactory =Tcp.netServer(socketPort).deserializer(new CustomSerializerDeserializer()).serializer(new CustomSerializerDeserializer()).soTcpNoDelay(true);TcpInboundGatewaySpec inboundGateway =Tcp.inboundGateway(connectionFactory);返回集成流.from(入站网关).handle(serverSocketHandler::handleMessage).得到();}@豆角,扁豆公共 ServerSocketHandler serverSocketHandler() {返回新的 ServerSocketHandler();}}

我想让接收功能在我尝试发送答案之前工作,所以这就是为什么要进行最少配置.

下面的类应该处理从服务器套接字接收到的消息

import lombok.extern.log4j.Log4j2;导入 org.springframework.messaging.Message;导入 org.springframework.messaging.MessageHeaders;导入 org.springframework.messaging.MessagingException;@Log4j2公共类 ServerSocketHandler {public String handleMessage(Message message, MessageHeaders messageHeaders) {log.info(message.getPayload());//TODO 在这里实现一些有用的东西来处理传入的消息...返回 message.getPayload().toString();}}

上面的处理程序方法甚至一次都没有被调用!我在谷歌上搜索了一些示例实现或教程,但我没有找到任何对我有用的东西.我已经尝试过这些网站的实现:

  1. 所以如果有人能帮我解决这个问题,我将不胜感激,如果您需要更多信息,请告诉我.

    提前致谢!

    解决方案

    您如何与此服务器通信?默认情况下,连接工厂配置为要求输入由 CRLF(例如 Telnet)终止.如果您的客户端使用其他东西来指示消息结束,则您必须配置不同的解串器.

    另外,你的方法签名不正确;应该是:

    public String handleMessage(byte[] message, MessageHeaders messageHeaders) {String string = new String(message);System.out.println(string);返回 string.toUpperCase();}

    这对我来说很好用 Telnet:

    $ telnet 本地主机 1234正在尝试:: 1 ...连接到本地主机.转义字符是^]".富食品级^]远程登录>放弃连接关闭.

    这是一个仅适用于 LF 的版本(例如 netcat):

    @Bean公共集成流服务器(ServerSocketHandler serverSocketHandler){返回 IntegrationFlows.from(Tcp.inboundGateway(Tcp.netServer(1234).deserializer(TcpCodecs.lf()).serializer(TcpCodecs.lf()))).handle(serverSocketHandler::handleMessage).得到();}

    $ nc 本地主机 1234富食品级^C

    I have tried to implement a TCP server socket with spring integration in an allready existing spring boot application, but I am facing a problem and this problem drives me crazy... The client is sending a message (a byte array) to the server and timesout. That's it. I am not receiving any exceptions from the server. It seems I have provided the wrong port or somthing but after checking the port, I am sure it is the right one.

    This is my annotation based configuration class:

    import home.brew.server.socket.ServerSocketHandler;
    import lombok.extern.log4j.Log4j2;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.integration.config.EnableIntegration;
    import org.springframework.integration.dsl.IntegrationFlow;
    import org.springframework.integration.dsl.IntegrationFlows;
    import org.springframework.integration.ip.dsl.Tcp;
    
    @Log4j2
    @Configuration
    @EnableIntegration
    public class TcpServerSocketConfiguration {
    
        @Value("${socket.port}")
        private int serverSocketPort;
    
        @Bean
        public IntegrationFlow server(ServerSocketHandler serverSocketHandler) {
            TcpServerConnectionFactorySpec connectionFactory = 
                Tcp.netServer(socketPort) 
                  .deserializer(new CustomSerializerDeserializer())
                  .serializer(new CustomSerializerDeserializer())
                  .soTcpNoDelay(true);
    
            TcpInboundGatewaySpec inboundGateway = 
               Tcp.inboundGateway(connectionFactory);
    
            return IntegrationFlows
             .from(inboundGateway)
             .handle(serverSocketHandler::handleMessage)
             .get();
        }
    
        @Bean
        public ServerSocketHandler serverSocketHandler() {
            return new ServerSocketHandler();
        }
    }
    

    I wanted to make the receive functionality work before I try to send an answer, so that's why have a minimal configuration.

    And the following class should process the received message from the server socket

    import lombok.extern.log4j.Log4j2;
    import org.springframework.messaging.Message;
    import org.springframework.messaging.MessageHeaders;
    import org.springframework.messaging.MessagingException;
    
    @Log4j2
    public class ServerSocketHandler {
    
        public String handleMessage(Message<?> message, MessageHeaders messageHeaders) {
            log.info(message.getPayload());
            // TODO implement something useful to process the incoming message here...
            return message.getPayload().toString();
        } 
    }
    

    The handler method from above was never invoked even once! I have googled for some example implementations or tutorials but I haven't found anyhing what worked for me. I allready tried the implementations of these sites:

    1. https://vispud.blogspot.com/2019/03/how-to-implement-simple-echo-socket.html
    2. https://docs.spring.io/spring-integration/docs/current/reference/html/ip.html#note-nio
    3. Spring Boot TCP Client

    and a bunch of sites more... but nothing helped me :-(

    UPDATE 1

    I have implemented a custom serializer/deserializer:

    import lombok.Data;
    import lombok.extern.log4j.Log4j2;
    import org.springframework.core.serializer.Deserializer;
    import org.springframework.core.serializer.Serializer;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    
    @Log4j2
    @Data
    public class CustomSerializerDeserializer implements Serializer<byte[]>, 
    Deserializer<byte[]> {
    
    
    @Override
    public byte[] deserialize(InputStream inputStream) throws IOException {
        return inputStream.readAllBytes();
    }
    
    @Override
    public void serialize(byte[] object, OutputStream outputStream) throws IOException {
        outputStream.write(object);
    }
    }
    

    After the client have sent a message, the custom serializer is invoked but the content ist always empty. I have no idea why.... The serializer needs a lot of time to read all bytes from the stream and in the end it is empty. The procedure is repeating all the time, so I think I have build an infinty loop by accident...

    UPDATE 2

    I have captured the communication between Client and server socket: It looks like I am stuck in the handshake and therefore there is no payload...

    So if anybody could help me out with this, I would be very thankful and if you need some more information, just let me know.

    Thanks in advance!

    解决方案

    How are you communicating with this server? By default the connection factory is configured to require the input to be terminated by CRLF (e.g. Telnet). You have to configure a different deserializer if your client uses something else to indicate a message end.

    Also, your method signature is incorrect; it should be:

    public String handleMessage(byte[] message, MessageHeaders messageHeaders) {
        String string = new String(message);
        System.out.println(string);
        return string.toUpperCase();
    }
    

    This works fine for me with Telnet:

    $ telnet localhost 1234
    Trying ::1...
    Connected to localhost.
    Escape character is '^]'.
    foo
    FOO
    ^]
    telnet> quit
    Connection closed.
    

    And here is a version that works with just LF (e.g. netcat):

    @Bean
    public IntegrationFlow server(ServerSocketHandler serverSocketHandler) {
        return IntegrationFlows.from(Tcp.inboundGateway(
                Tcp.netServer(1234)
                    .deserializer(TcpCodecs.lf())
                    .serializer(TcpCodecs.lf())))
                .handle(serverSocketHandler::handleMessage)
                .get();
    }
    

    $ nc localhost 1234
    foo
    FOO
    ^C
    

    这篇关于如何在 spring boot 中创建一个有效的 TCP Server 套接字以及如何处理传入的消息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆