My use case:
echo -n "coincoincoin" | nc -v host port
Unfortunately, the step from one to 3 is OK. The step 4 is not OK and I get a
... Failed to send reply ...
The server config's file:
@Configuration
public class ServerConfig {
@Value("${server.port}")
private int port;
@Bean
TcpNetServerConnectionFactory serverConnexion() {
TcpNetServerConnectionFactory factory = new TcpNetServerConnectionFactory(port);
factory.setSingleUse(true);
factory.setDeserializer(new CustomSerializerDeserializer());
factory.setSerializer(new CustomSerializerDeserializer());
factory.setSoTimeout(10000);
return factory;
}
@Bean
TcpInboundGateway tcpGateway() {
TcpInboundGateway gateway = new TcpInboundGateway();
gateway.setConnectionFactory(serverConnexion());
gateway.setRequestChannel(reqChannel());
gateway.setReplyChannel(reqChannel());
return gateway;
}
@Bean
public MessageChannel reqChannel() {
return new DirectChannel();
}
}
Here is my exception:
2022-12-18 14:21:51.524 DEBUG 14816 --- [pool-3-thread-2] org.springframework.integration.channel.DirectChannel : [( - )] postSend (sent=true) on channel 'bean 'reqChannel'; defined in: 'class path resource [com/server/config/ServerConfig.class]'; from source: 'com.rss.server.config.ServerConfig.reqChannel()'', message: GenericMessage [payload=byte[40], headers={replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@68980b5b, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@68980b5b, ip_tcp_remotePort=38567, ip_connectionId=kubernetes.docker.internal:38567:11000:e143aeae-532c-4aab-9ef1-ba7930ecc3ef, ip_localInetAddress=0.0.0.0/0.0.0.0, ip_address=127.0.0.1, id=3265835d-8088-7820-d7e5-0dd46ddab69c, ip_hostname=kubernetes.docker.internal, timestamp=1671369710212}]
2022-12-18 14:21:51.524 ERROR 14816 --- [pool-3-thread-2] org.springframework.integration.ip.tcp.TcpInboundGateway : [( - )] Failed to send reply
org.springframework.messaging.MessagingException: Send Failed; nested exception is java.net.SocketException: Socket is closed
at org.springframework.integration.ip.tcp.connection.TcpNetConnection.send(TcpNetConnection.java:119) ~[spring-integration-ip-5.5.8.jar:5.5.8]
at org.springframework.integration.ip.tcp.TcpInboundGateway.doOnMessage(TcpInboundGateway.java:139) [spring-integration-ip-5.5.8.jar:5.5.8]
at org.springframework.integration.ip.tcp.TcpInboundGateway.onMessage(TcpInboundGateway.java:101) [spring-integration-ip-5.5.8.jar:5.5.8]
at org.springframework.integration.ip.tcp.connection.TcpNetConnection.receiveAndProcessMessage(TcpNetConnection.java:224) [spring-integration-ip-5.5.8.jar:5.5.8]
at org.springframework.integration.ip.tcp.connection.TcpNetConnection.run(TcpNetConnection.java:197) [spring-integration-ip-5.5.8.jar:5.5.8]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
at java.lang.Thread.run(Thread.java:834) [?:?]
Caused by: java.net.SocketException: Socket is closed
at java.net.Socket.getSendBufferSize(Socket.java:1215) ~[?:?]
at org.springframework.integration.ip.tcp.connection.TcpNetConnection.send(TcpNetConnection.java:108) ~[spring-integration-ip-5.5.8.jar:5.5.8]
... 7 more
How can I solve this problem? Any help would be welcome! Thank you very much!
It looks like piping the echo into nc
closes the socket before the response is sent; this works fine for me...
@Component
class ServerConfig {
private final int port = 1234;
@Bean
TcpNetServerConnectionFactory serverConnexion() {
TcpNetServerConnectionFactory factory = new TcpNetServerConnectionFactory(port);
factory.setSingleUse(true);
// factory.setDeserializer(new CustomSerializerDeserializer());
// factory.setSerializer(new CustomSerializerDeserializer());
factory.setSoTimeout(10000);
return factory;
}
@Bean
TcpInboundGateway tcpGateway(TcpNetServerConnectionFactory serverConnexion, MessageChannel reqChannel) {
TcpInboundGateway gateway = new TcpInboundGateway();
gateway.setConnectionFactory(serverConnexion);
gateway.setRequestChannel(reqChannel);
gateway.setReplyChannel(reqChannel);
return gateway;
}
@Bean
public MessageChannel reqChannel() {
return new DirectChannel();
}
}
Note that I am using the default (de)serializer (CRLF).
% nc -cv localhost 1234
Connection to localhost port 1234 [tcp/search-agent] succeeded!
foo
foo
thanks for your answer @Gary, I modify (de)serializer and this work fine. Before this, I tried to use ByteArrayLengthHeaderSerializer because my default length field is a 4 byte. Unfortunelly, I get an exception
... length 808465456 exceeds max message length: 2048
Here is the complete exeption:
2022-12-23 09:02:43.746 DEBUG 59032 --- [pool-3-thread-2] org.springframework.integration.ip.tcp.serializer.ByteArrayLengthHeaderSerializer : [( - )] Read 4 bytes, buffer is now at 4 of 4
2022-12-23 09:02:43.748 DEBUG 59032 --- [pool-3-thread-2] org.springframework.integration.ip.tcp.serializer.ByteArrayLengthHeaderSerializer : [( - )] Message length is 808465456
2022-12-23 09:02:43.754 ERROR 59032 --- [pool-3-thread-2] org.springframework.integration.ip.tcp.connection.TcpNetConnection : [( - )] Read exception kubernetes.docker.internal:2522:11000:c7c6e319-8794-4dbd-91bd-48fb8c36f43e IOException:Message length 808465456 exceeds max message length: 2048
My payload looks like: 0040UUU011234021234000020065700000000001 According to me, the message length should be 40 but the exception rising is 808465456.
My CustomSerializer:
public class ModtelSerializerDeserializer extends AbstractByteArraySerializer {
private static final List<Integer> LV0_TOTAL_LENGTH = Arrays.asList(30, 40);
private static final int HEADER_SIZE_INT = 4;
private static final String ZERO_PAD = "00";
private int headerSize = HEADER_SIZE_INT;
public ModtelSerializerDeserializer() {
this(HEADER_SIZE_INT);
}
public ModtelSerializerDeserializer(int headerSize) {
if (headerSize != HEADER_SIZE_INT ) {
throw new IllegalArgumentException(String.format("Header size error: actual {}, expected : 4", headerSize));
}
}
public byte[] deserialize(InputStream inputStream) throws IOException {
final int headerRead = getHearderSizeFromInputStream(inputStream);
String lvReq = StringUtils.EMPTY;
if (LV0_TOTAL_LENGTH.contains(headerRead)) {
lvReq = parseData(inputStream,headerRead - HEADER_SIZE_INT);
StringBuilder builder = new StringBuilder();
builder.append(ZERO_PAD).append(headerRead).append(lvReq);
LOGGER.info("Deserializing request : {} ", builder.toString());
lvReq = builder.toString();
}else {
throw new IllegalArgumentException(String.format("Message to decode isn't of the expected length, expected %d or %d, actual : %d",
LV0_TOTAL_LENGTH.get(0), LV0_TOTAL_LENGTH.get(1), headerSize));
}
return lvReq.getBytes();
}
public void serialize(byte[] bytes, OutputStream outputStream) throws IOException {
outputStream.write(bytes);
outputStream.flush();
}
public String parseData(InputStream inputStream, int length) throws IOException {
StringBuilder builder = new StringBuilder();
int bite;
for (int i = 0; i < length; ++i) {
bite = inputStream.read();
this.checkClosure(bite);
builder.append((char) bite);
}
return builder.toString();
}
public String parseData(InputStream inputStream)
throws IOException {
StringBuilder textBuilder = new StringBuilder();
try (Reader reader = new BufferedReader(new InputStreamReader
(inputStream, Charset.forName(StandardCharsets.UTF_8.name())))) {
int bite = 0;
while ((bite = reader.read()) != -1) {
this.checkClosure(bite);
textBuilder.append((char) bite);
}
}
return textBuilder.toString();
}
private int getHearderSizeFromInputStream(InputStream inputStream) throws IOException {
final String value = parseData(inputStream, HEADER_SIZE_INT);
try
{
Integer.parseInt(value);
}
catch (NumberFormatException e)
{
throw new IllegalArgumentException(String.format("Header size is not integer as expected : actuel value {} ", value));
}
return Integer.valueOf(value.toString());
}
protected void checkClosure(int bite) throws IOException {
if (bite < 0) {
throw new IOException(String.format("Socket closed during message assembly byte is negative {} ", bite));
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.