Spring Integration TcpNetServerConnectionFactory for Single Never Close TCP Connection - spring-integration

Does the below ensure a never close single TCP connection, as well recover from any network errors by closing and recreating the TCP connection? Our use-case is legacy and requires a single TCP connection that should keep on reading and writing. Kindly suggest.
Also, couldn't find a way to include / configure heartbeat messages in the IntegrationFlow DSL.
#Bean
public AbstractConnectionFactory tcpNetServerConnectionFactory() {
var tcpNetServerConnectionFactory = new TcpNetServerConnectionFactory(port);
tcpNetServerConnectionFactory.setLeaveOpen(true);
tcpNetServerConnectionFactory.setSoTimeout(-1);
tcpNetServerConnectionFactory.setSoKeepAlive(true);
tcpNetServerConnectionFactory.setSoTcpNoDelay(true);
tcpNetServerConnectionFactory.setSerializer(byteArrayLengthHeaderSerializer());
tcpNetServerConnectionFactory.setDeserializer(byteArrayLengthHeaderSerializer());
return tcpNetServerConnectionFactory;
}

Yes, but the recovery is done by the client creating a new connection, not the server.

Related

Azure sql database TLS is always enable?

I wrote a java code. In the code, I used com.microsoft.sqlserver.jdbc.SQLServerDataSource to establish a JDBC connection with my Azure sql database . I found that no matter whether I used " ds.setEncrypt(true);" or not, the JDBC connection was encrypted by TLS ( I use wireshark to catch the TCP packaege , all the package is TLS whether I used " ds.setEncrypt(true);" or not ).
Why ? I checked many official documents, but I couldn't find the answer . It's too difficult...
Azure sql database TLS is always enable ? Are there relevant official documents to prove it ?
The question is : I use ds.setEncrypt(true) or not ,even i set this to "false" , the TCP packages are encrypted by TLS . Why ?
Below is my code to establish the JDBC connection .
public static Connection getConnectionObject() {
SQLServerDataSource ds = new SQLServerDataSource();
ds.setServerName("azuresqldbserver0821.database.windows.net");
ds.setDatabaseName("azuresqldb0821");
ds.setPortNumber(1433);
ds.setUser("root0817");
ds.setPassword("<YourStrong#Passw0rd>");
ds.setEncrypt(false);// I use this method or not ,even i set this to "false" , the TCP packages are encrypted by TLS
ds.setTrustServerCertificate(true);
Connection conn;
try {
conn = ds.getConnection();
} catch (Exception e) {
e.printStackTrace();
return null;
}
return conn;
}
}
When a client first attempts a connection to SQL Azure, it sends an initial connection request. Consider this a "pre-pre-connection" request. At this point the client does not know if TLS/SSL/Encryption is required and waits an answer from SQL Azure to determine if TLS/SSL is indeed required throughout the session (not just the login sequence, the entire connection session). A bit is set on the response indicating so. Then the client library disconnects and reconnects armed with this information.
When you set "Encrypt connection" setting on the connetion string you avoid the "pre-pre-connection", you are preventing any proxy from turning off the encryption bit on the client side of the proxy, this way attacks like man-in-the-middle attack are avoided.
When secure connections are needed, please enable "Encrypt connection" setting.
In-transit encryption to Azure SQL is always enabled.
Transport Layer Security (TLS) was previously known as Secure Sockets Layer (SSL).

Spring Integration Tcp project

I have a project that part of it is using Tcp connection, the case is as per below , I will also include a screen shot.
We have two clients, client 1 and client 2 those are conveyor belts so if we receive data on client one input we should send the reply to client 2 output and vise vers, I'm sure we can do it using Spring integration Tcp and probably getways. Am I approaching correctly Tcp integration at this case?
Yet I do not have code implementation but started to put something on it.
Sounds like you implementing a chat (or similar user-to-user) communication.
No, gateways won't help you here.
You need to have a TcpReceivingChannelAdapter and TcpSendingMessageHandler connected to the same AbstractServerConnectionFactory. The TcpSendingMessageHandler is registered as a TcpSender with that connection and all the sending connections are stored in the Map<String, TcpConnection> connections. When we produce a message to this MessageHandler, it tries to consult that registry like this:
private void handleMessageAsServer(Message<?> message) {
// We don't own the connection, we are asynchronously replying
String connectionId = message.getHeaders().get(IpHeaders.CONNECTION_ID, String.class);
TcpConnection connection = null;
if (connectionId != null) {
connection = this.connections.get(connectionId);
}
if (connection != null) {
So, on the receiving side (TcpReceivingChannelAdapter and its sub-flow) you need to ensure somehow that you really set a proper IpHeaders.CONNECTION_ID header for producing so-called reply in the end to a desired client.
You probably can react for the TcpConnectionOpenEvent via #EventListener and register some business key with the connectionId for the future correlation. When you send a message, you supply that target user business key, in the TcpReceivingChannelAdapter sub-flow you take that business key and obtain a desired connectionId from you registry. And enrich it into the IpHeaders.CONNECTION_ID header for automatic logic in the TcpSendingMessageHandler.
When TcpConnectionCloseEvent happens you have to remove its respective entry from your custom registry.
Since TCP/IP comes without headers support there is no any out-of-the-box mechanism to implement such a correlation feature.
Although TcpConnectionOpenEvent might not be enough for you since there is no any business info when connection is established. Perhaps you would need to implement some hand-shake logic in the TcpReceivingChannelAdapter flow to distinguish a real message and connection metadata for registering in the custom registry.
See more info in the docs: https://docs.spring.io/spring-integration/docs/current/reference/html/ip.html#ip-correlation
It might be also better for your use-case to look into a WebSocket support: https://docs.spring.io/spring-integration/docs/current/reference/html/web-sockets.html#web-sockets

Spring Integration TcpInboundGateway:TcpNetServerConnectionFactory : Server Socket closed exception

I am using spring integration TcpInboundGateway in my app that receives requests(packets) from remote clients over TCP channel.The configuration as follows:
#Bean
ByteArrayCrLfSerializer ser()
{
return new ByteArrayCrLfSerializer();
}
#Bean
TcpNetServerConnectionFactory cf(){
TcpNetServerConnectionFactory connectionFactory=new TcpNetServerConnectionFactory(45456);
connectionFactory.setSingleUse(true);
connectionFactory.setSerializer(ser());
connectionFactory.setDeserializer(ser());
return connectionFactory;
}
#Bean
TcpInboundGateway tcpGate(){
TcpInboundGateway gateway=new TcpInboundGateway();
gateway.setConnectionFactory(cf());
gateway.setRequestChannel(requestChannel());
gateway.setRequestTimeout(TIMEOUT);
return gateway;
}
#Bean
public MessageChannel requestChannel(){
return new DirectChannel();
}
As per my knowledge it supports multithreading. But when lot of requests comes at same time apllication stop working with following error message.
2016-06-13 06:12:52.330 INFO 1431 --- [pool-2-thread-1] .s.i.i.t.c.TcpNetServerConnectionFactory : Server Socket closed
Is there any any configuration missing to support multithreading to handle large number of requests concurrently.
Not enough StackTrace, though... Although that may be as a reason of that gateway.setRequestTimeout(TIMEOUT); when your downstream process can't catch up all the incoming messages. Consider to make it infinite.
Or take a look to your services and try to figure out why they don't work in multithreading properly.
You might want to use Non-Blocking I/O by means of TcpNioServerConnectionFactory instead of TcpNetServerConnectionFactory.
Some docs: https://docs.spring.io/spring-integration/docs/5.2.1.RELEASE/reference/html/ip.html#note-nio

ClientWebSocketContainer - can it be used on the client side to create a websocket connection?

The ClientWebSocketContainer Spring class can provide a websocket connection session to a remote endpoint. Though if an attempt is made to re-establish a closed connection (after a failed attempt) by using the ClientWebSocketContainer stop(), start(), and then getSession() methods, the connection is established but the ClientWebSocketContainer thinks it isn't connected due to the openConnectionException set in the failed attempt.
#Override
public void onFailure(Throwable t) {
logger.error("Failed to connect", t);
ClientWebSocketContainer.this.openConnectionException = t;
ClientWebSocketContainer.this.connectionLatch.countDown();
}
Should I be able to use the ClientWebSocketContainer in this fashion or should I create my own client connection manager?
I think it's just a bug, some kind of omission in the ClientWebSocketContainer logic.
I've just raised a JIRA on the matter. Will be fixed today.
Meanwhile give us more information what is your task?
The ClientWebSocketContainer is based on the ConnectionManagerSupport, where one of its implementation is WebSocketConnectionManager. So, consider to use the last one for obtaining the session.
If you use Spring Integration WebSocket Adapters, you don't have choice unless implement your own ClientWebSocketContainer variant. Yes, it fully may be based on the existing one.

Spring Integration - TCP - Response Correlation

I'm new to Spring Integration. The situation is that I've to connect to Tcp server dynamically(i.e. the DNS will be dynamically generated at runtime based on some params). Because of this I'm using Service Activator to manually create Tcp Connections and send messages. I've overridden CachingClientConnectionFactory to make use of shared connections concept(with single-use='false'). I was listening to messages using TcpReceivingChannelAdaptor by overriding "onMessage" method. The problem is that the server either responds with a Success or failure(with Generic messages) with no CorrelationID. Is there any way to correlate the request with the response ?
I tried using TcpOutboundGateway, but with this approach also I get the same problem. I used TcpConnectionSupport to send messages :
//Sample Code.
final String correlationId = "" // Dynamic unique number
TcpOutboundGateway outboundGateway = new TcpOutboundGateway(){
public synchronized boolean onMessage(Message<?> message) {
ByteArrayToStringConverter converter = new ByteArrayToStringConverter();
String response = converter.convert((byte[]) message
.getPayload());
logger.info(correlationId);
return false;
}
};
DefaultCachingClientConnectionFactory connFactory = new DefaultCachingClientConnectionFactory();
TcpConnectionSupport con = connFactory.obtainConnection();
GenericMessage<String> msg = new GenericMessage<String>("Sample Message" + correlationId);
con.registerListener(outboundGateway);
con.send(msg);
// DefaultCachingClientConnectionFactory is the subclass of CachingClientConnectionFactory.
When I send multiple messages, every time I get the same correlation printed in the "onMessage" method.
I read here that Outbound Gateway will correlate messages. Please help me. Maybe I'm doing something wrong.
Thanks
Unless you include correlation data in the message you can't correlate a response to a request.
The gateway achieves this by only allowing one outstanding request on a socket at a time; hence the reply has to be for the request. This is not very useful at high volume with a shared connection; hence the caching client cf was introduced. The gateway keeps a map of outstanding requests based on the connection id.
The gateway, in conjunction with the caching client connection factory should do what you need. However, overriding onMessage is not a good idea, because that's where the reply correlation is done.

Resources