0

I want to achieve the following using spring-integration: having a singleton open socket that constantly receives and writes data, asyncrhon!

This means I have to open a socket that constantly reads from the single socket, dispatches each message for async processing, and return the responses over the socket also async.

How can I achieve that asynchron pattern?

Especially: how can I use Serializer/Deserializer? As far as I understood, a serializer is only invoked on a new socket connection, so in my case only once at start of the first message?

@Configuration
public class SocketConfig {
    @Bean
    public TcpConnectionFactoryFactoryBean tcpFactory(MyConverter converter) {
        TcpConnectionFactoryFactoryBean fact = new TcpConnectionFactoryFactoryBean();
        fact.setType("server");
        fact.setPort(PORT);
        fact.setUsingNio(true); //should I use true or false?
        fact.setSingleUse(false); //keep socket constantly open
        fact.setSerializer(converter);
        fact.setDeserializer(converter);
        return fact;
    }

    @Bean
    public TcpInboundGateway serverGateway(
            @Qualifier("tcpFactory") TcpConnectionFactoryFactoryBean factory,
            @Qualifier("serverChannel") MessageChannel serverChannel) throws Exception {
        TcpInboundGateway g = new TcpInboundGateway();
        g.setConnectionFactory(factory.getObject());
        g.setRequestChannel(serverChannel);
        return g;
    }

}

@MessageEndpoint
public class SocketEndpoint {

    @ServiceActivator(inputChannel = "serverChannel")
    public Object run(Object obj) {

    }
}


@Service
public class MyConverter implements Serializer<Object>, Deserializer<Object> {
    //read from socket
    @Override
    public Object deserialize(InputStream inputStream) {
    }

    //send back to socket
    @Override
    public void serialize(Object message, OutputStream outputStream) {
    }
}
membersound
  • 81,582
  • 193
  • 585
  • 1,120

1 Answers1

2

A gateway is used for individual request/response pairs.

If you need to send multiple responses for a single request, you must use collaborating channel adapters as described in the documentation.

Collaborating adapters can also be used (server-side or client-side) for totally asynchronous communication (rather than with request/reply semantics).

On the server side, care must be taken to populate the ip_connectionId header because it is used to correlate the message to a connection. Messages that originate at the inbound adapter will automatically have the header set. If you wish to construct other messages to send, you will need to set the header. The header value can be captured from an incoming message.

Community
  • 1
  • 1
Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • I want to send only one response for each request. The only thing is that the socket is kept permanently open. Means a have to constantly read messages and write messages over the socket, all async. – membersound Jun 13 '18 at 13:24
  • I was confused by "divides messages" - it implied to me that you meant each message was divided, but I now see what you mean; that should just work; the framework provides the `ByteArrayLengthHeaderSerializer` for exactly that purpose. If it's not working for you, edit the question to explain exactly what the problem is. Using NIO means you'll automatically get multi-threading. – Gary Russell Jun 13 '18 at 13:42
  • Well but how would I have to read from the `InputStream` inside the `Serializer`? Because I only have one constant open socket, would I just return inside the Serializer as soon as one message has been fully read? Or should I create an endless loop inside the Serializer that constantly reads from the `InputStream` that dispatches the messages somehow async? – membersound Jun 14 '18 at 07:56
  • 1
    You would return each message; the `deserialize()` method will be called to get the next message. See the `ByteArrayLengthHeaderSerializer` for an example. – Gary Russell Jun 14 '18 at 12:52
  • So is `deserialize()` and `serialize()` nonblocking? If so, what if I return multiple messages concurrently, by chance at the same time? Would they be written back into the socket one by one, so I wouldn't get corrupt messages inside the single-socket and they won't overlap? – membersound Jun 18 '18 at 11:45
  • 1
    No; they can block. send operations are synchronized so only one write operation can occur at a time, preventing interleaving of data. On the receive side you can't have "concurrent deserialization"; it makes no sense; the deserializer should only exit after a message is completely decoded. When NIO is true, and more data is present, the next deserialization is dispatched to another thread. When false, a single thread does all the reads and you can use an executor channel if you want to read the next message(s) while the current one is being processed. – Gary Russell Jun 18 '18 at 12:53
  • Thanks for the detailed insight and everything is more clear. I tend to accept your answer. Though I'm not sure if future readers might get confused if I do so, because in your initial response you wrote "don't use a gateway", but using a gateway here as presented in my question is probably the solution to what I wanted. – membersound Jun 18 '18 at 13:02
  • 1
    I edited it to clarify the use of gateways Vs. collaborating adapters. – Gary Russell Jun 18 '18 at 13:10