春季集成:连接步骤中的容器应用程序悬挂几秒钟

发布于 2025-02-09 19:01:04 字数 3353 浏览 1 评论 0原文

简而言之,我有一个使用Spring实现的套接字应用程序,我共享以下代码:

@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);
            }
        };
    }
}

当我本地运行此应用程序时,一切都很好:

我只使用Telnet(用于手动连接),然后在连接之后连接到该连接大约立即请参阅我的服务器问候,我可以通过命令与服务器进行通信 - &gt;回复。

当我在Docker容器中运行我的应用程序时,它会遇到一些麻烦。基本上,它立即将我连接到服务器,但我看到了延迟6秒的问候消息。它也没有回复我的命令,只是在此期间忽略它们。当它打印问候时 - 它也显示了我的请求的响应。之后,我能够与服务器合作而没有任何问题。

有人面对同样的问题吗?

upd:仅作为记录,该应用程序没有使用任何数据库,因此它非常轻巧的

upd1:也许,我的docker组成文件中的问题看起来很简单:

  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:最长的延迟是在firt连接期间,通常是这样。需要6秒。下一个连接也将延迟,但最多将需要2秒钟。

upd3:此外,容器内部通信中存在此问题。我只使用此应用程序进行简单的Springboot Intergration测试 - 当我尝试从插座连接和阅读时 - 我正在收回ReadTimeOutConnection

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

下雨或天晴 2025-02-16 19:01:04

这解决了我的问题:

@Bean
public AbstractServerConnectionFactory serverConnectionFactory() {
    TcpNetServerConnectionFactory tcpNetServerConnectionFactory = new TcpNetServerConnectionFactory(port);
    tcpNetServerConnectionFactory.setLookupHost(false);
    return tcpNetServerConnectionFactory;
}

请参阅我禁用的选项:

/**
 * 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) {

最后使用此选项:

    InetAddress inetAddress = socket.getInetAddress();
    if (inetAddress != null) {
        this.hostAddress = inetAddress.getHostAddress();
        if (lookupHost) {
            this.hostName = inetAddress.getHostName();
        }
        else {
            this.hostName = this.hostAddress;
        }
    }

因此,显然,inetAddress.gethostName()确实需要一些时间来解决Docker DNS中的分辨率。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文