简体   繁体   中英

TCP Socket Server setup for receive/process/reply

This is a new question following up on this older question and answer (specifically the comment that says "don't comment on old answers, ask a new question"), as well as these examples in GitHub.

I know the answer and examples are minimal working "trivial examples", but I don't know enough about how "things work in Spring" (or should work) to understand how to decompose those generic, trivial examples into separate servers and clients that suit my purpose. I currently have a working Spring-Boot daemon application that is client to / calls on (without any "spring integration") a legacy daemon application over a TCP Socket connection. It's all working, running in production.

But now I am tasked with migrating the legacy daemon to Spring Boot too. So I only need to configure and set up a cached/pooled TCP connection "socket listener" on the server-side. However, the "client parts" of the existing (self contained) examples confuse me. In my case the "client side" (the existing Spring Boot daemon) is not going to change and is a separate app on a separate server, I only need to set up / configure the "server-side" of the socket connection (the "legacy-daemon freshly migrated to Spring Boot" daemon).

I've copied this example configuration (exactly) into my legacy-migration project

@EnableIntegration 
@IntegrationComponentScan 
@Configuration
public static class Config {

@Value(${some.port})
private int port;

@MessagingGateway(defaultRequestChannel="toTcp") 
public interface Gateway {

    String viaTcp(String in);

}

@Bean
@ServiceActivator(inputChannel="toTcp") 
public MessageHandler tcpOutGate(AbstractClientConnectionFactory connectionFactory) {
    TcpOutboundGateway gate = new TcpOutboundGateway();
    gate.setConnectionFactory(connectionFactory);
    gate.setOutputChannelName("resultToString");
    return gate;
}

@Bean 
public TcpInboundGateway tcpInGate(AbstractServerConnectionFactory connectionFactory)  {
    TcpInboundGateway inGate = new TcpInboundGateway();
    inGate.setConnectionFactory(connectionFactory);
    inGate.setRequestChannel(fromTcp());
    return inGate;
}

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

@MessageEndpoint
public static class Echo { 

    @Transformer(inputChannel="fromTcp", outputChannel="toEcho")
    public String convert(byte[] bytes) {
        return new String(bytes);
    }

    @ServiceActivator(inputChannel="toEcho")
    public String upCase(String in) {
        return in.toUpperCase();
    }

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

}

@Bean
public AbstractClientConnectionFactory clientCF() { 
    return new TcpNetClientConnectionFactory("localhost", this.port);
}

@Bean
public AbstractServerConnectionFactory serverCF() { 
    return new TcpNetServerConnectionFactory(this.port);
}

}

...and the project will start on 'localhost' and "listen" on port 10000. But, when I connect to the socket from another local app and send some test text, nothing returns until I shut down the socket listening app. Only after the socket listening app starts shutting down does a response (the correct 'uppercased' result) go back to the sending app.

How do I get the "listener" to return a response to the "sender" normally, without shutting down the listener's server first?

Or can someone please provide an example that ONLY shows the server-side (hopefully annotation based) setup? (Or edit the example so the server and client are clearly decoupled?)

Samples usually contain both the client and server because it's easier that way. But there is nothing special about breaking apart the client and server sides. Here's an example using the Java DSL:

@SpringBootApplication
public class So60443538Application {

    public static void main(String[] args) {
        SpringApplication.run(So60443538Application.class, args);
    }

    @Bean
    public IntegrationFlow server() {
        return IntegrationFlows.from(Tcp.inboundGateway(Tcp.netServer(1234)))
                .transform(Transformers.objectToString()) // byte[] -> String
                .<String, String>transform(p -> p.toUpperCase())
                .get();
    }

}
@SpringBootApplication
public class So604435381Application {

    private static final Logger LOG = LoggerFactory.getLogger(So604435381Application.class);

    public static void main(String[] args) {
        SpringApplication.run(So604435381Application.class, args);
    }

    @Bean
    public IntegrationFlow client() {
        return IntegrationFlows.from(Gate.class)
                .handle(Tcp.outboundGateway(Tcp.netClient("localhost", 1234)))
                .transform(Transformers.objectToString())
                .get();
    }

    @Bean
    @DependsOn("client")
    public ApplicationRunner runner(Gate gateway) {
        return args -> LOG.info(gateway.exchange("foo"));
    }

}

interface Gate {

    String exchange(String in);

}

2020-02-28 09:14:04.158 INFO 35974 --- [ main] com.example.demo.So604435381Application : FOO

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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