How to configure Spring to take a data from socket bytestream? - java

I'm trying to configure Spring on the server side to open a socket, listen for connections and take the incoming stream (converting to String).
But I cannot find any working examples on how to just create such an incoming tcp connection. This is what I have (taken from an incomplete example):
<int-ip:tcp-connection-factory id="cfServer"
type="server"
port="8080"
using-nio="true"
single-use="true" />
<int-ip:tcp-inbound-channel-adapter id="inboundServer"
channel="loop"
connection-factory="server"/>
<int:channel id="loop"/>
Well, but how do I continue? How can I acutally bind these adapters to a backing class? And what do these classes have to look like?

Subscribe something to the loop channel, e.g. a <service-activator/>.
See the tcp-client-server sample

Related

spring integration tcp-out-bound exception

We are using Spring integration 4.1.3.
Implemented the client using tcp-outbound-gateway.
A tcp rset packet was received from the server during the request and an exception occurred.
What is the reason?
Thank you.
// interface
public interface TcpSendGateway {
public byte[] send(String text);
}
// send
byte[] response = sendGateway.send(request);
<int:gateway id="gw"
service-interface="com.mainpay.service.TcpSendGateway"
default-request-channel="input"
default-reply-channel="reply"/>
<int-tcp:tcp-connection-factory id="client"
type="client"
host="#{prop['app.cultureland.host']}"
port="#{prop['app.cultureland.port']}"
so-timeout="10000"
single-use="false"
so-keep-alive="true"
/>
<int:channel id="input" />
<int-tcp:tcp-outbound-gateway id="outGateway"
request-channel="input"
reply-channel="reply"
connection-factory="client"
request-timeout="10000"
reply-timeout="10000"
/>
<int:channel id="reply" datatype="java.lang.String" />
ERROR LOG
▶ 17.09.29 17:07:37 [pool-2-thread-2] ERROR o.s.i.i.t.c.TcpNetConnection - Read exception 211.59.10.133:7611:51503:d2ec0199-fd15-49c0-bd99-0d864eb2145b SocketException:Connection reset
▶ 17.09.29 17:07:39 [http-nio-19900-exec-5] ERROR o.s.i.ip.tcp.TcpOutboundGateway - Tcp Gateway exception
org.springframework.messaging.MessagingException: Exception while awaiting reply; nested exception is java.net.SocketException: Connection reset
at org.springframework.integration.ip.tcp.TcpOutboundGateway$AsyncReply.getReply(TcpOutboundGateway.java:288)
wireshark log
enter image description here
I think you should be sure that your client and server are agreed with the (de)serialization protocol. See Reference Manual for more info:
TCP is a streaming protocol; this means that some structure has to be provided to data transported over TCP, so the receiver can demarcate the data into discrete messages. Connection factories are configured to use (de)serializers to convert between the message payload and the bits that are sent over TCP.
The default one is the ByteArrayCrLfSerializer which deals with the \r\n message delimiter.
So, your client may receive the package but since it doesn't meet the proper delimiter it fails waiting for the reply.
java.net.SocketException: Connection reset
Means the server forced the socket closed (RST) for some reason. You need to look at the server logs.
Perhaps it's not expecting the default wire format (text terminated by CRLF - 0x0d0a).

Netty4 - TCP Server - basic testing using Camel

I am a beginner learning Camel and trying to run netty4 on camel using apache blueprint.
I am creating a TCP server using netty :
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="timerToLog">
<from uri="netty4:tcp://localhost:5150"/>
<log message="The message contains ${body}"/>
<to uri="mock:result"/>
</route>
</camelContext>
Everything works fine when I run camel using mvn:
[ Blueprint Extender: 1] TCPNettyServerBootstrapFactory INFO ServerBootstrap binding to localhost:5150
[ Blueprint Extender: 1] NettyConsumer INFO Netty consumer bound to: localhost:5150
[ Blueprint Extender: 1] BlueprintCamelContext INFO Route: timerToLog started and consuming from: Endpoint[tcp://localhost:5150]
I connect to the tcp server using and send data using Hercules ( even tried windows telnet ) and as soon as I send a "Hello" ascii text, the connection gets closed with the following error:
[d #0 - NettyEventExecutorGroup] NettyConsumer WARN Closing channel as an exception was thrown from Netty. Caused by: [io.netty.hand
ler.codec.TooLongFrameException - Adjusted frame length exceeds 1048576: 1212501072 - discarded]
io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 1048576: 1212501072 - discarded
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.fail(LengthFieldBasedFrameDecoder.java:499)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.failIfNecessary(LengthFieldBasedFrameDecoder.java:477)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:403) ...
I am only sending a "Hello" over the socket and still it says frame length exceeded.. !
I know am missing something very basic. Please bear with me and help :)
According to the Camel Netty4 Component documentation if the textline parameter of the the url is NULL then it installs and uses a default encoder/decoder. This is the equivalent of using textline=false which is the default behavior.
In your example you have this for the netty4 component:
<from uri="netty4:tcp://localhost:5150"/>
Thus you are using the default encoder/decoders which probably is not a text line based encoder/decoder. YOu can probably find which is the default encoder in the documentation but I think you probably can learn more than me by finding that information.
Remember that Netty uses the concept of encoders and decoders to send/receive data to and from clients and servers. These decoders define how Netty should read the raw data from the socket. If you are unfamiliar with this there is tons of documentation on Netty available.
Lets look at how to implement a simple text line based protocol encoder/decoder like you want to achieve.
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="timerToLog">
<from uri="netty4:tcp://localhost:5150?textline=true"/>
<log message="The message contains ${body}"/>
<to uri="mock:result"/>
</route>
All you were missing was the encoder bit.

what is equivalent of <tcp-outbound-channel-adapter> in java config?

I have the spring integration XML config with following bean
<int-ip:tcp-outbound-channel-adapter id="outboundClient"
channel="input"
connection-factory="client"/>
I thought the equivalent in java config would be
#ServiceActivator(inputChannel = "input", requiresReply = "true")
public TcpSendingMessageHandler outboundClient() {
TcpSendingMessageHandler tcpSendingMessageHandler = new TcpSendingMessageHandler();
tcpSendingMessageHandler.setConnectionFactory(clientConnectionFactory());
tcpSendingMessageHandler.setRetryInterval(10000);
tcpSendingMessageHandler.setClientMode(true);
return tcpSendingMessageHandler;
}
However, in the log, I see
TcpListener exiting - no listener and not single use
and I can't receive the reply from server.
Any help is appreciated
The TcpSendingMessageHandler is for one-way usage - just for sending messages to the TCP socket.
So, your config looks good and seems for me it should work.
TcpListener exiting - no listener and not single use
Is just DEBUG message from the TcpNetConnection which indicates that your component is one-way.
Therefore it is normal that you can't receive a reply from the server. Because you only send message to there.
To have request/reply scenarios consider to use TcpOutboundGateway.

Spring FTP Inbound vs Outbound Channel Adaptor

What is the difference between Inbound Channel Adaptor and Outbound Channel Adaptor in Spring Integration FTP. Which one I should I use and when?
I read from documentation that outbound can send any type of file(like byte[], String, java.io.File) but Inbound is restricted for File type only. Is that only difference or anything else?
I suggest you to read a theory first of all.
Any Inbound adapter is intended to get data from external system. Outbound - to put data. E.g. simple case: JDBC Inbound performs a SELECT from DB, Outbound - INSERT.
In case of FTP: the first one to read files from FTP, the last - to write them.

Listening to a multicast UDP address

I wrote an application in MATLAB to open a UDP socket and listen for incoming datagrams. Basically, something like this:
u = udp(rHost, rPort, 'LocalHost', lHost, 'LocalPort', lPort);
u.DatagramAvailableFcn = #(o,e) operateOnData(o,e);
fopen(u);
This works wonderfully when I'm listening to something in a unicast fashion. But I would now like to be able to listen to multicast traffic. Apparently, this isn't possible in MATLAB.
The workaround is, per above link,
As a workaround to connect to a UDP multicast, you can do the following:
Use a Java multicast socket to access it directly from MATLAB. For more information, see javadoc or tutorials for the "core java.net" classes from Sun, specifically "java.net.MulticastSocket". This could be found at:
http://java.sun.com/j2se/1.4.2/docs/api/java/net/MulticastSocket.html
I have no background in Java so this is a struggle for me. I've only been able to run the following to instantiate a MulticastSocket object:
>> ms = javaObject('java.net.MulticastSocket');
I looked around and found that I also need a java.net.Datagram object to actually contain the incoming stream.
How do I use the MulticastSocket and Datagram objects within the context of MATLAB? I'm trying to replicate the functionality of u.DatagramAvailableFcn, i.e., fire a callback to operate on the contents of the datagram once I receive one.
EDIT: Looks like this is how I want to go about this in terms of the Java, but now it's getting this back into MATLAB-land...
I successfully subscribed and received a packet from a multicast stream, by the following:
socket = java.net.MultiSocket(streamPort);
socket.joinGroup(java.net.InetAddress.getByName(streamIP));
socket.setReuseAddress(1);
packet = java.net.DatagramPacket(zeros(1, intmax('uint16'), 'int8'), intmax('uint16'));
socket.receive(packet);
socket.leaveGroup(InetAddress.getByName(streamIP));
socket.close;
msg = packet.getData;
msg = msg(1:packet.getLength);
This was essentially lifted from judp availble on the MathWorks File Exchange.
I am still looking for a way to get some equivalent of a DatagramReceivedFcn - right now it looks like the socket.receive call is blocking until it times out. I can use timer objects to fire the "callback" on a regular basis but that's of course not the same as having a DatagramReceivedFcn.

Categories