This is the place to get started with the Samples for Spring Integration's support for the the Transmission Control Protocol (TCP). The sample demonstrates a simple message flow represented by the diagram below:
Gateway (SimpleGateway) -> Channel -> TcpOutboundGateway -> <==Socket==> -> TcpInboundGateway -> Channel -> ServiceActivator (EchoService)
The EchoService class returns a response which the Inbound Gateway sends back over the socket to the Outbound Gateway and the result is returned to the client that invoked the original SimpleGateway method.
Several variations of the sample are provided:
- Client-Server Demo with explicit Transformers (Sample also provides Telnet connectivity)
- Client-Server Demo with ConversionService
- Serializer Demo
- Annotation based client-server Demo (JUnit test only)
The Client-Server Demo illustrates the use of a Gateway as an entry point into the integration flow. The message generated by the Gateway is sent over TCP by the Outbound Gateway to the Inbound Gateway. In turn the Inbound Gateway sends the message to an echo service (Class EchoService) and the echoed response comes back over TCP. The demo uses explicit Transformers to convert the byte array payloads to Strings.
You can execute this sample simply via Gradle:
$ gradlew :tcp-client-server:run
Alternatively, you can also execute the Main method in class org.springframework.integration.samples.tcpclientserver.Main. In both cases you should see the following console output:
========================================================= Welcome to the Spring Integration TCP-Client-Server Sample! For more information please visit: http://www.springintegration.org/ ========================================================= Detect open server socket...using port 5680 Waiting for server to accept connections...running. Please enter some text and press <enter>: Note: - Entering FAIL will create an exception - Entering q will quit the application --> Please also check out the other samples, that are provided as JUnit tests. --> You can also connect to the server on port '5680' using Telnet. hello echo:hello q Exiting application...bye.
The respective open server socket it dynamically selected. Alternatively, you can also customize the port by providing an additional system property at startup e.g.
$ gradlew :tcp-client-server:run -DavailableServerSocket=7777
Connect via Telnet
The configured Inbound Gateway processes CRLF (Carriage Return + Line Feed) delimited messages using the default ByteArrayCrLfSerializer. This means that the Inbound Gateway works works fine as a very simple Telnet server! Just start up the sample and connect to the used port:
$ telnet localhost <your_port>
Each time you hit enter you should see your input echoed back, preceded by 'echo:'
$ telnet localhost 11111 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello world! echo:Hello world! Test echo:Test ^] telnet> quit Connection closed.
In order to quit the Telnet session, press
Control+](Mac) followed by
The test case also demonstrates error handling on an Inbound Gateway using direct channels. If the payload is 'FAIL', the EchoService throws an exception. The Gateway is configured with an error-channel attribute. Messages sent to that channel are consumed by a Transformer that concatenates the inbound message payload with the message text from the thrown exception, returning FAIL:Failure Demonstration over the TCP socket.
This can also be demonstrated with the Telnet client:
telnet 127.0.0.1 5679 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. hello echo:hello FAIL FAIL:Failure Demonstration Hello World echo:Hello World ^] telnet> quit Connection closed.
Client-Server Demo with ConversionService
This demo is similar to the previous demo. However, instead of using explicit Transformers, this version shows how Spring's Conversion Service can be used to convert the byte array payloads to Strings. This demo also uses a Gateway as an entry point into the integration flow. The message generated by the Gateway is sent over TCP by the Outbound Gateway to the Inbound Gateway. In return, the Inbound Gateway sends the message to the echo service and the echoed response comes back over TCP and is returned to the test case for verification.
Please note the channel's dataType attribute. This attribute which will trigger the conversion service.
<int:channel id="toSA" datatype="java.lang.String" />
You can run the example by executing JUnit test TcpClientServerDemoWithConversionServiceTest.
<int-ip:tcp-connection-factory id="…" … serializer="" deserializer=""/>
This will apply the conversions right when the stream comes in to the Gateway and right when it goes out. Two examples (JUnit Tests) are provided:
- TcpServerConnectionDeserializeTest for using a simple (comes with Spring) Stx/Etx Serializer/Deserializer.
- TcpServerCustomSerializerTest for creating and using your own serializers
Stx-Etx Serializer Demo
The Stx-Etx Serializer Demo shows an example of using the Stx/Etx stream framing serializer (ByteArrayStxEtxSerializer) that is included with Spring Integration. This serializer reads data in an InputStream to a byte array. The data must be prefixed with the
<stx> control character and terminated by the
<etx> control character.
We can be confident that the streams are properly handled because we explicitly send a stream with the Stx/Etx frame and the beginning and end of the actual content and the Server is configured to be able to handle the frame. In the asserts, we assert that the payload, once it reaches a component (in this case, the message listener we create and attach to the incomingServerChannel), does not have any of the Stx/Etx bytes.
You can run the example by executing JUnit test TcpServerConnectionDeserializeTest.
Using Custom Serializers
Some use cases may dictate you needing to create your own stream handling serializers and deserializers. This sample shows a custom Serializer/Deserializer being used with the Java socket API on the front end (client) and the Spring Integration TCP inbound gateway with the custom serializer/deserializers.
You can run the example by executing JUnit test TcpServerCustomSerializerTest.
A simple client server test using entirely annotation-based configuration is shown in TcpClientServerAnnotationDemoTest.