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

Spring integration Spring集成回复消息将挂起,直到';超时TcpNioConnection';发生,spring-integration,Spring Integration,我想使用spring集成与另一台服务器(用C语言编写)进行TCP通信 服务器之间的交换数据是原始字节,但消息没有分隔符 因此,我编写了自己的序列化程序/反序列化程序,它扩展了AbstractByteArraySerializer 但是,当我通过MessagingGateway->TcpOutboundGateway->TcpNioClientConnectionFactory发送消息时,回复消息将挂起,直到TcpNioConnection超时 以下是我的SI java配置: @Bean(name

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

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

因此,我编写了自己的序列化程序/反序列化程序,它扩展了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();
}
@覆盖
公共字节[]反序列化(InputStream InputStream)引发IOException{
if(logger.isDebugEnabled()){
debug(“可读取:”+inputStream.Available());
}
字节[]头=新字节[2];
标头[0]=(字节)inputStream.read();
if(头[0]<0){
抛出新的SoftEndOfStreamException(“有效负载之间关闭的流”);
}
头[1]=(字节)inputStream.read();
if(头[1]<0){
抛出新的SoftEndOfStreamException(“有效负载之间关闭的流”);
}
int val=getIntFromTwoBytes(标头);
字节[]长度=新字节[val];
对于(int i=0;i

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

这当然不是目的,但我看到,是的,超时作为正常的EOF而不是IOException报告给反序列化程序

我们的标准原始反序列化程序(需要一个套接字来结束流)显示了这个问题

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

这当然不是目的,但我看到,是的,超时作为正常的EOF而不是IOException报告给反序列化程序

我们的标准原始反序列化程序(需要一个套接字来结束流)显示了这个问题

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

我看不到超时;我看到了回复:
2015-11-12 13:49:11.118调试10329---[nio-8080-exec-1]o.s.I.ip.tcp.TcpOutboundGateway:Response GenericMessage[payload=byte[108],headers={ip_地址=10.1.3.119,id=1006fc9a-8be4-3722-3cbb-9250714b47ec,ip_主机名=10.1.3.119,ip_tcp_远程端口=10101,ip_连接id=10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19,时间戳=144733255117}]
对不起,我的问题不好。问题应该是“在TcpNioConnection超时后,回复消息是否会传递回调用方?”。日志显示回复数据在13:49:09.116被读取到原始缓冲区,但“onMessage”方法在13:49:11.117…2s 1ms后被调用。谢谢。哦,我明白了;抱歉;错过了此
2015-11-12 13:49:10.117警告e> 。它不是设计用来这样做的,但这取决于反序列化程序的编写方式。我需要查看它的代码(或至少是错误处理)。您确实需要一些方法来分隔流上的消息。标准原始反序列化程序使用关闭套接字的对等方作为消息结束的通知。我在主题中添加了反序列化方法。我没有看到超时;我看到回复到达:
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_主机名=10.1.3.119,ip_远程端口=10101,ip_连接id=10.1.3.119:10101:38308:430e8a01-3d8a-462a-85a7-00ff6ce70b19,时间戳=1447332517]
对不起,我的问题不好。问题应该是“在TcpNioConnection超时后,回复消息是否会传递回调用方?”。日志显示回复数据在13:49:09.116被读取到原始缓冲区,但“onMessage”方法在13:49:11.117…2s 1ms后被调用。谢谢。哦,我明白了;抱歉;错过了此
2015-11-12 13:49:10.117警告e> 。它不是设计用来这样做的,但这取决于反序列化程序的编写方式。我需要查看它的代码(或至少是错误处理)。您确实需要一些方法来分隔流上的消息。标准原始反序列化器使用对等方关闭套接字作为消息结束的通知。我在主题中添加了反序列化方法。编辑;我无法使用您的反序列化器复制它;仅使用我们的反序列化器;请参阅编辑。感谢您的回答,我明白您的意思。因此,当您使用我的反序列化器时,回复消息是否立即发送回呼叫方?与我的情况不同,不是在连接超时后??如果消息已完成,则为是;如果是短消息(仍在等待数据)且超时,则为否,则不会向被呼叫方返回消息。当我发送
“\u0000\u0002\u0000\u0005回复”
收到回复。当我发送
“\u0000\u0002\u0000\u0005repl”
,即使在超时后,也不会收到任何内容。我为您的代码添加了一个测试,但它不需要任何代码更改就可以通过。感谢Garry的快速响应。您是对的。您无法使用我的反序列化程序重现超时,因为它按预期工作。我不知道昨天为什么会发生这种情况,但现在它可以工作了。无论如何,我很高兴由于这个问题,您改进了TearrayRawDeserializer
。编辑;我无法复制它
@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) {
        checkClosure(-1);
    }

    ByteBuffer headerBB = ByteBuffer.wrap(header);
    int val = headerBB.getShort();

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

    headerBB = ByteBuffer.wrap(length);
    int messageLength;
    if (val == 2) {
        messageLength = headerBB.getShort();
    }
    else if (val == 4) {
        messageLength = headerBB.getInt();
    }
    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) {
            checkClosure(-1);
        }
        answer[i] = (byte) bite;
    }

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