In brief, I have a socket app, implemented with spring, I share the code below:
@SpringBootApplication
public class ExampleApp {
public static void main(String[] args) {
SpringApplication.run(ExampleApp.class, args);
}
@Bean
public AbstractServerConnectionFactory serverConnectionFactory() {
TcpNetServerConnectionFactory tcpNetServerConnectionFactory = new TcpNetServerConnectionFactory(1234);
return tcpNetServerConnectionFactory;
}
@Bean
public MessageChannel requestChannel() {
return new DirectChannel();
}
@Bean
public MessageChannel replyChannel() {
return new DirectChannel();
}
@Bean
public TcpReceivingChannelAdapter receivingChannelAdapter(AbstractServerConnectionFactory serverConnectionFactory, MessageChannel requestChannel) {
TcpReceivingChannelAdapter tcpReceivingChannelAdapter = new TcpReceivingChannelAdapter();
tcpReceivingChannelAdapter.setConnectionFactory(serverConnectionFactory);
tcpReceivingChannelAdapter.setOutputChannel(requestChannel);
return tcpReceivingChannelAdapter;
}
@Bean
@ServiceActivator(inputChannel = "replyChannel")
public TcpSendingMessageHandler tcpSendingMessageHandler(AbstractServerConnectionFactory serverConnectionFactory) {
TcpSendingMessageHandler tcpSendingMessageHandler = new TcpSendingMessageHandler();
tcpSendingMessageHandler.setConnectionFactory(serverConnectionFactory);
return tcpSendingMessageHandler;
}
@ServiceActivator(inputChannel = "requestChannel", outputChannel = "replyChannel")
public Message<String> processMessage(Message<String> message) {
Message<String> reply = MessageBuilder
.withPayload("OK")
.setHeader(IpHeaders.CONNECTION_ID, message.getHeaders().get(IpHeaders.CONNECTION_ID, String.class))
.build();
return reply;
}
@Bean
public ApplicationListener<TcpConnectionEvent> listener(MessageChannel replyChannel) {
return tcpConnectionEvent -> {
if (tcpConnectionEvent instanceof TcpConnectionOpenEvent) {
Message<String> message = MessageBuilder
.withPayload("Hello client")
.setHeader(IpHeaders.CONNECTION_ID, tcpConnectionEvent.getConnectionId())
.build();
replyChannel.send(message);
}
};
}
}
When I am running this application locally, everything is fine:
I just use telnet (for the manual connect) and connect there, after connection approximately instantly I see my Server greeting and I am able to communicate with the Server by command -> response.
When I am running my app in docker container - it has some troubles. Basically, it instantly connects me to the Server but I see the greeting message with 6 seconds of delay. It does not reply to my commands as well, just ignores them during that period. When it prints greeting - it shows the responses for my requests as well. After that I am able to cooperate with the Server without any problems.
Have anybody faced the same problem?
UPD: just for the record, the app is not using any database, so it is very lightweight
UPD1: maybe, problem is in my docker compose file, it looks quite simple:
app:
image: me/app:v1
container_name: app
build:
context: *ToAppRootDir*
dockerfile: *pathToDockerFile*
restart: always
environment:
- SERVER_PORT: 8080
- SOCKET_PORT: 8081
ports:
- "8080:8080"
- "8081:8081"
UPD2: The longest delay is during the firt connection, usually it takes 6seconds. The next connection will have delay as well, but it will takes up to 2 seconds.
UPD3: Moreover, this problem exists in the container internal communication. I have simple springBoot intergration test with only this app - and when i am trying to connect and read from the socket - i am recieving ReadTimeoutConnection
CodePudding user response:
This has fixed the problem for me:
@Bean
public AbstractServerConnectionFactory serverConnectionFactory() {
TcpNetServerConnectionFactory tcpNetServerConnectionFactory = new TcpNetServerConnectionFactory(port);
tcpNetServerConnectionFactory.setLookupHost(false);
return tcpNetServerConnectionFactory;
}
See that option I disable:
/**
* If true, DNS reverse lookup is done on the remote ip address.
* Default true.
* @param lookupHost the lookupHost to set
*/
public void setLookupHost(boolean lookupHost) {
This one in the end is used like this:
InetAddress inetAddress = socket.getInetAddress();
if (inetAddress != null) {
this.hostAddress = inetAddress.getHostAddress();
if (lookupHost) {
this.hostName = inetAddress.getHostName();
}
else {
this.hostName = this.hostAddress;
}
}
So, apparently that inetAddress.getHostName()
really takes some time for resolution in the Docker DNS.