Yuanfei Bi
Yuanfei Bi

Reputation: 51

TCP client send Message to external server, reply message is not expected

I am setting up a TCP client by Spring Integration, send Message with String as payload, return is not expected. Perhaps serializer/deserializer is not working correctly? Sorry I am learning Spring integration.

I can connect to an external TCP server by oepnssl:

---
# DC API Test System: microstrategy
sessions.list.
.
response
,status_code,1
,status_message,Unrecognised operation
,time,2019-02-15 07:08:08 (+1000)
.

The command I need to sent is "sessions.list\n.\n".

Now I built a tcp client trying to connect to the server:

spring-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:int="http://www.springframework.org/schema/integration"
    xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip-5.1.xsd
        http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-5.1.xsd">

<bean id="integrationConversionService"
          class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="com.microstrategy.example.ByteArrayToStringConverter"/>
            </list>
        </property>
</bean> 


<bean id="customeSerilizerDeserlizer" class="com.microstrategy.example.CustomSerializerDeserializer" />

<int:gateway service-interface="com.microstrategy.example.SimpleGateway"
    default-request-channel="output"
    default-reply-channel="reply"/>

<int:channel id="output"/>
<int:channel id="reply" datatype="java.lang.String"/>

<int-ip:tcp-connection-factory
    id="clientFactory"
    type="client"
    host="server"
    port="15099"
    serializer="customeSerilizerDeserlizer"
    single-use="true"
    so-timeout="10000"/>

<int-ip:tcp-outbound-gateway 
    request-channel="output"
    reply-channel="reply"
    connection-factory="clientFactory"
    request-timeout="10000"
    reply-timeout="10000"/>

</beans>

So following this repo, the string should convert to byte[].

I am using exactly the same converter as the repo, so I just copy here to save your time:

import java.io.UnsupportedEncodingException;

import org.springframework.core.convert.converter.Converter;

public class ByteArrayToStringConverter implements Converter<byte[], String> {

    private String charSet = "UTF-8";

    public String convert(byte[] bytes) {
        try {
            return new String(bytes, this.charSet);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            System.out.println("caught excepton in converter");
            return new String(bytes);
        }
    }

    /**
     * @return the charSet
     */
    public String getCharSet() {
        return charSet;
    }

    /**
     * @param charSet the charSet to set
     */
    public void setCharSet(String charSet) {
        this.charSet = charSet;
    }

}
public interface SimpleGateway {
    public String send(Message message);
}

I made a custom serializer:

package com.microstrategy.example;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.springframework.integration.ip.tcp.serializer.AbstractByteArraySerializer;

public class CustomSerializerDeserializer extends AbstractByteArraySerializer {
    @Override
    public void serialize(byte[] bytes, OutputStream outputStream) throws IOException {
        outputStream.write(bytes); 
    }

    @Override
    public byte[] deserialize(InputStream inputStream) throws IOException {
        // TODO Auto-generated method stub
        return null;
    }

}

My main function:

Message<String> message = MessageBuilder.withPayload("sessions.list").build();
String replyMessage = simpleGateway.send(message);
Message<String> message2 = MessageBuilder.withPayload(".").build();
String replyMessage2 = simpleGateway.send(message2);
System.out.println(replyMessage2);

The replyMessage is

# DC API Test System: microstrategy

It seems I successfully connected to the server by sending message, but the message is not correctly recognized by the server. Any useful suggestions will be appreciated, thanks!

Update 1:

I add output to serializer:

public class CustomSerializerDeserializer extends AbstractByteArraySerializer {
    @Override
    public void serialize(byte[] bytes, OutputStream outputStream) throws IOException {
        System.out.println("inside serialize");
        System.out.println(System.currentTimeMillis());


        String string = new String(bytes);
        System.out.println("byte[] in serialize is " + string);
        outputStream.write(bytes); 
    }

    @Override
    public byte[] deserialize(InputStream inputStream) throws IOException {
        // TODO Auto-generated method stub
        System.out.println("inside deserialize");
        System.out.println(System.currentTimeMillis());

        return null;
    }

}
inside serialize
1550182834431
byte[] in serialize is sessions.list
.

# DC API Test System: microstrategy
2019-02-14 17:21:35.185  INFO 91620 --- [       Thread-1] o.s.i.endpoint.EventDrive

The output shows byte[] seems correct, then why server is not return as expected?

Update 2: I changed the main function (has been updated) because the framework will add "\n" at the end of each message. Is it right?

The output is

inside serialize
1550184564485
byte[] in serialize is sessions.list
inside serialize
1550184565003
byte[] in serialize is .
2019-02-14 17:49:35.013 ERROR 91740 --- [           main] o.s.i.ip.tcp.TcpOutboundGateway          : Tcp Gateway exception

org.springframework.integration.MessageTimeoutException: Timed out waiting for response

No response?

Update 3: I am able to open the connection by sending an empty message. But why other message is not working?

Message<String> message = MessageBuilder.withPayload("").build();
String replyMessage = simpleGateway.send(message);
System.out.println(replyMessage);

Any helps thanks?

This is my update before I solved the issue, which is deleted by admin:

I got the response from server now, but it comes with error:

Cannot correlate response - no pending reply for server:15099:49469:0fdce5c4-432f-4ce4-b878-2e08d0e96419
inside serialize
1550189909340
byte[] in serialize is sessions.list
.

GenericMessage [payload=byte[35], headers={ip_tcp_remotePort=15099, ip_connectionId=server:15099:49550:a3bc44fa-7d36-483c-a1b8-f91eea62d839, ip_localInetAddress=/10.21.66.115, ip_address=217.78.6.17, id=3a6ff696-f12f-6328-da1a-5d613d37a4b2, ip_hostname=server, timestamp=1550189909764}]
2019-02-14 19:18:29.850 ERROR 92282 --- [pool-1-thread-1] o.s.i.ip.tcp.TcpOutboundGateway          : Cannot correlate response - no pending reply for server:15099:49550:a3bc44fa-7d36-483c-a1b8-f91eea62d839
2019-02-14 19:18:29.851 ERROR 92282 --- [pool-1-thread-1] o.s.i.ip.tcp.TcpOutboundGateway          : Cannot correlate response - no pending reply for server:15099:49550:a3bc44fa-7d36-483c-a1b8-f91eea62d839
2019-02-14 19:18:29.851 ERROR 92282 --- [pool-1-thread-1] o.s.i.ip.tcp.TcpOutboundGateway          : Cannot correlate response - no pending reply for server:15099:49550:a3bc44fa-7d36-483c-a1b8-f91eea62d839
2019-02-14 19:18:29.851 ERROR 92282 --- [pool-1-thread-1] o.s.i.ip.tcp.TcpOutboundGateway          : Cannot correlate response - no pending reply for server:15099:49550:a3bc44fa-7d36-483c-a1b8-f91eea62d839
2019-02-14 19:18:29.852 ERROR 92282 --- [pool-1-thread-1] o.s.i.ip.tcp.TcpOutboundGateway          : Cannot correlate response - no pending reply for server:15099:49550:a3bc44fa-7d36-483c-a1b8-f91eea62d839
2019-02-14 19:18:29.852 ERROR 92282 --- [pool-1-thread-1] o.s.i.ip.tcp.TcpOutboundGateway  

The main function is

message = new GenericMessage<String>("sessions.list\n.\n");
replyMessage = simpleGateway.send(message);
System.out.println(replyMessage);

I tried to remove the last "\n"

message = new GenericMessage<String>("sessions.list\n.");

It does not work, got time-out exception. How can I remove these "Cannot correlate response" errors?

Update 1:

I think the server responses with several lines of message:

sessions.list
.
response
,status_code,0
,status_message,OK
,time,2019-02-16 00:10:49 (+1000)
sessions
.

I need to capture all responses until ".".

Upvotes: 0

Views: 945

Answers (2)

Yuanfei Bi
Yuanfei Bi

Reputation: 51

Finally it got solved. I will post my solution for others' reference.

My TCP client send multiple line commands which ends with ".", and expects multiple line response which also ends with "." from the external server. So I need to write custom serializer and deserializer. The default CRLF serializer/deserializer does not meet my case.

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;


import org.springframework.core.serializer.Deserializer;
import org.springframework.core.serializer.Serializer;

public class CustomSerializerDeserializer implements Serializer<String>, Deserializer<String> {

    @Override
    public String deserialize(InputStream inputStream) throws IOException {
        // TODO Auto-generated method stub
        StringBuilder builder = new StringBuilder();
        int c;
        while (true) {
            c = inputStream.read();
            builder.append((char)c);
            if ((char)c == '.') {
                break;
            }
        }

        return builder.toString();
    }

    @Override
    public void serialize(String object, OutputStream outputStream) throws IOException {
        // TODO Auto-generated method stub
        outputStream.write(object.getBytes());
        outputStream.flush();   
    }
}

The xml configuration is

<int-ip:tcp-connection-factory
    id="clientFactory"
    type="client"
    host="server"
    port="15099"
    ssl-context-support="sslContext"
    serializer="customeSerilizerDeserlizer"
    deserializer="customeSerilizerDeserlizer"
    single-use="true"
    so-timeout="10000"/>

Upvotes: 0

Gary Russell
Gary Russell

Reputation: 174494

If you are not expecting a reply you should use an outbound-channel-adapter instead of a gateway.

Upvotes: 1

Related Questions