2016-11-07 47 views
0

我知道Spring集成有TcpInboundGateway和ByteArrayStxEtxSerializer來處理通過TCP端口傳來的數據。一次性關閉套接字連接=假彈簧集成TCP服務器

如果TCP服務器需要讀取客戶端發送的所有數據並進行處理,則ByteArrayStxEtxSerializer的工作效果很好。 (請求和響應模型)我正在使用single-use = false,以便可以在同一個連接中處理多個請求。

例如,如果客戶端發送0x02AAPL0x03,則服務器可以發送AAPL價格。

如果客戶端發送0x02AAPL0x030x02GOOG0x03,我的TCP服務器正在工作。它發送AAPL和GOOG價格。

有時客戶端可以發送EOT(0x04)。如果客戶端發送EOT,我想關閉套接字連接。

例如:客戶端請求可以是0x02AAPL0x030x02GOOG0x03 0x020x040x03。注意EOT出現在最後一個數據包中。

我知道ByteArrayStxEtxSerializer解串器可以被定製來讀取客戶端發送的字節。

是解串器關閉套接字連接的好地方嗎?如果不是,應該如何通知Spring集成框架關閉套接字連接?

請幫忙。

這裏是我的Spring配置:

<int-ip:tcp-connection-factory id="crLfServer" 
     type="server" 
     port="${availableServerSocket}" 
     single-use="false" 
     so-timeout="10000" 
     using-nio="false" 
     serializer="connectionSerializeDeserialize" 
     deserializer="connectionSerializeDeserialize" 
     so-linger="2000"/> 

    <bean id="connectionSerializeDeserialize" class="org.springframework.integration.ip.tcp.serializer.ByteArrayStxEtxSerializer"/> 

    <int-ip:tcp-inbound-gateway id="gatewayCrLf" 
     connection-factory="crLfServer" 
     request-channel="serverBytes2StringChannel" 
     error-channel="errorChannel" 
     reply-timeout="10000"/> <!-- reply-timeout works on inbound-gateway --> 

    <int:channel id="toSA" /> 

    <int:service-activator input-channel="toSA" 
     ref="myService" 
     method="prepare"/> 

    <int:object-to-string-transformer id="serverBytes2String" 
     input-channel="serverBytes2StringChannel" 
     output-channel="toSA"/> 

    <int:transformer id="errorHandler" 
     input-channel="errorChannel" 
     expression="payload.failedMessage.payload + ':' + payload.cause.message"/> 

UPDATE: 添加拋出新SoftEndOfStreamException(「流關閉」)關閉在串行工作流,我可以看到關閉了事件監聽日誌條目。當服務器關閉連接時,我希望在客戶端接收java.io.InputStream.read()爲-1。但客戶端正在收到

java.net.SocketTimeoutException: Read timed out 
    at java.net.SocketInputStream.socketRead0(Native Method) 
    at java.net.SocketInputStream.read(SocketInputStream.java:129) 
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264) 
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306) 
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158) 
    at sun.nio.cs.StreamDecoder.read0(StreamDecoder.java:107) 
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:93) 
    at java.io.InputStreamReader.read(InputStreamReader.java:151) 

還有什麼要關閉服務器端的連接並將其傳播到客戶端?

我感謝你的幫助。

謝謝

回答

1

解串器無法訪問套接字,只是輸入流;關閉它可能會起作用,但你可能會在日誌中聽到很多噪音。

最好的解決辦法是拋出一個SoftEndOfStreamException;這表示應該關閉插座並清理所有東西。

編輯

添加一個監聽器,檢測/日誌關閉...

@SpringBootApplication 
public class So40471456Application { 

    public static void main(String[] args) throws Exception { 
     ConfigurableApplicationContext context = SpringApplication.run(So40471456Application.class, args); 
     Socket socket = SocketFactory.getDefault().createSocket("localhost", 1234); 
     socket.getOutputStream().write("foo\r\n".getBytes()); 
     socket.close(); 
     Thread.sleep(10000); 
     context.close(); 
    } 

    @Bean 
    public EventListener eventListener() { 
     return new EventListener(); 
    } 

    @Bean 
    public TcpNetServerConnectionFactory server() { 
     return new TcpNetServerConnectionFactory(1234); 
    } 

    @Bean 
    public TcpReceivingChannelAdapter inbound() { 
     TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); 
     adapter.setConnectionFactory(server()); 
     adapter.setOutputChannelName("foo"); 
     return adapter; 
    } 

    @ServiceActivator(inputChannel = "foo") 
    public void syso(byte[] in) { 
     System.out.println(new String(in)); 
    } 

    public static class EventListener implements ApplicationListener<TcpConnectionCloseEvent> { 

     private final Log logger = LogFactory.getLog(getClass()); 

     @Override 
     public void onApplicationEvent(TcpConnectionCloseEvent event) { 
      logger.info(event); 
     } 

    } 

} 

在XML中,只需添加一個<bean/>爲您的監聽器類。

結果:

foo 
2016-11-07 16:52:04.133 INFO 29536 --- [pool-1-thread-2] c.e.So40471456Application$EventListener : TcpConnectionCloseEvent 
[source=org[email protected]118a7548], 
[factory=server, connectionId=localhost:50347:1234:b9fcfaa9-e92c-487f-be59-1ed7ebd9312e] 
**CLOSED** 

EDIT2

它的工作如預期的我...

@SpringBootApplication 
public class So40471456Application { 

    public static void main(String[] args) throws Exception { 
     ConfigurableApplicationContext context = SpringApplication.run(So40471456Application.class, args); 
     Socket socket = SocketFactory.getDefault().createSocket("localhost", 1234); 
     socket.getOutputStream().write("foo\r\n".getBytes()); 
     try { 
      System.out.println("\n\n\n" + socket.getInputStream().read() + "\n\n\n"); 
      context.getBean(EventListener.class).latch.await(10, TimeUnit.SECONDS); 
     } 
     finally { 
      socket.close(); 
      context.close(); 
     } 
    } 

    @Bean 
    public EventListener eventListener() { 
     return new EventListener(); 
    } 

    @Bean 
    public TcpNetServerConnectionFactory server() { 
     TcpNetServerConnectionFactory server = new TcpNetServerConnectionFactory(1234); 
     server.setDeserializer(is -> { 
      throw new SoftEndOfStreamException(); 
     }); 
     return server; 
    } 

    @Bean 
    public TcpReceivingChannelAdapter inbound() { 
     TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); 
     adapter.setConnectionFactory(server()); 
     adapter.setOutputChannelName("foo"); 
     return adapter; 
    } 

    public static class EventListener implements ApplicationListener<TcpConnectionCloseEvent> { 

     private final Log logger = LogFactory.getLog(getClass()); 

     private final CountDownLatch latch = new CountDownLatch(1); 

     @Override 
     public void onApplicationEvent(TcpConnectionCloseEvent event) { 
      logger.info(event); 
      latch.countDown(); 
     } 

    } 

} 

結果:

2016-11-08 08:27:25.964 INFO 86147 --- [   main] com.example2.So40471456Application  : Started So40471456Application in 1.195 seconds (JVM running for 1.764) 



-1 



2016-11-08 08:27:25.972 INFO 86147 --- [pool-1-thread-2] c.e.So40471456Application$EventListener : TcpConnectionCloseEvent [source=org[email protected]fee3774], [factory=server, connectionId=localhost:54984:1234:f79a6826-0336-4823-8844-67054903a094] **CLOSED** 
+0

這聽起來不錯。框架在關閉連接時是否記錄日誌?想看看什麼時候它在日誌中關閉(最好是使用threadId。) – kevin

+0

沒有日誌記錄「SoftEndOfStreamException」,因爲它被認爲是「正常」關閉。然而,你可以添加一個'ApplicationListener',它將在調用你的解串器的同一個線程上被調用。我用一個例子編輯了我的答案。 –

+0

ApplicationListener非常有用。非常感謝。 – kevin

相關問題