5
votes

I wonder if it is possible to create a UDP server with spring-integration framework that is able to accept requests and return responses.

For TCP there are TCP gateways which allow request/response processing but I don't see similar thing for UDP.

It is easy to setup UDP listener and receive packets but then I don't see how to return a response as I can only route it to a predefined output channel.

Also I don't see sender's IP and port as the transformer doesn't receive the DatagramPacket object but only the data.

Here is my configuration:

<int:channel id="ChannelIn" />

<ip:udp-inbound-channel-adapter id="ChannelReceiver"
    channel="ChannelIn"
    port="5555"
    multicast="false"
    check-length="false" 
    pool-size="10"
    />

<int:transformer
    ref="datagramToPacketTransformer"
    input-channel="ChannelIn"
    output-channel="ChannelSA" 
    method="toPacket"/>

<int:channel id="ChannelSA" />

<int:service-activator id="ChannelActivator" 
    input-channel="ChannelSA"
    ref="PacketHandler"
    method="process"
/>
3

3 Answers

2
votes

I have found n way to deal with UDP. Below is my configuration

<int-ip:udp-inbound-channel-adapter id="ChannelReceiver"
                                    channel="serverBytes2StringChannel"
                                    port="9000"
                                    multicast="false"
                                    check-length="false" 
                                    pool-size="10"
                                    lookup-host="false"
/>

<int:transformer id="serverBytes2String"
                 input-channel="serverBytes2StringChannel"
                 output-channel="udpSA" 
                 expression="new String(payload)"

/>

<int:service-activator input-channel="udpSA" 
                       ref="deviceService" 
                       method="udpMessage"/>

And deviceService bean has this code:

 public Message udpMessage(Message message) {
        String response = "KO";
        try {
            response = process(message);
        } catch (Throwable th) {
            //do something
        }
        Message msg = MessageBuilder.withPayload(response.getBytes()).copyHeaders(message.getHeaders()).build();
        sendReply(msg);
        return null;
    }
    private void sendReply(Message message) {
        try {
            int port = (Integer) message.getHeaders().get("ip_port");
            String ip = (String) message.getHeaders().get("ip_address");
            InetAddress IPAddress = InetAddress.getByName(ip);

            byte[] sentence = (byte[]) message.getPayload();
            byte[] sendData = new byte[sentence.length];
            byte[] receiveData = new byte[1024];
            sendData = sentence;
            DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port);
            DatagramSocket clientSocket = new DatagramSocket();
            clientSocket.send(sendPacket);
            clientSocket.close();
        } catch (Exception ex) {
            throw new RuntimeException("KO");
        }
    }

And this is working perfectly on my personal computer however when I deploy this code on Amazon AWS it is not working. I found that even though program is listening on UDP 9000 port, but no communication received at server side. This could be an issue with AWS setup though I have allowed all UDP port for that AWS instance.

Any hints on how to make this work on Amazon AWS?

1
votes

I opened a new feature JIRA nearly two years ago

https://jira.springsource.org/browse/INT-1809

but it received no votes, or watchers, so I closed it.

Feel free to add a comment to it and we can re-open it.

The sender's ip is in the message header, but not his port...

            message = MessageBuilder.withPayload(payload)
                    .setHeader(IpHeaders.HOSTNAME, hostName)
                    .setHeader(IpHeaders.IP_ADDRESS, hostAddress)
                    .build();

If you want to open a new JIRA for that, it's a small enough change to get into the 2.2. release that will come out shortly (but the gateways will not make 2.2).

https://jira.springsource.org/browse/INT

-1
votes

Thank you, Gary!

I noticed that remote IP address is in the headers but the remote port isn't so I've made some changes to add it.

I've extended UnicastReceivingChannelAdapter to override asyncSendMessage where Message is constructed. I had to extend DatagramPacketMessageMapper too. It would have been easier if I could just inject my own implementation of DatagramPacketMessageMapper in UnicastReceivingChannelAdapter but that's not possible.

Then in spring configuration I've removed the

<ip:udp-inbound-channel-adapter id="ChannelReceiver"...>

definition and added following

<bean id="udpInboundChannelAdapterBean" 
          class="me.spring.integration.udp.UnicastReceivingChannelAdapterExt" init-method="run">
          <constructor-arg name="port" value="5555" />
          <property name="poolSize" value="10"/>
          <property name="lookupHost" value="false"/>
          <property name="outputChannel" ref="ChannelIn" />

This seems to work although I had no time to fully test it yet.

My idea is to use the remote IP and port and the DatagramSocket reference from udpInboundChannelAdapterBean to create a new activation service which will just write the response to the socket.

I will open a new jira for the remote port as you suggested.