Spring集成回复消息挂起,直到超时TcpNioConnection'发生

时间:2015-11-12 13:32:11

标签: spring-integration

我想使用spring集成与另一台服务器进行TCP通信(用C语言编写)。

服务器之间的Exchange数据是原始字节,但消息没有分隔符。

因此,我编写了自己的Serializer / Deserializer,扩展了 AbstractByteArraySerializer

但是,当我通过MessagingGateway发送消息时 - > TcpOutboundGateway - > TcpNioClientConnectionFactory,回复消息挂起,直到超时TcpNioConnection发生。

这是我的SI java配置:

@Bean(name = "loggingChannel")
public MessageChannel loggingChannel() {
    return new DirectChannel();
}

@Bean
@GlobalChannelInterceptor()
public ChannelInterceptor wiretap() {
    return new WireTap(loggingChannel(), s -> true);
}

private int port = 10101;

private String host = "10.1.3.119";

@Bean
public MessageChannel toTcp() {
    return new DirectChannel();
}

@Bean
public MessageChannel fromTcp() {
    return new DirectChannel();
}

@Autowired
public PerunGateway perunGateway;

@MessagingGateway(defaultRequestChannel = "toTcp", defaultReplyChannel = "fromTcp")
public interface PerunGateway {

    @Gateway
    byte[] sendCommand(byte[] message);
}

@Bean
@ServiceActivator(inputChannel = "toTcp")
public TcpOutboundGateway tcpOutGate() {
    TcpOutboundGateway gate = new TcpOutboundGateway();
    gate.setConnectionFactory(clientConnectionFactory());
    gate.setOutputChannelName("fromTcp");
    gate.setRequestTimeout(5000);
    return gate;
}

@Bean
public AbstractClientConnectionFactory clientConnectionFactory() {
    TcpNioClientConnectionFactory tnccf = new TcpNioClientConnectionFactory(host, port);
    tnccf.setSoTimeout(1000);
    tnccf.setSingleUse(true);
    tnccf.setSerializer(new SunByteArrayRawSerializer());
    tnccf.setDeserializer(new SunByteArrayRawSerializer());
    return tnccf;
}

发送消息后我得到输出:

2015-11-12 13:49:09.032 DEBUG 10329 --- [nio-8080-exec-1] o.s.integration.channel.DirectChannel    : preSend on channel 'toTcp', message: GenericMessage [payload=byte[150], headers={replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@66e6fc48, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@66e6fc48, id=e5425395-e1cb-8cc7-20fd-eb5b9be3a615, timestamp=1447332549031}]
        2015-11-12 13:49:09.032 DEBUG 10329 --- [nio-8080-exec-1] o.s.integration.channel.DirectChannel    : preSend on channel 'loggingChannel', message: GenericMessage [payload=byte[150], headers={replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@66e6fc48, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@66e6fc48, id=e5425395-e1cb-8cc7-20fd-eb5b9be3a615, timestamp=1447332549031}]
        2015-11-12 13:49:09.033 DEBUG 10329 --- [nio-8080-exec-1] o.s.integration.handler.LoggingHandler   : org.springframework.integration.handler.LoggingHandler#0 received message: GenericMessage [payload=byte[150], headers={replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@66e6fc48, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@66e6fc48, id=e5425395-e1cb-8cc7-20fd-eb5b9be3a615, timestamp=1447332549031}]
        2015-11-12 13:49:09.033  INFO 10329 --- [nio-8080-exec-1] o.s.integration.handler.LoggingHandler   : GenericMessage [payload=byte[150], headers={replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@66e6fc48, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@66e6fc48, id=e5425395-e1cb-8cc7-20fd-eb5b9be3a615, timestamp=1447332549031}]
        2015-11-12 13:49:09.034 DEBUG 10329 --- [nio-8080-exec-1] o.s.integration.channel.DirectChannel    : postSend (sent=true) on channel 'loggingChannel', message: GenericMessage [payload=byte[150], headers={replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@66e6fc48, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@66e6fc48, id=e5425395-e1cb-8cc7-20fd-eb5b9be3a615, timestamp=1447332549031}]
        2015-11-12 13:49:09.034 DEBUG 10329 --- [nio-8080-exec-1] o.s.i.ip.tcp.TcpOutboundGateway          : tcpOutGate received message: GenericMessage [payload=byte[150], headers={replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@66e6fc48, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@66e6fc48, id=e5425395-e1cb-8cc7-20fd-eb5b9be3a615, timestamp=1447332549031}]
        2015-11-12 13:49:09.034 DEBUG 10329 --- [nio-8080-exec-1] .s.i.i.t.c.TcpNioClientConnectionFactory : Opening new socket connection to 10.1.3.119:10101
        2015-11-12 13:49:09.042 DEBUG 10329 --- [nio-8080-exec-1] o.s.i.i.tcp.connection.TcpNioConnection  : New connection 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19
        2015-11-12 13:49:09.043 DEBUG 10329 --- [nio-8080-exec-1] .s.i.i.t.c.TcpNioClientConnectionFactory : clientConnectionFactory: Added new connection: 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19
        2015-11-12 13:49:09.045 TRACE 10329 --- [pool-1-thread-1] .s.i.i.t.c.TcpNioClientConnectionFactory : clientConnectionFactory: Connection is open: 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19
        2015-11-12 13:49:09.045 TRACE 10329 --- [pool-1-thread-1] .s.i.i.t.c.TcpNioClientConnectionFactory : Host 10.1.3.119 port 10101 SelectionCount: 0
        2015-11-12 13:49:09.048 DEBUG 10329 --- [nio-8080-exec-1] o.s.i.ip.tcp.TcpOutboundGateway          : Added pending reply 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19
        2015-11-12 13:49:09.049 DEBUG 10329 --- [nio-8080-exec-1] o.s.i.i.tcp.connection.TcpNioConnection  : 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19 writing 150
        2015-11-12 13:49:09.049 DEBUG 10329 --- [nio-8080-exec-1] o.s.i.i.tcp.connection.TcpNioConnection  : 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19 Message sent GenericMessage [payload=byte[150], headers={replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@66e6fc48, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@66e6fc48, id=e5425395-e1cb-8cc7-20fd-eb5b9be3a615, timestamp=1447332549031}]
        2015-11-12 13:49:09.111 TRACE 10329 --- [pool-1-thread-1] .s.i.i.t.c.TcpNioClientConnectionFactory : clientConnectionFactory: Connection is open: 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19
        2015-11-12 13:49:09.111 TRACE 10329 --- [pool-1-thread-1] .s.i.i.t.c.TcpNioClientConnectionFactory : Host 10.1.3.119 port 10101 SelectionCount: 1
        2015-11-12 13:49:09.114 DEBUG 10329 --- [pool-1-thread-2] o.s.i.i.tcp.connection.TcpNioConnection  : 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19 Reading...
        2015-11-12 13:49:09.115 DEBUG 10329 --- [pool-1-thread-2] o.s.i.i.tcp.connection.TcpNioConnection  : 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19 Running an assembler
        2015-11-12 13:49:09.115 TRACE 10329 --- [pool-1-thread-2] o.s.i.i.tcp.connection.TcpNioConnection  : Before read:0/61440
        2015-11-12 13:49:09.115 TRACE 10329 --- [pool-1-thread-3] o.s.i.i.tcp.connection.TcpNioConnection  : 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19 Nio message assembler running...
        2015-11-12 13:49:09.115 TRACE 10329 --- [pool-1-thread-3] o.s.i.i.tcp.connection.TcpNioConnection  : 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19 checking data avail: 0 pending: true
        2015-11-12 13:49:09.116 TRACE 10329 --- [pool-1-thread-3] o.s.i.i.tcp.connection.TcpNioConnection  : 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19 checking data avail (convert): 0 pending: true
        2015-11-12 13:49:09.116 TRACE 10329 --- [pool-1-thread-2] o.s.i.i.tcp.connection.TcpNioConnection  : After read:102/61440
        2015-11-12 13:49:09.116 TRACE 10329 --- [pool-1-thread-2] o.s.i.i.tcp.connection.TcpNioConnection  : After flip:0/102
        2015-11-12 13:49:09.116 DEBUG 10329 --- [pool-1-thread-2] o.s.i.i.tcp.connection.TcpNioConnection  : Read 102 into raw buffer
        2015-11-12 13:49:09.116 TRACE 10329 --- [pool-1-thread-2] o.s.i.i.tcp.connection.TcpNioConnection  : 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19 Sending 102 to pipe
        2015-11-12 13:49:09.116 TRACE 10329 --- [pool-1-thread-1] .s.i.i.t.c.TcpNioClientConnectionFactory : clientConnectionFactory: Connection is open: 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19
        2015-11-12 13:49:09.117 TRACE 10329 --- [pool-1-thread-1] .s.i.i.t.c.TcpNioClientConnectionFactory : Host 10.1.3.119 port 10101 SelectionCount: 0
        2015-11-12 13:49:10.117  WARN 10329 --- [pool-1-thread-1] .s.i.i.t.c.TcpNioClientConnectionFactory : Timing out TcpNioConnection 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19
        2015-11-12 13:49:10.118 DEBUG 10329 --- [pool-1-thread-1] .s.i.i.t.c.TcpNioClientConnectionFactory : clientConnectionFactory: Removed closed connection: 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19
        2015-11-12 13:49:10.119 TRACE 10329 --- [pool-1-thread-1] .s.i.i.t.c.TcpNioClientConnectionFactory : Host 10.1.3.119 port 10101 SelectionCount: 0
        2015-11-12 13:49:11.117 TRACE 10329 --- [pool-1-thread-3] o.s.i.i.tcp.connection.TcpNioConnection  : 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19 checking data avail: 0 pending: false
        2015-11-12 13:49:11.117 TRACE 10329 --- [pool-1-thread-3] o.s.i.ip.tcp.TcpOutboundGateway          : onMessage: 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19(GenericMessage [payload=byte[108], headers={ip_address=10.1.3.119, id=1006fc9a-8be4-3722-3cbb-9250714b47ec, ip_hostname=10.1.3.119, ip_tcp_remotePort=10101, ip_connectionId=10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19, timestamp=1447332551117}])
        2015-11-12 13:49:11.117 TRACE 10329 --- [pool-1-thread-3] o.s.i.i.tcp.connection.TcpNioConnection  : 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19 checking data avail: 0 pending: false
        2015-11-12 13:49:11.118 TRACE 10329 --- [pool-1-thread-3] o.s.i.i.tcp.connection.TcpNioConnection  : 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19 Nio message assembler exiting... avail: 0
        2015-11-12 13:49:11.118 DEBUG 10329 --- [nio-8080-exec-1] o.s.i.ip.tcp.TcpOutboundGateway          : Response GenericMessage [payload=byte[108], headers={ip_address=10.1.3.119, id=1006fc9a-8be4-3722-3cbb-9250714b47ec, ip_hostname=10.1.3.119, ip_tcp_remotePort=10101, ip_connectionId=10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19, timestamp=1447332551117}]
        2015-11-12 13:49:11.118 DEBUG 10329 --- [nio-8080-exec-1] o.s.i.ip.tcp.TcpOutboundGateway          : Removed pending reply 10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19

有什么想法吗?

这是我的自定义反序列化方法:

@Override
public byte[] deserialize(InputStream inputStream) throws IOException {
    if (logger.isDebugEnabled()) {
        logger.debug("Available to read:" + inputStream.available());
    }

    byte[] header = new byte[2];
    header[0] = (byte) inputStream.read();
    if (header[0] < 0) {
        throw new SoftEndOfStreamException("Stream closed between payloads");
    }

    header[1] = (byte) inputStream.read();
    if (header[1] < 0) {
        throw new SoftEndOfStreamException("Stream closed between payloads");
    }

    int val = getIntFromTwoBytes(header);

    byte[] length = new byte[val];
    for (int i = 0; i < val; i++) {
        length[i] = (byte) inputStream.read();
    }

    int messageLength;
    if (val == 2) {
        messageLength = getIntFromTwoBytes(length);
    } else if (val == 4) {
        messageLength = getIntFromFourBytes(length);
    } else throw new IOException("Unexpected count of bytes that holds message length");

    byte[] answer = new byte[messageLength];
    for (int i = 0; i < messageLength; i++) {
        int bite = inputStream.read();
        if (bite < 0) {
            throw new SoftEndOfStreamException("Stream closed between payloads");
        }
        answer[i] = (byte) bite;
    }

    ByteBuffer b = ByteBuffer.allocate(2 + val + messageLength);
    b.put(header);
    b.put(length);
    b.put(answer);
    return b.array();
}

我们使用自己的二进制协议,所以我知道传入消息的确切长度。

1 个答案:

答案 0 :(得分:0)

这当然不是意图,但是我看到了,是的,超时被报告给反序列化器作为正常的EOF而不是IOException。

我们的标准原始反序列化器(期望一个套接字接近结束流)表现出这个问题......

fetch first

因为超时被视为EOF并且返回了部分消息(作为休息的结果)。

你的反序列化程序在获得EOF时根本不会检查它是否有部分结果......

if (bite < 0) {
    if (n == 0) {
        throw new SoftEndOfStreamException("Stream closed between payloads");
    }
    break;
}

...所以我看不出你的解串器如何表现出这个问题。当我们超时消息时,您的反序列化器应该得到if (bite < 0) { throw new SoftEndOfStreamException("Stream closed between payloads"); } ,这应该只是导致部分消息被丢弃。

我们需要更改NIO连接,以便反序列化器在超时后获得超时异常,但在这种情况下,反序列化器不应该导致部分消息。

我会看看我是否可以模拟一些数据来处理你的代码并回复你。

修改

我没有看到您的反序列化程序的行为,只能使用我们的标准-1

我首先用你提供的测试;然后我把它打磨了一下 - 在开始解码数据之后你不应该抛出ByteArrayRawDeserializer;这应该是一个硬IOException(例如通过调用SoftEndOfStreamException)。

这是我的精美版本:

checkClosure()