Results 1 to 10 of 12

Thread: Simple TCP Client - Spring Integration ( Not connecting)

Hybrid View

  1. #1

    Default Simple TCP Client - Spring Integration ( Not connecting)

    I am trying to simulate following simple tcp client which connect to a socket and reads the data when available and prints.
    Code:
    public class TestAdapter {
    	public static void main(String[] args) throws IOException {
    		Socket socket = null;
    		PrintWriter out = null;
    		BufferedReader in = null;
    
    		try {
    			socket = new Socket("localhost ", 11111);
    			boolean state = socket.isConnected();
    			if( state) 
    				System.out.println("Successfuly connected ");
    			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    		} catch (UnknownHostException e) {
    			System.err.println("Don't know about host: localhost.");
    			System.exit(1);
    		} catch (IOException e) {
    			System.err.println("Couldn't get I/O for " + "the connection to: localhost.");
    			System.exit(1);
    		}
    
    		String userInput;
    	
    		while ((userInput = in.readLine()) != null) {
    			System.out.println("echo: " + userInput);
    		}
    
    		out.close();
    		in.close();
    		socket.close();
    	}
    
    }
    With the following configuration, test method on PrintService is not getting invoked when there is some bytes available.
    Can anyone help me correct these settings if anything wrong?

    Code:
    <int:channel id="inputChannel"/> 
    <ip:tcp-inbound-channel-adapter id="tcpInboundAdapter" 
    	                               	channel="inputChannel" 
    	                               	connection-factory="client" 
    	                           	client-mode="true"  /> 
    <ip:tcp-connection-factory id="client" 
    				type="client"
    				host="localhost"
    				port="11111" 
    				single-use="false"
    				using-nio="true"
    				using-direct-buffers="false"
    				pool-size="2"
    				so-keep-alive="true"
    				so-timeout="0"/>
    <int:service-activator id="activator"
                   		   input-channel="inputChannel"
    	   		   ref="printService"
    	   		   method="test"/>
    <bean id="printService" class="com.springintegration.print.PrintService" />
    Code:
    public class PrintService {
    	public void test(byte[] bytes) {
    		System.out.println("Received:" + new String(bytes) );
    	}
    }
    from the debug log, connection seems to be established, but the service activator is not invoking test method on PrintService

    Code:
    01/19 15:25:00,486 DEBUG [main] DefaultLifecycleProcessor} - Successfully started bean 'tcpInboundAdapter'
    01/19 15:25:00,586 DEBUG [ThreadPoolTaskScheduler-1] TcpNioClientConnectionFactory} - Opening new socket channel connection to localhost:11111
    01/19 15:25:00,622 DEBUG [ThreadPoolTaskScheduler-1] ClientModeConnectionManager} - Connection dell271:11111:79d7e264-d1bb-4b93-8d1b-ffa5c13e9b94 established
    01/19 15:25:15,374 DEBUG [pool-1-thread-2] TcpNioConnection} - dell271:11111:79d7e264-d1bb-4b93-8d1b-ffa5c13e9b94 Reading...
    01/19 15:25:15,374 DEBUG [pool-1-thread-2] TcpNioConnection} - Read 3251 into raw buffer
    Last edited by pkbhavani; Jan 19th, 2012 at 03:48 PM.

  2. #2
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,020

    Default

    You need some structure to the message to tell the adapter when a complete message has been received.

    TCP is a streaming protocol; Spring Integration (SI) is a messaging system, we need some way to tell SI when a full message has been completely received.

    I see you are using BufferedReader.readLine() in your example, which returns if only '\n', '\r', or '\r\n'. Depending on the sending side, you may only be sending, say, '\n'.

    The connection factory has an attribute 'deserializer' which tells us how to interpret the data, and produce a Message object. The default deserializer expects a carriage return + linefeed ('\r\n') at the end of the data; but other deserializers are available - see the reference documentation...

    http://static.springsource.org/sprin...tion-factories

    The provided classes implement both serializer and deserializer functionality. We don't currently have an implementation that only uses '\n'.

    For very simple applications, where the client sends a message and then closes the socket, you can use a ByteArrayRawSerializer which uses the socket closure to signal the end of the message.

    For applications that send more than one message on the same socket, you need some mechanism to demarcate the messages. If one of the standard (de)serializers are not sufficient, you can write your own and set it in the deserializer attribute. If this is the case, you might want to look at one of the standard (de)serializers and, perhaps, make yours a subclass of AbstractByteArraySerializer.

    Hope that helps.
    Last edited by Gary Russell; Jan 19th, 2012 at 04:19 PM.
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

  3. #3

    Default

    thank you so much for your reply, I am trying to figure out how to plugin the serializer/deserializer for this use case.
    I changed configuration with serializer interceptor, but deserialize and serialize methods in my custom ByteArrayCrLfSerializer is being invoked. still seeing the same output with no change.

    can you please see if this configuration is infact could address the above plain old java sample tcp listener.

    Code:
    <bean id="serializer" class="com.springintegration.print.ByteArrayCrLfSerializer" />
    
    <int:channel id="inputChannel"/>
     
    <ip:tcp-inbound-channel-adapter id="tcpInboundAdapter" 
    	                               	channel="inputChannel" 
    	                               	connection-factory="client" 
    	                           	client-mode="true"  /> 
    
    <ip:tcp-connection-factory id="client" 
    				type="client"
    				host="localhost"
    				port="11111" 
    				single-use="false"
    				using-nio="true"
    				using-direct-buffers="false"
    				pool-size="2"
    				so-keep-alive="true" 
                                    deserializer="serializer"
                                    serializer="serializer"
    				so-timeout="0"/>
    
    <int:service-activator id="activator"
                   		   input-channel="inputChannel"
    	   		   ref="printService"
    	   		   method="test"/>
    
    <bean id="printService" class="com.springintegration.print.PrintService" />

  4. #4

    Default

    changed the setting with using-nio=false, now seems to be working. Here is the complete configuration for any one looking this kind of example. I have no idea if rest of the setting are needed or not for tcp-connection-factory.

    Code:
    	<bean id="serializer" class="org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer" />
      	
    	<int:channel id="inputChannel"/> 
    	<int:channel id="outputChannel"/>
    	
    	<ip:tcp-inbound-channel-adapter id="tcpInboundAdapter" 
    		                           	channel="inputChannel" 
    		                           	connection-factory="client"  
    		                           	client-mode="true"  /> 
    		                           	
    	<ip:tcp-connection-factory id="client" 
    					type="client"
    					host="localhost"
    					port="11111" 
    					single-use="false"
    					using-nio="false"
    					using-direct-buffers="false"
    					pool-size="2"
    					so-keep-alive="true" deserializer="serializer" serializer="serializer"
    					so-timeout="0"/>
    					
    	<int:service-activator id="activator"
    	               input-channel="inputChannel"
    		   		   ref="printService"/>
    		   		   
    	<bean id="printService" class="com.springintegration.print.TcpListener" />
    TcpListener class
    Code:
    @Component
    public class TcpListener {
    	@ServiceActivator
    	public void handleTcp(Message<?> message) {
    		System.out.println("*** TCP Message: " + message);
    		System.out.println("*** TCP Message Payload: " + new String((byte[]) message.getPayload()));
    	}
    }

  5. #5
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,020

    Default

    Do you mean "is NOT being invoked"?

    Can you run with a TRACE level log and attach it?

    I just modified the tcp-client-server sample like this...

    Code:
    	<ip:tcp-connection-factory id="client"
    		type="client"
    		host="localhost"
    		port="11111"
    		so-timeout="10000"
    		using-nio="true"
            />
    	
    	<ip:tcp-inbound-channel-adapter id="inbound"
    		connection-factory="client"
    		client-mode="true"
    		channel="serverBytes2StringChannel" />
    	
    	<transformer id="serverBytes2String"
    		input-channel="serverBytes2StringChannel"
    		output-channel="toSA" 
    		expression="new String(payload)"/>
    
    	<channel id="toSA" />
    
    	<service-activator input-channel="toSA"
    					   output-channel="stdout"
    					   ref="echoService"
    					   method="test" />
    
    	<int-stream:stdout-channel-adapter id="stdout" append-newline="true" />
    
    	<beans:bean id="echoService" 
    		  class="org.springframework.integration.samples.tcpclientserver.EchoService" />
    Code:
    @ContextConfiguration("/META-INF/spring/integration/tcpClientServerDemoX-context.xml")
    @RunWith(SpringJUnit4ClassRunner.class)
    public class TcpClientServerDemoClientModeTest {
    
    	@Test
    	public void testHappyDay() throws Exception {
    		ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(11111);
    		Socket sock = server.accept();
    		sock.getOutputStream().write("Hello, world!\r\n".getBytes());
    		Thread.sleep(1000);
    		sock.close();
    		server.close();
    	}
    And everything worked as expected...

    Code:
    echo:Hello, world!
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

  6. #6
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,020

    Default

    As you can see 'using-nio="true"' worked fine for me. I'd like to see a TRACE log if possible; I'd like to understand why you are seeing this problem.

    In the past, we have found some subtle differences in operating systems. What OS are you running on?

    Thanks.
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

  7. #7
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,020

    Default

    I think the problem is that your pool-size is too small; I would suggest a minimum of 3. I think what's happening is you have data to assemble into a message, but there are no threads available to consume it and the thread that's reading from the port is blocked waiting for some of the data to be consumed before it can continue. One thread is always reserved to handle socket events.

    We should probably change the documentation to suggest a minumum pool-size of 3.
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •