Hot questions for Using Transmission Control Protocol in connection

Question:

I have been through this and understood that I need to create a TcpReceivingChannelAdapter to accept connections. But I don't know how to proceed with that.

Could someone guide me over this?


Answer:

See the tcp-client-server sample for some pointers using XML configuration.

For Java configuration; here's a simple Spring Boot app...

package com.example;

import java.net.Socket;

import javax.net.SocketFactory;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.annotation.Transformer;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.ip.tcp.TcpReceivingChannelAdapter;
import org.springframework.integration.ip.tcp.connection.AbstractServerConnectionFactory;
import org.springframework.integration.ip.tcp.connection.TcpNetServerConnectionFactory;
import org.springframework.integration.transformer.ObjectToStringTransformer;
import org.springframework.messaging.MessageChannel;

@SpringBootApplication
public class So39290834Application {

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

    @Bean
    public TcpNetServerConnectionFactory cf() {
        return new TcpNetServerConnectionFactory(9999);
    }

    @Bean
    public TcpReceivingChannelAdapter inbound(AbstractServerConnectionFactory cf) {
        TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
        adapter.setConnectionFactory(cf);
        adapter.setOutputChannel(tcpIn());
        return adapter;
    }

    @Bean
    public MessageChannel tcpIn() {
        return new DirectChannel();
    }

    @Transformer(inputChannel = "tcpIn", outputChannel = "serviceChannel")
    @Bean
    public ObjectToStringTransformer transformer() {
        return new ObjectToStringTransformer();
    }

    @ServiceActivator(inputChannel = "serviceChannel")
    public void service(String in) {
        System.out.println(in);
    }

}

Question:

My unsertanding

Without NIO: For every keepAlive connection server continue to block a thread.

With NIO: This connector has a couple of poller threads used to keep the connection alive for all connected users while worker threads are called whenever data (a new HTTP request) is available

Now: If i have a simple servlet which return a 100 KB string to client(browser).

....
String HunderdKBString = "reallylongstring"
PrintWriter out = response.getWriter();
out.println(HunderdKBString);
....

If a client with 1 KB connection connects then it will take around 100 Sec to receive the string. So is it that the java thread will be blocked for around 100 sec?

How does TCP buffer, Java OutputStream or Writer or other buffers affects the thread block time?

PS: using apache-tomcat-8.0.24 in centos 7 with oracle JDK 1.7.

EDIT: As mentioned thread does get blocked and buffer can reduce thread block time.. How to optimism tomcat/OS to reduce thread block time by using these buffer?

How one can detect in production environment if tomcat is starving of thread due to many slow connection client connected to it?


Answer:

So is it that the java thread will be blocked for around 100 sec?

Yes.

How does TCP buffer, Java OutputStream or Writer or other buffers affect the thread block time?

If the buffer is large enough to hold the sent data, the sending thread won't block.

Question:

I've been reading this socket tutorial by Oracle and stumbled upon the following text:

If everything goes well, the server accepts the connection. Upon acceptance, the server gets a new socket bound to the same local port and also has its remote endpoint set to the address and port of the client. It needs a new socket so that it can continue to listen to the original socket for connection requests while tending to the needs of the connected client.

Now if I'm not wrong then the port size is 16 bit which limits the max no of ports around 65K. This means that a server can't handle more than 65535 connections at any instant if all of it's port are bound to some client local port. While some answers like this on stackoverflow suggest that there's no limit on active connections. What is true about this and what is wrong?

Edit 1: If indeed a server can't handle more than 2^16-1 connections, then how do websites like Google handle this limitation?


Answer:

A unique TCP connection is defined by a unique combination of client IP, client port, server IP and server port. For a specific service server IP and port are constant (i.e. port 80 for HTTP), but client IP and port can vary. Since the port range is only 1..65535 this means that the server can only handle at most 65535 different connections from the same client IP address at the same time, because these are all possible unique combinations of the connection tuple when only the port can be changed. But, if there are multiple clients with different IP addresses this limitations applies to each of these clients separately. If you then look at the amount of different possible IP addresses (IPv4 and IPv6) you'll see that there is essentially no real limit of how much connections the server could handle in theory.

In practice each of these TCP connections takes memory at the server since the current state has to be kept. Additional memory is needed in kernel and application for file descriptor and application protocol state etc. This means that there is a practical limit based on the resources of the machine which might be less then 64k but also way more, depending on the system and its configuration.

Question:

After reading all sort of docs on Java HttpURLConnection, I'm still quite confused as what kind of pooling it does and how it hands connections.

For example, the following code

URL url = new URL(someUrl);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
OutputStream os = connection.getOutputStream();
InputStream is = connection.getInputStream();

/** Write something to os and flush */
/** Read from is */

os.close();
is.close();
connection.disconnect();
  1. Do both os and is need to be flushed and closed for the underlying socket to be reusable?

  2. Will connection.disconnect() close the underlying socket (and hence make it unreusable)? Does keep-alive affect this behavior?

  3. If I use different URL objects, but with the same URL, will the connections created from them share the underlying sockets? How about when the host part of the URL is the same, but paths are different?

  4. When will pooled connections be destroyed?

  5. What's the system property that controls the size of the pool?

Additionally, if you could also compare the Android version with Java it would be great.

Thanks


Answer:

  1. Do both os and is need to be flushed and closed for the underlying socket to be reusable?

Closing the input stream is sufficient. You can't flush an input stream, and flushing an output stream before close is redundant.

  1. Will connection.disconnect() close the underlying socket (and hence make it unreusable)?

It 'acts as a hint' to close the underlying connection.

Does keep-alive affect this behavior?

Yes. If it isn't present, the connection must be closed.

  1. If I use different URL objects, but with the same URL, will the connections created from them share the underlying sockets?

Yes.

How about when the host part of the URL is the same, but paths are different?

Yes.

  1. When will pooled connections be destroyed?

After an idle timeout.

  1. What's the system property that controls the size of the pool?

I'm not aware that there is one, but if there is it will be defined in the Networking Properties page which you can find via the Javadoc.

Additionally, if you could also compare the Android version with Java it would be great.

I believe that Android doesn't do pooling at all, but this should change when they switch to the OpenJDK source.

Question:

I am trying to make a client send a request to a server and receive a response whilst keeping to connection up.

If i close the socket:

//server side
outToClient.writeBytes("Message to send");
connectionSocket.close();

//client side
serverResponse = inFromServer.readLine(); 
System.out.println("FROM SERVER: " + serverResponse);

Output on client side

FROM SERVER: Message to send

And after that the connection is lost, obviously.

If i do not close the socket:

//server side
outToClient.writeBytes("Message to send");

//client side
serverResponse = inFromServer.readLine(); 
System.out.println("FROM SERVER: " + serverResponse);

No output on client side. The server never sends the message or the client never receives it.

Anyone knows a possible reason for this to be happening? The client uses a thread to receive messages and a thread to send messages. The client socket is created in the main client thread so receiver and sender threads use the current socket to communicate.

Thanks in advance.


Answer:

If the client expects to read a line, the server should write a line. A line is terminated by a \n character.

It may also be necessary to flush the stream you are using to send data to the client:

outToClient.writeBytes("Message to send\n");
outToClient.flush();

Without seeing the code it's hard to say if the flush is required or not.

Question:

I would like to use Java Netty to create a TCP server for a large number of persistent connections from a clients. In other words, imaging that there are 1000 client devices out there, and all of them create and maintain a persistent connection to the TCP server. There will be a reasonable amount of traffic (mostly lines of text) that go back and forth across each of these persistent connections. How can I determine the best number of threads to use in the boss and worker groups for NioEventLoopGroup?

My understanding is that when the connection is created, Netty creates a SimpleChannelInboundHandler<String> object to handle the connection. When the connection is created then the handler channelActive method is called, and every time it gets a new message from the client, the method messageReceived gets called (or channelRead0 method in Netty 4.0.24).

  1. Is my understanding correct?

  2. What happens if I have long running code to run in messageReceived - do I need to launch this code in yet another thread (java.util.Thread)?

  3. What happens if my messageReceived method blocks on something or takes a long time to complete? Does that bring Netty to a grinding halt?

Basically I need to write a TCP socket server that can serve a large number of persistent connections as quickly as possible.

  1. Is there any guidance available on number of threads for NioEventLoopGroup and on how to use any threads inside the handler?

Any help would be greatly appreciated.


Answer:

How can I determine the best number of threads to use in the boss and worker groups for NioEventLoopGroup?

  • About Boss Thread,if you are saying that you need persistent connections , there is no sense to use a lot of boss threads, because boss threads only responsible for accepting new connections. So I would use only one boss thread.
  • The number of worker threads should depends on your processor cores.

Don't forget to add -XmsYYYYM and -XmxYYYYM as your VM attributes, because without them you can face the case, when your JVM are not using all cores.

What happens if I have long running code to run in messageReceived - do I need to launch this code in yet another thread (java.util.Thread)?

  • Do you really need to do it? Probably you should think of doing your logic another way, if not then probably you should consider OIO with new thread for each connection.

What happens if my messageReceived method blocks on something or takes a long time to complete?

  • You should avoid using thread blocking actions in your handlers.

Does that bring Netty to a grinding halt?

  • Yep, it does.

Question:

I am new to Spring Boot but have been requested by my job to implement a small web service using spring boot.

The web service needs to accept SSL TCP connections (an external system will connect to my web service using a custom protocol - NOT HTTP). Also, I would like to handle these connections in a background task (or multiple background tasks).

After looking at the official documentation (http://docs.spring.io/spring-integration/reference/html/ip.html), I still don't understand (where do I place all that XML). When I asked on SO about where to place that XML, I was answered that this is a very old method of configuration and should not be used anymore.

What would be the "up-to-date" way to do this ?


Answer:

@SpringBootApplication
public class So43983296Application implements CommandLineRunner {

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(So43983296Application.class, args);
        Thread.sleep(10_000);
        context.close();
    }

    @Autowired
    private DefaultTcpNetSSLSocketFactorySupport ssl;

    @Override
    public void run(String... args) throws Exception {
        Socket socket = ssl.getSocketFactory().createSocket("localhost", 1234);
        socket.getOutputStream().write("foo\r\n".getBytes());
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String result = br.readLine();
        System.out.println(result);
        br.close();
        socket.close();
    }

    @Bean
    public TcpNetServerConnectionFactory scf() {
        TcpNetServerConnectionFactory scf = new TcpNetServerConnectionFactory(1234);
        DefaultTcpNetSSLSocketFactorySupport tcpSocketFactorySupport = tcpSocketFactorySupport();
        scf.setTcpSocketFactorySupport(tcpSocketFactorySupport);
        // Add custom serializer/deserializer here; default is ByteArrayCrLfSerializer
        return scf;
    }

    @Bean
    public DefaultTcpNetSSLSocketFactorySupport tcpSocketFactorySupport() {
        TcpSSLContextSupport sslContextSupport = new DefaultTcpSSLContextSupport("classpath:test.ks",
                "classpath:test.truststore.ks", "secret", "secret");
        DefaultTcpNetSSLSocketFactorySupport tcpSocketFactorySupport =
                new DefaultTcpNetSSLSocketFactorySupport(sslContextSupport);
        return tcpSocketFactorySupport;
    }

    @Bean
    public TcpInboundGateway inGate() {
        TcpInboundGateway inGate = new TcpInboundGateway();
        inGate.setConnectionFactory(scf());
        inGate.setRequestChannelName("upperCase");
        return inGate;
    }

    @ServiceActivator(inputChannel = "upperCase")
    public String upCase(byte[] in) {
        return new String(in).toUpperCase();
    }

}

If you prefer XML configuration for Spring Integration, add it to a spring configuration xml file and use @ImportResource("my-context.xml") on the class.

Question:

I'm working with Java NIO and this is my first time setting up a working TCP connection (I've only done UDP up until this point and a simple TCP test program a long time ago).

Right now, I'm unsure the exact moment where I can reliably start sending data to the clients such that they know there is an active connection on the other end (assuming something hasn't gone wrong).


Assume everything is non-blocking.

CLIENT:

1) Open a new socket channel with no bindings so it can be set to async

s = SocketChannel.open()

2) Set it to be non-blocking

s.configureBlocking(false)
  • Do we need to bind here? Or is that just for if we want to refer to a local port?

3) Attempt to connect to a server that is listening

s.connect(someAddr)
  • If this returns true, the javadocs say the connection is established. Does that mean I don't need to call finishConnect()? From what I read, this is for local connections, but it does not specify if remote connections could possibly return true immediately or not.

  • Is this where the client sends a SYN to the server?


SERVER:

4) Server gets an incoming connection through some serverSocketChannel.accept(), which we assume is non blocking and will pretend in this case it returns a valid socket object (and not null).

  • Does this mean that as soon as the server gets the connection, it accepted the connection (assuming all went well) and sends back a SYN-ACK?

CLIENT:

5) Does the client call finishConnect() now?

  • When does the client know when to keep calling finishConnect()? Do I just loop for X seconds immediately after calling s.connect(...) from step (3)?

  • Is this when it sends the ACK? Am I supposed to loop for X seconds until it returns true... and kill the 'half formed connection' if it doesn't respond within X seconds due to something going wrong?

  • Does s.isConnected() return true for the connect() in step (3) succeeding, or finishConnect() succeeding?


I'm not sure if I'm doing this properly, and I'm also not sure at what point is it safe for the server to send, or the client to send... is it at (4) for the server, and (5) for the client?

Do I need to have the client send a heartbeat packet after the connection is done to the server so my application knows it's okay to start sending data? I don't know how the server would know it's fully connected since I can't see any way the server would know when the final acknowledgement is done... except for the client knowing the connection is established and it sends some kind of 'first packet' data.

The only way the server would know is if I can somehow figure out when it gets the ACK packet, but I can't see a way of Java letting me know currently.

NOTE: I may be missing knowledge, I may have said some incorrect stuff, if you can point out where they are wrong I'd be more than glad to update my post so it's factually correct.

Links that guided my knowledge/creation of this post:

TCP protocol

SocketChannel Javadocs


Answer:

Do we need to bind here? Or is that just for if we want to refer to a local port?

You don't need to bind the client SocketChannel.

s.connect(someAddr)

If this returns true, the javadocs say the connection is established. Does that mean I don't need to call finishConnect()?

Correct.

From what I read, this is for local connections, but it does not specify if remote connections could possibly return true immediately or not.

It can return true any time, you have to check.

Is this where the client sends a SYN to the server?

Yes.

Server gets an incoming connection through some serverSocketChannel.accept(), which we assume is non blocking and will pretend in this case it returns a valid socket object (and not null). Does this mean that as soon as the server gets the connection, it accepted the connection (assuming all went well) and sends back a SYN-ACK?

No. The SYN-ACK has already been sent by the TCP/IP stack. It doesn't depend on when the application code calls accept().

Does the client call finishConnect() now?

Again this doesn't depend on when the server application called accept. The TCP handshake is completed by the server kernel. The client should call finishConnnect() if connect() didn't return true and a subsequent select() indicates that the channel is now connectable.

Note that finishConnect() can return true, in which case you just proceed, or false, in which case you just keep waiting for OP_CONNECT, or throw an exception, in which case it failed and you should close the channel.

When does the client know when to keep calling finishConnect()? Do I just loop for X seconds immediately after calling s.connect(...) from step (3)?

See above.

Is this when it sends the ACK?

No. That is all done by the kernel asynchronosusly

Am I supposed to loop for X seconds until it returns true... and kill the 'half formed connection' if it doesn't respond within X seconds due to something going wrong?

No, see above.

Does s.isConnected() return true for the connect() in step (3) succeeding, or finishConnect() succeeding?

Both: they're mutually exclusive.

I'm not sure if I'm doing this properly, and I'm also not sure at what point is it safe for the server to send, or the client to send... is it at (4) for the server, and (5) for the client?

The server can send as soon as it has an accepted socket. The client can send as soon as either connect() or finishConnect() returns true.

Do I need to have the client send a heartbeat packet after the connection is done to the server so my application knows it's okay to start sending data?

No.

I don't know how the server would know it's fully connected since I can't see any way the server would know when the final acknowledgement is done... except for the client knowing the connection is established and it sends some kind of 'first packet' data.

See above. The idea of sending a packet to see if you can send a packet doesn't make sense.

The only way the server would know is if I can somehow figure out when it gets the ACK packet

The server already has the ACK packet when accept() returns.

NOTE: I may be missing knowledge ...

What you're overlooking is the existence of the listen backlog queue at the server.

Question:

My sql server engine is using dynamic TCP port, e.g., 52358. I can do JDBC query without any problem if I specified the port number 52358 in my JDBC DB url connection string, i.e.,

jdbc:sqlserver://serverName:52358;databaseName=myDB

However, since this is dynamic port, sql server might choose another port if this port (52358) becomes unavailable after you restart sql server next time.

So what's best way to configure my DB URL in the connection string?


Approach I have tried:

Omitting the port number and using only the instance name, i.e.,

jdbc:sqlserver://serverName;databaseName=myDB

This doesn't work. By the way, sql server browser service is already enabled.


Solution found (thanks to Gord Thompson). The complete form of DB URL is:

jdbc:sqlserver://[serverName[\instanceName][:portNumber]][;property=value[;property=value]]

where either the portNumber or instanceName may be used to connect to serverName. However,

If both a portNumber and instanceName are used, the portNumber will take precedence and the instanceName will be ignored.

Therefore, for the case of dynamic port, we should only use instanceName for connection and keep the SQL Browser service running (SQL Server provides the SQL Server Browser Service, to monitor the ports, and direct incoming connections to the current port for that instance). Thus, in my case, the correct form is:

jdbc:sqlserver://serverName\instanceName;databaseName=myDB

Also, we should keep in mind that

For optimal connection performance, you should set the portNumber when you connect to a named instance. This will avoid a round trip to the server to determine the port number

Then this will call for a static port number.


Answer:

If you really cannot count on the port number remaining constant then you will have to connect using the SQL Server instance name.

Default instance:

jdbc:sqlserver://servername\MSSQLSERVER;...

Named instance

jdbc:sqlserver://servername\instancename;...

Of course, this means that the SQL Browser service must be running on the server so the instance name can be resolved to the actual port number currently being used.

Question:

I have a PCan wireless device that can play the role as which they called "Micro Access Point". The concept is to make it router and other devices connect to it. With this connection I can send/receive CAN frames using TCP or UDP. The main Goal is to connect to this Wifi and open a socket and send/ receive TPC/UPD frames in android M.

I wrote an android activity which search for all available Wifis and connects to it with a button which i can connect successfully.

After connection I tried to open a socket but it failed. I tried it also with different timeouts:

button2.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        new Thread(new Runnable() {
            @Override
            public void run() {

                for (int i = 0; i <= 255; ++i) { // I wrote this for loop to check all possibilities!
                    String ip = "192.168.1." + i;
                    try {
                        Log.i(TAG, "Try ip: " + ip);
                        Socket socket = new Socket();
                        socket.connect(new InetSocketAddress(ip, 50000), 100);
                        Log.e(TAG, "Connected!");
                    } catch (IOException e) {
                        Log.e(TAG, "Exception is catched!");
                    }
                }

            }
        }).start();
    }
});

Can somebody tell me how to open a socket? Here are the infos on the device:

ip: 192.168.1.10

port: 50000

gateway:192.168.1.199

UPDATE:

I don't know if I am on the right way to overcome this problem. Very short to say: I want to connect to this wireless device and send/receive tcp and UPD frames. Unfortunately I have a very limited knowledge on networking.


Answer:

It seems that the wireless router only accepts the static IPs. Using a static IP and gateway solved the problem.

Question:

buyerSocket = new ServerSocket(BUYER_PORT);
sellerSocket = new ServerSocket(SELLER_PORT);
Socket clientSocket = null;
while (true)
    {
        clientSocket = sellerSocket.accept();
        MultiServerThread x = new MultiServerThread(clientSocket, dat);
        x.start();

        clientSocket = buyerSocket.accept();
        MultiServerThread y = new MultiServerThread(clientSocket, dat);
        y.start();

    }

In this block of code, it always waits for the sellerSocket to connect first before accepting buyerSocket. Could anyone suggest a way to accept whichever come first?

As for the description of accept() - Listens for a connection to be made to this socket and accepts it. The method blocks until a connection is made. Should I use another method instead of accept() if I want to accept connection from multiple ports?


Answer:

You have to use Non Blocking IO (NIO) library for this. You can follow this nice tutorial http://tutorials.jenkov.com/java-nio/index.html

Question:

I have made a small telnet-like application, and currently the only way i know if two sockets cannot communicate is when a SocketException is thrown with the message "Connection reset" (when i poll for input). It doesn't produce a problem in my application however, since i can catch the exception, but is there a way for me to test if the connection has been reset before i poll for input, or is catching the exception the only way? Methods have to be a part of the Java API (no 3. parties).

No methods of the Socket class seems to be able to answer this, and i haven't been able to find anything on the web.


Answer:

The only way to detect anything wrong with a TCP connection is to write to it or read from it.

Question:

I'm new on Android platform, coming from .NET world. I need to write a TCP/SSL client class in my app, which send/recieve text messages with some Java server. I also need to use server public certificate (.cer file) in that communication. In C# I have SSLStream class that do all the job, and a lot of examples for it. However for Android (Lolipop) I cannot find any good examples on this subject, especially without http protocol on top. Any hint would be appreciated.


Answer:

Below is basially steps to create ssl connection in android :

Step 1 : Get public key of ur server (.cert file), which you already have.

Step 2: Create keystore via bouncycastle jar

Below is commands :

keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/myKeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret

Verify if the certificates were imported correctly into the keystore:

keytool -list -keystore "res/raw/myKeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret

Should output the whole chain:

RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43

Now you can copy the keystore as a raw resource in your android app under res/raw/

Step 3:

Create HttpsClient like below and query you service with this client only :

public class HttpsClient extends DefaultHttpClient {

    final Context context;

    public HttpsClient(Context context) {
        this.context = context;
    }

    @Override
    protected ClientConnectionManager createClientConnectionManager() {
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory
                .getSocketFactory(), 80));
        // Register for port 443 our SSLSocketFactory with our keystore
        // to the ConnectionManager
        registry.register(new Scheme("https", newSslSocketFactory(), 443));
        return new SingleClientConnManager(getParams(), registry);
    }

    private SSLSocketFactory newSslSocketFactory() {
        try {
            // Get an instance of the Bouncy Castle KeyStore format
            KeyStore trusted = KeyStore.getInstance("BKS");
            // Get the raw resource, which contains the keystore with
            // your trusted certificates (root and any intermediate certs)
            InputStream in = context.getResources().openRawResource(
                    R.raw.mykeystore);
            try {
                // Initialize the keystore with the provided trusted
                // certificates
                // Also provide the password of the keystore
                trusted.load(in, "mysecret".toCharArray());
            } finally {
                in.close();
            }
            // Pass the keystore to the SSLSocketFactory. The factory is
            // responsible
            // for the verification of the server certificate.
            SSLSocketFactory sf = new SSLSocketFactory(trusted);
            // Hostname verification from certificate
            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            return sf;
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}

The Above Case holds true for connection over http , if you need to have connection without http , the keystore procedure remains the same and you need to use sockets to open and close the connection :

String keyStorePath = "absolute path to your JKS keystore file";
String keyStorePass = "keystore password";

System.setProperty("javax.net.ssl.keyStore", keyStorePath);
System.setProperty("javax.net.ssl.keyStorePassword", keyStorePass);

SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket serverSocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(port_number);

while (true) {
    new ClientThread((SSLSocket) serverSocket.accept()).start();
}

Question:

On an Android device, I want to create a tcp communication on a local network with a device that I know only the mac address (no the ip). There is a way to start the communication with only the mac address or, alternatively, to find directly the ip associated without scan all network looking for the device? Thank you very much


Answer:

To deliver ip address of your server to a client you can send broadcast UDP packet from server. The flow could look like this:

  1. Server opens TCP port and waits for TCP clients.
  2. Server sends broadcast UDP packet with specific data ( something which says that this packet is from your server )
  3. If there is a client in the same network it receives the packet. The client reads data, checks that the packet is from your server. This packet also has ip address of your server.
  4. That is all: now client knows ip address and port, it connects through TCP to your server.
  5. Server accepts new client. Connection is done.

Here is sample of how UDP packet could be sent and received: https://stackoverflow.com/a/25520279/798165

Question:

I have a Python TCP Socket server service which:

  • Allows only one client connection at time;
  • Its inputstream/outputstream operates independently.

On the other side, I have a Java Spring Boot client application using Spring Integration. My actual TCP Socket configurator implementation uses:

@MessagingGateway(defaultRequestChannel = REQUEST_CHANNEL, errorChannel = ERROR_CHANNEL)
public interface ClientGtw {
    Future<Response> send(Request request);
}

@Bean
@ServiceActivator(inputChannel = REQUEST_CHANNEL)
public MessageHandler outboundGateway(TcpNioClientConnectionFactory connectionFactory) {
    TcpOutboundGateway gateway = new TcpOutboundGateway();
    gateway.setConnectionFactory(connectionFactory);
    gateway.setRequestTimeout(TimeUnit.SECONDS.toMillis(timeout));
    gateway.setRemoteTimeout(TimeUnit.SECONDS.toMillis(timeout));
    return gateway;
}

@Bean
public TcpNioClientConnectionFactory clientConnectionFactory(AppConfig config) {    
    Host host = getHost(config);

    TcpNioClientConnectionFactory factory = new TcpNioClientConnectionFactory(host.name, host.port);
    factory.setSingleUse(false);
    factory.setSoTimeout((int) TimeUnit.SECONDS.toMillis(timeout));

    SerializerDeserializer sd = new SerializerDeserializer();
    factory.setDeserializer(sd);
    factory.setSerializer(sd);
    return factory;
}

This actual approach works fine, however, when a request is sent it hangs the connection until a response is received. This is a problem due the fact that some times a request can get too much time to receive a response and the system has other requests incomming whose response can be achieved faster. I would like to send and receive as much as possible requests and responses independetly (decoupled between them). The object transported (serialized and deserialized) contains a key pair that can do the correct correlation.

TL;DR: How to implement an Asynchronous requests/responses over the same connection?

The Spring TcpOutboundGateway javadoc mentions: Use a pair of outbound/inbound adapters for that use case.

So, in addition to the declaration above:

1st Attempt

@Bean
public TcpInboundGateway inboundGateway(AbstractServerConnectionFactory connectionFactory) {
    TcpInboundGateway gateway = new TcpInboundGateway();
    gateway.setConnectionFactory(connectionFactory);
    gateway.setRequestTimeout(TimeUnit.SECONDS.toMillis(timeout));
    return gateway;
}

@Bean
public AbstractServerConnectionFactory serverFactory(AppConfig config) {
    Host host = getHost(config);
    AbstractServerConnectionFactory connectionFactory = new TcpNetServerConnectionFactory(host.port);
    connectionFactory.setSingleUse(true);
    connectionFactory.setSoTimeout(timeout);
    return connectionFactory;
}

The requests are blocked until a response is delivered as before.

2nd Attempt

@Bean
public TcpInboundGateway inboundGateway(TcpNioClientConnectionFactory connectionFactory) {
    TcpInboundGateway gateway = new TcpInboundGateway();
    gateway.setConnectionFactory(connectionFactory);
    gateway.setRequestTimeout(TimeUnit.SECONDS.toMillis(timeout));
    gateway.setClientMode(true);
    return gateway;
}

org.springframework.integration.ip.tcp.connection.TcpNioClientConnectionFactory may only be used by one inbound adapter

Any clue?


Answer:

Use a pair of channel adapters instead of an outbound gateway. Instead of using a MessagingGateway, you can do the correlation yourself in your application, or you can use the same technique as is used in the tcp-client-server-multiplex sample app. It uses an aggregator to aggregate a copy of the outbound message with an inbound message, replying to the gateway.

It's old, and uses XML configuration, but the same techniques apply.

<publish-subscribe-channel id="input" />

<ip:tcp-outbound-channel-adapter id="outAdapter.client"
    order="2"
    channel="input"
    connection-factory="client" /> <!-- Collaborator -->

<!-- Also send a copy to the custom aggregator for correlation and
     so this message's replyChannel will be transferred to the
     aggregated message.
     The order ensures this gets to the aggregator first -->
<bridge input-channel="input" output-channel="toAggregator.client"
        order="1"/>

<!-- Asynch receive reply -->
<ip:tcp-inbound-channel-adapter id="inAdapter.client"
    channel="toAggregator.client"
    connection-factory="client" /> <!-- Collaborator -->

<!-- dataType attribute invokes the conversion service, if necessary -->
<channel id="toAggregator.client" datatype="java.lang.String" />

<aggregator input-channel="toAggregator.client"
    output-channel="toTransformer.client"
    expire-groups-upon-completion="true"
    expire-groups-upon-timeout="true"
    discard-channel="noResponseChannel"
    group-timeout="1000"
    correlation-strategy-expression="payload.substring(0,3)"
    release-strategy-expression="size() == 2" />

<channel id="noResponseChannel" />

<service-activator input-channel="noResponseChannel" ref="echoService" method="noResponse" />

<transformer input-channel="toTransformer.client"
    expression="payload.get(1)"/> <!-- The response is always second -->

(This simple sample correlates on the first 3 bytes).

Question:

I'm writing a simple tcp stream SMTP server. I wrote following code to check if the client connection is still available. Simply peeking one byte to see if socket input stream is working. But when I set in.mark(x) read ahead limit to 1, it shows error when I attempt to send Header for the second time. When it's set to 2, it doesn't seem to have any problem at all. Why is this?

// check if client disconnected
try {
    in.mark(1); // 1 char read ahead limit
    if (in.read() == -1) {
        System.out.println("CONNECTION CLOSED BY CLIENT!");
        return; // end of thread
    } else {
        in.reset();
    }
} catch (Exception e) {
    e.printStackTrace();
    throw new RuntimeException();
}

The error I get is this:

java.io.IOException: Mark invalid
    at java.io.BufferedReader.reset(BufferedReader.java:512)
    at smtp.server.SocketThread.run(SocketThread.java:59)

The entire code is on my github.


Answer:

Forget it. Just read and write, and deal with the exceptions as they arise.

At present you are engaged in fortune-telling. Even if you find a method that works to tell you whether the client connection is alive now, it could go down between calling this method and the very next line of code.

The only method that actually works of trying to detect whether a resource is available is to try to use it in the normal way.

Question:

How can I use Apache common pool to pool TCP connections and reuse the connection?

To implement a TCP connection pool, I am trying to use Apache common pool(1.6), I used the object pool that is posted in https://javaarchitectforum.com/tag/apache-common-object-pool-example/ to implement it.

I do expect to see persisted TCP connection upon initiating connection to another server and reuse it for other subsequent connection requests.

The issue is, I can not see any persistent connection to the server(netstat -an). By borrowing object, new connection is established and when return the object, socket is disconnected.No pooling!

Am I using correct approach to create TCP pool?


Answer:

Issue is resolved.

Two amendments to resolve the issue:

  1. Upon returning object, the DataOutputStream should not to be closed.
  2. clientSocket should be kept alive upon makeObject() [clientSocket.setKeepAlive(true)].

As a result connections are persisted and reused for next requests.

Question:

I'm using node.js to create a server that is used for sending server-sent events to the clients. I'm running the server on a Windows 7 machine.

The way I connect is by sending HTTP get requests with apache httpclient, establish TCP connection and receive the events from the server. What I notice is that after I connect 11 clients at the same time, the previous connections close.

Is there a limit in Node.js? Or is this system-specific? I've been googling about this and I couldn't find anything.

Here is a sample code from the requests I'm sending:

HttpClient httpClient = HttpClientBuilder.create().build(); 

String domain =    "..."; 

HttpUriRequest httpGet = new HttpGet(domain); String encoding = "..."

httpGet.setHeader(new BasicHeader("Authorization", "Basic " + encoding)); 
httpGet.setHeader(new BasicHeader("Content-Type", "text/event-stream")); 

HttpResponse resp = httpClient.execute(httpGet); 
HttpEntity entity = resp.getEntity(); 

if (resp.getStatusLine().getStatusCode() != 200){ String 
   responseString = EntityUtils.toString(entity, "UTF-8"); 
   System.out.println(responseString); 
}

and I'm doing this many times in my test code.

Thanks for your help!


Answer:

Since node js v0.12 the http.globalAgent.maxSockets has been set to Infinity, so it is a client side problem.

This should set the limit for the client side:

http.globalAgent.maxSockets = 1000;

Another option is to pass an Agent object to the http request. Have a look at this other question: How to set maximum http client connections in Node.js

Question:

I currently have a simple instant messaging program which is utilizing Java's Socket and ServerSocket classes. It is functioning as intended but when I attempt to close the connection it is not using the 4 way handshake TCP teardown to close the connection. Instead it is closing the connection abruptly with an RST packet.

The way in which I am closing the connection is sending a string from the client to the server which the server will recognize as the command to close the connection. I then use the ServerSocket.close() method on the server and the Socket.close() method on the client.

What is the correct way and/or order of events to properly close a TCP connection utilizing these classes?

Client side disconnect code:

//Disconnects from remote server
//Returns true on success, false on failure
public boolean disconnect(){
    try{
        this.clientOut.println("0x000000");
        this.clientRemoteSocket.close();
        this.isConnected = false;
        return true;
    }catch(Exception e){
        return false;
    }
}

Server side disconnect code:

//Check to see if the client wants to close the connection
//If yes, then close the connection and break out of the while loop
if(incoming.equals("0x000000")){
    serverLocalSocket.close();
    break;
}

EDIT: The code works perfectly fine. I'm just trying to learn socket programming in Java and know that a proper TCP teardown process is to include a 4 way handshake. A FIN packet to the remote host, then an ACK packet from the remote host back. Then a FIN packet from the remote host, then an ACK packet to the remote host. When monitoring the traffic via Wireshark I am not getting that. Instead I am getting a FIN to the remote server, then a RST/ACK back from the server.

This image depicts a proper TCP 4 way teardown process.

So far everything I've found suggest that all one needs is a call to close() or to just let Java's Try-with-resources statement handle the clean up. I can't see Java implementing functionality which does not comply with the standard TCP specifications though. It is very possible I may be calling certain lines in an incorrect order or something of the sort, I'm just unaware of it.


Answer:

If you are resetting your own connection on close, either:

  1. You haven't read all the pending incoming data that was sent by the peer, or
  2. You had already written to the connection which had previously already been closed by the peer.

In both cases, an application protocol error.

Question:

I'm in the process of writing a messaging program, and I'm running into a spot where I'm having trouble understanding how to pass a socket over to a new thread for handling outbound messages via TCP. I'm currently using UDP packets for messages coming from a client, to the server, which, being UDP, doesn't require very much processing, as it's simply listening for incoming packets, before it de-serializes the objects, and processes them as needed in a separate thread. My problem now is, I'm setting up a client initiated TCP socket for reverse traffic, from the server to the assorted clients that connect. I've done a bit of research, and I already understood that each client should have their own thread for handling outgoing messages, along with another thread simply for accepting the incoming connections. I'm unsure of how to actually achieve this, and I've done some research into the topic.

I've found this: http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html

The resource above basically verified my original suspicion that this would have to be handled by threads dedicated to the client. They included psuedo code here, which is representing my listener thread.

while (true) {
    accept a connection;
    create a thread to deal with the client;
}

I'm a bit of a visual learner, and I have been searching for some type of an example where this is done. I'm unsure of what variable I'd be passing over to the thread that keeps the original connection open, and pushes data back to clients. I'm also having a little bit of trouble grasping whether it even keeps the same socket open, or if a new one needs to be established, which then, makes me believe a firewall could interfere, but I know that won't be the case.

Can somebody explain this for me in detail? If possible, an example would be greatly appreciated!

I'll be likely replying and commenting on responses in about 15-30 minutes from the time this is posted.


Answer:

What you are doing sounds correct. I typically implement a server like this (simplified version with no tracking of the clients and so on):

@Override
public void run() {
    //start listening on the port
    try {
        serverSocket = new ServerSocket(port);
        logger.info("Listening for connections on port " + port);
    } catch (IOException e) {
        logger.error("Cannot start SocketListener on port " + port + ". Stopping.", e);
        return;
    }

    while (!stopped) {
        try {
            //wait for connection
            Socket newSocket = serverSocket.accept();
            ClientThread client = new ClientThread(newSocket);
            Thread clientThread = new Thread(client, MEANINGFUL_THREAD_ID);
            clientThread.start();
        } catch ...
    }
}

where serverSocket is a ServerSocket instance variable and stopped is a flag I use to stop the listener thread.

So to answer your questions in the comment, you normally pass the Socket object to each client thread so that that thread can work with the input and output stream and handle closing of the socket and so on. Once you "accept" a socket connection, you do not need to recreate the ServerSocket, you simply call .accept() again to start waiting for a new connection.

In most cases, you will need to keep track of all client threads in your server so that you can stop the server gracefully or do broadcasts for example.

Question:

I have a Spring Integration project that handles TCP messages.

The simplest scenario is the PING message (receive msg from source and echo it back), the flow in the SI project is as follows :

1) Message is received from source (by a tcp-inbound-gateway). The source closes the socket after each message.

2) A transformer analyzes the message and sets (among others) a header value with the reply channel name

3) A Header-Value-Router is applied over the message that routes it back to the source.

XML config (simplified version) is below :

<int-ip:tcp-connection-factory id="TCP_SRV"
                               type="server"
                               port="${router.port}"
                               using-nio="true"
                               single-use="true"
                               serializer="CustomSerializer"
                               deserializer="CustomSerializer"/>

<int-ip:tcp-inbound-gateway request-channel="rawInputFromSource"
                            reply-channel="outputBackToSource"
                            connection-factory="TCP_SRV"/>

<int:channel id="rawInputFromSource"/>

<int:transformer ref="inputFromSourceTransformer"
                 input-channel="rawInputFromSource"
                 output-channel="processedInputFromSource"/>

<int:channel id="processedInputFromSource"/>

<bean id="inputFromSourceTransformer" class="my.org.InputFromSourceTransformer"/>

<int:header-value-router input-channel="processedInputFromSource" 
                         header-name="RouteToChannel"/>

It works ok from a functional pov when invoking messages manually, but it fails under stress testing. Once I ramp up over 15 threads (each thread running a for loop sending 10 messages) I receive java.net.ConnectException: Connection refused: connect for about 20% of the attempts.

The code snippets used by the threads to send the msg :

byte[] sendAndReceive(byte[] data){
    byte[] result = new byte[data.length];
    try {
        Socket socket=new Socket("localhost", SI_PORT); // here is where the err occurs
        OutputStream output = socket.getOutputStream();
        InputStream  input = socket.getInputStream();
        output.write(data);
        input.read(result);
        socket.close();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return result;
}

Error :

java.net.ConnectException: Connection refused: connect
at java.net.TwoStacksPlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at java.net.Socket.connect(Socket.java:538)
at java.net.Socket.<init>(Socket.java:434)
at java.net.Socket.<init>(Socket.java:211)
at my.org.PerformanceTest.sendAndReceive(PerformanceTest.java:98)

The requirements say it must pass with 60 threads. Any ideas what I can do to solve this issue ? I tried adding a task:executor id="threadPoolTaskExecutor" pool-size="5-10" queue-capacity="100" rejection-policy="CALLER_RUNS" on the factory but this didn't solved the issue.

Any advice is highly appreciated


Answer:

Increase the backlog on the server connection factory.

/**
 * The number of sockets in the connection backlog. Default 5;
 * increase if you expect high connection rates.
 * @param backlog The backlog to set.
 */
public void setBacklog(int backlog) {
    Assert.isTrue(backlog >= 0, "You cannot set backlog negative");
    this.backlog = backlog;
}

Available in XML configuration with the backlog attribute...

<xsd:attribute name="backlog" type="xsd:string">
    <xsd:annotation>
        <xsd:documentation>
            Specifies the connection backlog for server sockets. Does not
            apply to client factories.
        </xsd:documentation>
    </xsd:annotation>
</xsd:attribute>

Question:

I have TCP gateway built using Spring Integration. My server is able to process the request from the client and send response. But Client is giving SocketException

java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:168)
    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)

It seems server is closing the connection before the client reads all the data. Hence I would like to use so-linger.

setSoLinger is supposed to keep the server socket open for the linger time. javadoc for setSoLinger says Enable/disable SO_LINGER with the specified linger time in seconds.

See https://docs.oracle.com/javase/6/docs/api/java/net/Socket.html#setSoLinger%28boolean,%20int%29

See Spring Integration document for setting SoLinger.

My spring context.xml :

    <int-ip:tcp-connection-factory id="crLfServer"
            type="server"
            port="${availableServerSocket}"
            single-use="true"
            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"/>

I am not sure whether Spring integration takes linger time in seconds or milli seconds. is there any other flag to be set so that Server socket is kept open till the client reads data.

I am seeing Socket connection closed event almost immediately sending response from the service bean. Server does not seem to wait. Please help how to set so-linger time or suggest alternative. Thank you.

Here is the log:

2016-06-01 15:43:46,276 MyService response:                 ACCEPT:E211001:

2016-06-01 15:43:46.293 DEBUG [pool-1-thread-2][org.springframework.context.support.GenericXmlApplicationContext] Publishing event in org.springframework.context.support.GenericXmlApplicationContext@7a187814: TcpConnectionCloseEvent [source=org.springframework.integration.ip.tcp.connection.TcpNetConnection@4c4b11e9], [factory=crLfServer, connectionId=22.220.220.222:1034:5678:77483643-2156-427f-96dd-a513670a75a3] **CLOSED**

2016-06-01 15:43:46.294 DEBUG [pool-1-thread-2][org.springframework.context.support.GenericXmlApplicationContext] Publishing event in org.springframework.context.support.GenericXmlApplicationContext@7a187814: TcpConnectionExceptionEvent [source=org.springframework.integration.ip.tcp.connection.TcpNetConnection@4c4b11e9, cause=java.net.SocketException: Socket is closed], [factory=crLfServer, connectionId=22.220.220.222:1034:5678:77483643-2156-427f-96dd-a513670a75a3]

Answer:

Spring integration performs no conversion on the value, so it's seconds.

The behavior you describe sounds like so-linger is 0 (immediate RST sent for close()).

You really don't need so linger for this purpose; when it's not set the TCP stack should gracefully close the socket.

You probably need to run a network monitor to figure out what's happening.

If you trust your client to close the socket, you could remove the

single-use="true"

or set it to false so the server doesn't close the socket after sending the reply.

Question:

This has been a relatively tedious problem for me, allow me to walk you through it, dear helper.

I am sending through TCP sockets several strings from a C server to a Java Android application. My first solution, on the Android side, was the following (simplified for readability):

protected void receiveMessage() {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
            String buffer;
            while ((buffer = br.readLine()) == null) {}     //This is blocking, unless a line is read
        dispatch(buffer);
        catch(...){}
}

This was running in a Thread, and was working ok. Only problem is, it doesn't survive stress test at all. When sending several messages in a row, it skips most of it (I think it only processes the first one). Forcing a sleep(1) between every sending task is working.

Second solution, with a StringBuilder, allowing me to catch everything in-between the sockets:

StringBuilder total = new StringBuilder(inputStream.available());
String line;
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
while((line = bufferedReader.readLine()) != null) {
      total.append(line).append('\n');
}

But:

  1. It never breaks out of the while instruction
  2. Buffer is noisy, although everything is there

Here's a sample of the logcat with that second solution, first message is fine and can be processed by the dispatcher, then it becomes shady, third one is ok, fourth is bad again, etc

05-20 16:26:56.901 10082-10204/com.myapp D/RECEIVER: RECEIVING
05-20 16:26:56.901 10082-10204/com.myapp D/RECEIVER: line={  "action": 20,  "data": [    {      "id": 100,      "addr": 64,      "pin": 0,      "state": true,      "name": "Ecumeur"    },    {      "id": 101,      "addr": 64,      "pin": 1,      "state": false,      "name": "Brasseurs"    }  ]}
05-20 16:26:56.901 10082-10204/com.myapp D/RECEIVER: RECEIVING
05-20 16:26:56.901 10082-10204/com.myapp D/RECEIVER: line=���������������������������� ���������������������������������������������~�_������_��������������������������������X�������x;~�_���� ;~�_����������������x;~�_����'������������b@�����������J�_����@������_������������������P��������+V�_������������������X��������i���O���������������������A������@������������������������������������]

How am I supposed to do this, in the good way? Thank you very much for your responses!


Answer:

I'll skip your first attempt it seems very wrong at first glance. Your second attempt is closer but... You are doing nothing to tell the (android) client that you have reached the end of the message.

If the (C) server were to close the connection, that would kick android out the loop because it would reach the end of the InputStream and that would cause the buffered reader to return null. Then it would end the loop and continue processing.


If you want to keep the connection open then you must send a marker from the server (eg: send the string "EOF" on a line and have android check every line for that marker).

eg:

StringBuilder total = new StringBuilder(inputStream.available());
String line;
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
while((line = bufferedReader.readLine()) != null && !line.equals("EOF")) {
      total.append(line).append('\n');
}

For this to work the server must send the string "EOF" on a line to tell android it is the end of the message.


I think the data noise is being caused by C sending something that it shouldn't. It's not clear from your question what the cause for this is.

Question:

I am trying to create a Tcp server which accept inbound connection, and send message to connected clients asynchronously. There is a sample of Tcp server but it is using gateway, which is request/response, does not support async.

my goal,

  1. server listen to socket, e.g. 9000
  2. a tcp client connect to 9000
  3. server accept connect and receive message. (use TcpReceivingChannelAdapter?)
  4. server keep the connection/socket and make note of the ip_connectId header.
  5. when some event or schedule task produce a message for a client, it looks up the ip_connectId and send a message to that client. (use TcpSendingMessageHandler?)

From the reference document, I should use Collaborating Outbound and Inbound Channel Adapters. but there is no java config sample. I don't understand how to do this with java config, especially how and where to look for a client to send.

Do I need two channels? one for inbound and one for outbound? inboundAdapter->fromTcpChannel->consumer producer->outboundAdapter->toTcpChannel

Do I create ServiceActivator or Endpoint to act as consumer/producer? Does spring integration keep connections alive by default? and when I need to send message to it, by just adding ip_connectId header to a message? Do I dispatch the message to client using TcpSendingMessageHandler or need to implement a gateway?

Clean up my code and test again after Gary's help, this is my code so far.

@EnableIntegration
@IntegrationComponentScan
@Configuration
public class IntegrationConfig implements
        ApplicationListener<TcpConnectionEvent> {
    @Value("${listen.port:8000}")
    private int port;

    @Bean  //for accepting text message from TCP, putty
    public MessageChannel fromTcp() {
        return new DirectChannel();
    }

    @Bean  //for sending text message to TCP client, outbound
    public MessageChannel toTcp() {
        return new DirectChannel();
    }

    // receive from MVC controller
    @Bean
    public MessageChannel invokeChannel() {
        return new DirectChannel();
    }   

    @Bean  //inbound, it is working, I could read the inbound message while debugging
    public TcpReceivingChannelAdapter in(
            AbstractServerConnectionFactory connectionFactory) {
        TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
        adapter.setOutputChannel(fromTcp());
        adapter.setConnectionFactory(connectionFactory);
        return adapter;
    }

    //transform TCP bytes to string message, working
    @Transformer(inputChannel = "fromTcp", outputChannel = "toCollaborate")
    public String convert(byte[] bytes) {

        return new String(bytes);
    }

    MessageHeaders staticheader;  //save ip_connectinId, use this to collaborate outbound message later, for testing purpose only
    @ServiceActivator(inputChannel = "toCollaborate", outputChannel = "toTcp")
    public Message<String> handleTcpMessage(Message<String> stringMsg) {
        staticheader = stringMsg.getHeaders();
        return stringMsg;
        // save the header, collaborate to output channel
    }

    //collaborate message from REST API invokeChannel to a outbound tcp client, this fail
    @Transformer(inputChannel = "invokeChannel", outputChannel = "toTcp")
    public Message<String> headerBeforeSend(String test) {
        GenericMessage<String> msg = new GenericMessage<String>(
                "from rest api");
        if (staticheader != null) {         
            MessageBuilder
                    .fromMessage(msg)
                    .setHeader("ip_connectionId",
                            staticheader.get("ip_connectionId")).build();
        }
        return msg;
    }

    @ServiceActivator(inputChannel = "toTcp")
    @Bean
    public TcpSendingMessageHandler out(
            AbstractServerConnectionFactory connectionFactory) {
        TcpSendingMessageHandler tcpOutboundAdp = new TcpSendingMessageHandler();
        tcpOutboundAdp.setConnectionFactory(connectionFactory);


        return tcpOutboundAdp;
    }   

    // should need only 1 factory? and keep connectin alive
    // server for in coming connection
    @Bean
    public AbstractServerConnectionFactory serverCF() {
        return new TcpNetServerConnectionFactory(this.port);
    }

    @Override
    public void onApplicationEvent(TcpConnectionEvent tcpEvent) {
        // TODO Auto-generated method stub
        TcpConnection source = (TcpConnection) tcpEvent.getSource();

    }

}
//The MVC controller
@Autowired
    MessageChannel invokeChannel;
    @RequestMapping(value="/invoke")
    public String sayHello()
    {
        //trigger gateway to send a message
        String msg = "hello";
        MessagingTemplate template = new MessagingTemplate();
        template.send(invokeChannel, new GenericMessage<String>(msg));      
        return msg;
    }

The test result: 1. putty connect ok, send text message 2. SI receive message ok 3. use REST API localhost/webappname/rest/invoke to send a message to invokeChannel, ok 4. The transformer set message header 5. exception as follow

exception org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.messaging.MessageHandlingException: Unable to find outbound socket org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981) org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:860) javax.servlet.http.HttpServlet.service(HttpServlet.java:622) org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845) javax.servlet.http.HttpServlet.service(HttpServlet.java:729) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)


Answer:

Yes; the connection is kept open by default; yes you can use a @ServiceActivator to handle requests; yes you just have to set the connection id header.

To configure the outbound adapter in Java Configuration, add @ServiceActivator to the handler bean...

@Bean
public TcpReceivingChannelAdapter() in() {

    ...
    adapter.setOutputChannel(newRequests());

}


...

@ServiceActivator(inputChannel="toClientChannel")
@Bean
public TcpSendingMessageHandler out() {

    ...

}

Question:

I have a service which creates a socket server and a client connects to it. The connection is kept open to transfer data. The service is START_STICKY. So when user kills the app by swiping it from recent tasks, the onCreate and onStartCommand functions are called again. I don't want to re-initialize the socket and instead preserve it's state as it was before the user swiped the task to kill it and keep transferring the data uninterrupted.

public class SendTasksService extends Service {
    static Socket socket=null;
    static boolean shouldRun=true;
    static final int port = PORT_NO;
    static ServerSocket listener = null;

    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("Service onBind.");
        return null;
    }

    @Override
    public void onCreate() {
        System.out.println("Service onCreate.");
        shouldRun=true;
        try {
            if(socket==null){
                System.out.println("Starting Listening..");
                listener = new ServerSocket(port);
                System.out.println("Notification Started.");
            }else{
                System.out.println("Continuing With Old Socket..");
                /*
                    How to get the socket if the connection
                    was made before swipe killing the app from recent
                */
            }
        }catch(Exception ioe){
            System.out.println("Exception in listening.");
            ioe.printStackTrace();
        }
    }

    public void onDestroy() {
        System.out.println("Service onDestroy.");
        closeConnection();
    }

    public void closeConnection(){
        //Wind up work and close connection
        /*
            This should also remove any socket information saved anywhere
        */
    }

    public int onStartCommand(Intent intent, int flags, int startid) {
        System.out.println("Service onStartCommand.");
        try{
            new AsyncAction().execute();
        }catch (Exception e) {
            e.printStackTrace();
        }

        return START_STICKY;
    }

    private class AsyncAction extends AsyncTask<String, Void, String> {
        protected String doInBackground(String... args) {
            while(shouldRun) {
                try {
                    if(socket==null) {
                        socket = listener.accept();
                        /*
                            Socket connection established here.
                            Save this socket state or preserve it somehow
                            So that connection does not break on killing the app
                        */
                    }else{
                        /*
                            Continue with the old socket data, and resume connection
                        */
                    }
                    if(socket==null)
                        continue;
                }catch(Exception e){
                    System.out.println("Exception after Break");
                    e.printStackTrace();
                }
            }
            return null;
        }

        protected void onPostExecute(String result) {
        }
    }
}

What I have tried?

  1. Try to save socket as using gson in SharedPreferences. Couldn't retrieve the socket object back.

    SharedPreferences pref = getApplicationContext().
                         getSharedPreferences("MyPref", MODE_PRIVATE);
    SharedPreferences.Editor editor = pref.edit();
    editor.putBoolean("onGoingConnection",false);
    Gson gson = new Gson();
    String json = gson.toJson(socket);
    editor.putString("ExistingSocket",json);
    editor.apply()
    
  2. Create a static saving Socket in the activity which started the service. It was always null on service resume.

Answer:

I don't want to re-initialize the socket and instead preserve it's state as it was before the user swiped the task to kill it and keep transferring the data uninterrupted.

By definition, that is not possible. Your process was terminated. Your socket goes away when your process does.

Try to save socket as using gson in SharedPreferences.

A socket cannot be persisted. You saved the toString() of the Socket, nothing more.

Question:

My colleague and I were working on a client application that communicates with the web service in order to process some transaction data. These are steps in our communication:

  1. Client application initiates the connection and sends the request message (timestamp = T1)
  2. Web service accepts the connection and processes the request (timestamp ≈ T1)
  3. Web service returns the response message (timestamp = T1 + few_seconds)
  4. Web service closes the connection (timestamp = T1 + 3_minutes)
  5. Client application gets the response message and proceed with data parsing (timestamp = T1 + 3_minutes)

Our problem lies in the timestamp references: The web service process the request and retrieves the response almost immediately but the client application does not get the response message until the server closes the connection. Here are log files:

Client application log snippet:

10:46:25,031 INFO  MessageHandler.java:115 Message sent.
10:49:25,071 INFO  MessageHandler.java:125 Message received.
10:49:25,103 DEBUG  MessageParser.java:67 Message parsed.

Server application log:

10:46:25:153 <INFO>   Client connection accepted.
...
10:46:26:602 <INFO>   Response message sent.
...
10:49:25:069 <INFO>   Closing connection...

As you can see, client gets the response only when the server closes the connection.

Here is the client app code of the method where the communication is done:

public static String sendMsg(byte[] msg, String serverIp, int port) {
    try {
            InetAddress address = InetAddress.getByName(serverIp);
            Socket socket = new Socket(address, port);
            OutputStream os = socket.getOutputStream();

            logger.info("Message sent.");

            os.write(msg, 0, msg.length);
            os.flush();

            InputStream is = socket.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String msgReceived = br.readLine();

            logger.info("Message received.");
            os.close();
            return msgReceived;
        } ...(catch blocks) ... 
}

Suppose that we can't change the web service implementation, is there a way to get the response message on the client side immediately when the service initiates the response (and then to close the connection by client) ? Thanks in advance.


Answer:

Most likely, the client is not properly implementing the message protocol. For example, the client calls readLine. Does the message protocol specify that the message is a line? If not, readLine will keep waiting until the connection closes, still trying to get that line that was never going to be sent.

The client will be unable to find the end of a message unless it understands how a message is delimited. How is a message delimited in your protocol? Where is the client code to detect the end of a message? If you didn't write it, it won't happen.

Question:

I have stucked for 4h already with the sockets, the way I am using is is that there is only one application as client and server, once the client connect it is opening the theard with new client and waiting for message.

Once the message is send to the server, the client will receive respond, that part is working without any problems.

Part of the Client Theard:

while (true)
        {
            InputStreamReader IR = new InputStreamReader(clientSocket.getInputStream());
            BufferedReader BR = new BufferedReader(IR);
            PrintStream PS = new PrintStream(clientSocket.getOutputStream());
            String message = BR.readLine();
            if (message != null)
            {
                System.out.println(clientSocket.getInetAddress() + ":" + clientSocket.getPort() + " has connected."+message);
                if (message.equals("exit"))
                {
                    PS.println("Exiting...");
                    exit();
                }
                else if (message.equals("list"))
                {
                    getList(PS);
                }
                else if ((message.contains("get") && (message.contains(",") && (message.contains(" ")))))
                {
                    String[] spliter = message.split(" ");
                    String[] file = spliter[1].split(",");
                    String file_name = file[0];
                    String file_md5 = file[1];
                    getFile(file_name, file_md5, clientSocket);
                }
            }
            else
            {
                break;
            }

        }

There are 2 messages that the server is supporting, the first one is "list" and the send one command is "get with values".

if client will request command "list" it will run this: There is a "server/client", it is sending request and receive the one line string and it is working without any problem, I am receiving the list of files from the server.

PrintStream PS = new PrintStream(clientSocket.getOutputStream());
        PS.println("list");
        InputStreamReader IR = new InputStreamReader(clientSocket.getInputStream());
        BufferedReader BR = new BufferedReader(IR);
        String lista_plikow = BR.readLine();
        if ( lista_plikow != null)
        {
            return lista_plikow;
        }

But I have problems to send the files over the sockets using code found on stackoverflow, but the "receiving" is not working, there is my receive function, the loop is always as 0 (even if first bytes length is correct), but the length of the bytes is correct, it is using newly created file but nothing is happening, the file is always on use, and has 0 bytes instead of content of the PS.println.

PrintStream PS = new PrintStream(clientSocket.getOutputStream());
    PS.println("get "+filename+","+file_md5);
    int bytesRead;
    int current = 0;
    FileOutputStream fos = null;
    BufferedOutputStream bos = null;
    try
    {
        byte [] mybytearray  = new byte [Integer.parseInt(size)];
        InputStream is = clientSocket.getInputStream();
        fos = new FileOutputStream(filename + ".recived");
        bos = new BufferedOutputStream(fos);
        bytesRead = is.read(mybytearray,0,mybytearray.length);
        current = bytesRead;
        System.out.println("X" + bytesRead);
        do {
               bytesRead =
                  is.read(mybytearray, current, (mybytearray.length-current));
            System.out.println(bytesRead + " = " + current + " " + (mybytearray.length-current));

               if(bytesRead >= 0) current += bytesRead;
               System.out.println(bytesRead);
        } while(bytesRead > -1);
        bos.write(mybytearray, 0 , current);
        bos.flush();
        System.out.println("File " + "recived." +filename.replace(":", " ")
            + " downloaded (" + current + " bytes read)");
    }catch (Exception e)
    {
        System.out.println(e.getMessage());
    }

And last part of the scrip the "PS.println("get "+filename+","+file_md5);" is doing exactly this one, the sending is working fine:

FileInputStream fis = null;
            BufferedInputStream bis = null;
            OutputStream os = null;

            String the_file = TorrentAppGui.folder+"\\"+file_name.replace(":", " ");
             File myFile = new File (the_file);
              byte [] mybytearray  = new byte [(int)myFile.length()];
              fis = new FileInputStream(myFile);
              bis = new BufferedInputStream(fis);
              bis.read(mybytearray,0,mybytearray.length);
              os = clientSocket.getOutputStream();
              System.out.println("Sending " + the_file + "(" + mybytearray.length + " bytes)");
              os.write(mybytearray, 0, mybytearray.length);
              os.flush();
              System.out.println("Done.");

I have no idea why I cannot save the bytes received by the "get" command, do you have any ideas? I know that only the "receve" function is not working, because if I looged to the application via telnet I could get the file in the console, but it doesnt reach my target. See the screen from cli.


Answer:

You can't mixed buffered and unbuffered streams/readers/writers on the same socket. You will lose data in the buffers. Use the same stream pair for the life of the socket. In this case I would use DataInputStream and DataOutputStream, and the readUTF()/writeUTF() methods for the messages and filenames. You will also need to send the file length ahead of the file, unless the file is the last thing sent over the connection: otherwise the peer won't know when to stop reading the file and go back and start reading messages again.

Question:

I've created a TCP Server in Java and a TCP client in Ruby. The problem is I'm not able to send more than 1 message in the same connection, Only the first message is sent while the other one is not sent.

here is the Java code

package com.roun512.tcpserver;

import java.io.*;
import java.net.*;

public class Program {


    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {

        String clientSentence;
        String capitalizedSentence;
        ServerSocket Socket = new ServerSocket(6789);

        while(true)
        {
            Socket connection = Socket.accept();
            BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            DataOutputStream outToClient = new DataOutputStream(connection.getOutputStream());
            clientSentence = inFromClient.readLine();
            System.out.println(clientSentence);
            capitalizedSentence = clientSentence + '\n';
            outToClient.writeBytes(capitalizedSentence);
            System.out.println("Sent msg");
        }
    }
}

And here is the client code

Client.rb

require 'socket'
class Client

        def initialize()
                server = TCPSocket.open("127.0.0.1", 6789)
                if server.nil?
                        puts "error"
                else
                        puts "connected"
                end
                server.puts("Hello\r\n")
                sleep 2
                server.puts("There\r\n")
                server.close
        end
end
Client.new()

I'm only receiving Hello. I have tried many other ways but none worked.

So my question is how to send more than 1 message in a single connection, Any help would be appreciated :)

Thanks in advance!


Answer:

Socket.accept() waits for new connection after reading the first line. Try the following:

public static void main(String[] args) throws Exception {

    String clientSentence;
    String capitalizedSentence;
    ServerSocket Socket = new ServerSocket(6789);

    while (true)
    {
        Socket connection = Socket.accept();
        while(true)
        {
            BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            DataOutputStream outToClient = new DataOutputStream(connection.getOutputStream());
            clientSentence = inFromClient.readLine();
            System.out.println(clientSentence);
            capitalizedSentence = clientSentence + '\n';
            outToClient.writeBytes(capitalizedSentence);
            System.out.println("Sent msg");
        } 
    }
}

If it works, change while (true) to some meaningful condition and don`t fotget to close the connection after the work is done.

Question:

I am currently coding a simple TCP chat client-server application which works with sockets. A client connects to the server and as soon as it gets accepted, a new worker thread is created to listen for client input. Connecting to the sever (localhost at port 8818) works fine, but as soon as the worker thread starts listening for more client input after the login a java.net.SocketException: Connection reset is thrown (see stack trace below). I am aware that one possible source of this exception can be a socket that hasn't been closed properly or forcefully by either the server or the client. Therefore, my assumption is that I am not handling the closing of my client socket properly which causes the connection to reset. What I would like to achieve: The worker listens for client input, as long as this is not null, requests (e.g. a simple login) are processed, otherwise, the socket is closed (see code excerpts below). My client receives a 'Login Successful' message from the server indicating that my handleLogin() function works, but instead of closing the socket after receiving no more input from the client, the server seems to just reset, even though clientSocket.close() is issued after the while loop.

Server.java

@Override
    public void run() {

        try {

            ServerSocket serverSocket = new ServerSocket(serverPort);

            while (true) {

                // Accept connection(s) from new chat client(s)
                System.out.println("SERVER: WAITING TO ACCEPT CLIENT CONNECTIONS ...");
                Socket clientSocket = serverSocket.accept();
                System.out.println("SERVER: CONNECTION ACCEPTED FROM: " + clientSocket);
                // Process client request in separate Thread
                WorkerThread worker = new WorkerThread(this, clientSocket);
                workerList.add(worker);
                worker.start();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

WorkerThread.java

 @Override
    public void run() {

        try {
            handleClientSocket();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }


    private void handleLogin(OutputStream outputStream, String[] tokens) throws IOException {

        if (tokens.length != 3) {
            outputStream.write("LOGIN FAILED!\n".getBytes());
                return;
        }

        // Extract username and password from user input
        String username = tokens[1];
        String password = tokens[2];

        if (username.equals("anna") && password.equals("anna")) {

            outputStream.write("Login successful!\n".getBytes());

        } else {
            outputStream.write("Error logging in!\n".getBytes());
        }

    }

    private void handleClientSocket() throws IOException, InterruptedException {

        InputStream inputStream = clientSocket.getInputStream();
        this.outputStream = clientSocket.getOutputStream();

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String line;

        // THIS IS WHERE THE EXCEPTION OCCURS AFTER CLIENT HAS LOGGED IN SUCCESSFULLY
        while ((line = bufferedReader.readLine()) != null) {

            String[] tokens = StringUtils.split(line);

            if (tokens.length > 0 && tokens != null) {

                String command = tokens[0];

                // Evaluate the entered command and handle the request accordingly

                if ("login".equalsIgnoreCase(command)) {
                    handleLogin(outputStream, tokens);
                } 

                // process other commands ...  

            }
        }

        clientSocket.close();   // POSSIBLY WORNG WAY OF CLOSING THE CLIENT SOCKET?
    }

Client.java

import java.io.*;
import java.net.Socket;

public class Client {

    private final String serverName;
    private final int serverPort;
    private Socket mySocket;
    private OutputStream serverOut;
    private InputStream serverIn;

    public Client(String serverName, int serverPort) {
        this.serverName = serverName;
        this.serverPort = serverPort;
    }

    private boolean connect() {

        try {
            mySocket = new Socket(serverName, serverPort);
            serverOut = mySocket.getOutputStream();
            serverIn = mySocket.getInputStream();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    private void login(String username, String password) throws IOException {
        String command = "login " + username + " " + password + "\n";
        serverOut.write(command.getBytes());
    }

    public static void main(String[] args) throws IOException {

        Client client = new Client("localhost", 8818);

        if (client.connect()) {                             
            System.out.println("Connection successful!");   
            client.login("anna", "anna");                   

        } else {
            System.err.println("Connection failed ...");
        }

    }

}

Stack Trace

java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:189)
    at java.net.SocketInputStream.read(SocketInputStream.java:121)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.BufferedReader.fill(BufferedReader.java:161)
    at java.io.BufferedReader.readLine(BufferedReader.java:324)
    at java.io.BufferedReader.readLine(BufferedReader.java:389)
    at WorkerThread.handleClientSocket(WorkerThread.java:70)
    at WorkerThread.run(WorkerThread.java:45)

When I test my server with PUTTY (i.e. by connecting to localhost and then issuing commands in PUTTY's terminal), everything works just fine. I am still fairly new to socket programming, so I also might have a logic flaw here. Any help will be much appreciated as I really would like to continue this project. Thanks in advance!


Answer:

The reason of this exception is that you terminated the client once you connected the server, but the server still read something from the stream. The exception occurs. Here is the code I tested:

    while (inputStream.available() != 0) {
        line = bufferedReader.readLine();
        String[] tokens = StringUtils.split(line);

        if (tokens.length > 0 && tokens != null) {

            String command = tokens[0];

            // Evaluate the entered command and handle the request accordingly

            if ("login".equalsIgnoreCase(command)) {
                handleLogin(outputStream, tokens);
            } 

            // process other commands ...  

        }
    }

change the condition in while loop to check if the inputstream is still available to read.

Question:

I don't really know much of the theory behind TCP socket communication, but out of practice, I have achieved the following code:

Server:

public class Server {

    public static volatile ArrayList<ReplyThread> connections = new ArrayList<>();

    public static void main(String[] args) {
        new AcceptThread().start();
    }

    private static class AcceptThread extends Thread {
        @Override
        public void run() {
            ServerSocket inSock;

            try {
                inSock = new ServerSocket(3074);

                boolean loop = true;
                while(loop) {
                    System.out.println("waiting for next connection");
                    connections.add(new ReplyThread(inSock.accept()));
                    System.out.println("connection made");
                    connections.get(connections.size() - 1).setName(""+(connections.size() - 1));
                    connections.get(connections.size() - 1).start();
                }
                inSock.close();

            } catch (IOException ex) {
                System.out.println(ex.getMessage());
            }
        }
    }

    public static class ReplyThread extends Thread {
        private static Socket sock;
        private DataOutputStream out;

        public ReplyThread(Socket newSock) {
            sock = newSock;
        }

        @Override
        public void run() {
            try {
                DataInputStream in = new DataInputStream(sock.getInputStream());
                out = new DataOutputStream(sock.getOutputStream());

                boolean loop = true;
                while(loop) {
                    String msg = in.readUTF();
                    System.out.println(msg);
                    for (ReplyThread thread : connections) {
                        thread.output(sock, msg);
                    }
                }

                in.close();
            } catch (SocketException ex) {
                Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                System.out.println("Connection terminated.");
                this.interrupt();
                System.out.println(this.getName() + " I was interrupted");
            } catch (IOException ex) {
                Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        public final void output(Socket sock, String message) throws IOException {
            this.out.writeUTF(this.getName() + ": " + message);
        }
    }
}

Client:

package server;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.URL;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
/*
 * @author RaKXeR
 */
public class Client {

    public static Socket sock;

    public static void main(String[] args) {
        try {
            sock = new Socket("localhost", 3074);
            new writeThread().start();
            new readThread().start();

        } catch (IOException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static class readThread extends Thread {
        @Override
        public void run() {
            boolean loop = true;
            while (loop) {
                try {

                    DataInputStream in = new DataInputStream(sock.getInputStream());
                    //BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
                    String msg = in.readUTF();
                    //String msg = in.readLine();
                    System.out.println(msg);

                } catch (IOException ex) {
                    System.out.println("read error");
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    loop = false;
                }
            }
        }
    }

    public static class writeThread extends Thread {
        @Override
        public void run() {
            boolean loop = true;
            while(loop) {
                try {
                    DataOutputStream out = new DataOutputStream(sock.getOutputStream());
                    System.out.println("Type your message to the server: ");
                    Scanner scan = new Scanner(System.in);
                    out.writeUTF(scan.nextLine());

                } catch (IOException ex) {
                    System.out.println("write error");
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    loop = false;
                }
            }
        }
    }

}

This program doesn't do much. you open up a server, and it starts a thread waiting for incoming connections on the server socket. once you open up a client that tries to connect to the server socket, it accepts the connection, and adds a new thread to my thread array list, which starts waiting for messages from that client/client socket.

This way whenever a new client tries to connect, I just add him to another thread, and manage to talk to both clients at once.

The way I have it setup at the moment, as soon as 1 client sends the server a message, the server sends that same message to every client connected, along with the number of the thread. And all of this works as intended.

My problem, however, is that as soon as I stop one of the clients from running, everything stops working. It is better for you to test the code on your own instead of me explaining what exactly I mean by "stops working", because if I knew I don't think I would be asking this xD

So, The actual question: What is causing this, and can I fix this without changing everything about my code? I have a feeling it has something to do with me re-using the server socket to create several client sockets, but I'm not sure.

EDIT: You can see below Jim Garrison's answer, and he explains what the issue was - I was trying to send the message of other clients to the clients that were offline, and that would throw an exception and stop the thread. All I did to fix this was add a "T" of "Terminated" to the name of the threads that were closed, and checked every name of a thread before sending it info. It's not perfect, but it's the solution I have right now. If you ever use the code in this thread as a base, I'm sorry for you because this code isn't that good xD but anyway, if you do, I recomend you improve on it, as I will in my original program. Here is the fixed server code:

package server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Server {

    public static volatile ArrayList<ReplyThread> connections = new ArrayList<>();

    public static void main(String[] args) {
        new AcceptThread().start();
    }

    private static class AcceptThread extends Thread {
        @Override
        public void run() {
            ServerSocket inSock;

            try {
                inSock = new ServerSocket(3074);

                boolean loop = true;
                while(loop) {
                    System.out.println("waiting for next connection");
                    connections.add(new ReplyThread(inSock.accept()));
                    System.out.println("connection made");
                    connections.get(connections.size() - 1).setName(""+(connections.size() - 1));
                    connections.get(connections.size() - 1).start();
                }
                inSock.close();

            } catch (IOException ex) {
                System.out.println(ex.getMessage());
            }
        }
    }

    public static class ReplyThread extends Thread {
        private static Socket sock;
        private DataOutputStream out;

        public ReplyThread(Socket newSock) {
            sock = newSock;
        }

        @Override
        public void run() {
            try {
                DataInputStream in = new DataInputStream(sock.getInputStream());
                out = new DataOutputStream(sock.getOutputStream());

                boolean loop = true;
                while(loop) {
                    String msg = in.readUTF();
                    System.out.println(msg);
                    for (ReplyThread thread : connections) {
                        if (!thread.getName().contains("T")) thread.output(sock, msg);
                    }
                }

                in.close();
            } catch (SocketException ex) {
                //Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                System.out.println("Connection terminated.");
                this.setName(this.getName() + "T");
                this.interrupt();
                System.out.println(this.getName() + " I was interrupted");
            } catch (IOException ex) {
                Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        public final void output(Socket sock, String message) throws IOException {
            this.out.writeUTF(this.getName() + ": " + message);
        }
    }
}

Answer:

After one client terminates, the corresponding ReplyThread gets a SocketException and terminates. However you don't clean up the connection array list. As each still-connected client sends a message you still attempt to send a reply to the now-closed client. This throws an exception terminating the ReplyThread for the current sending client.

In other words, after one client terminates, the ReplyThread for each remaining client will die when a message is received for that client.

The solution is to add code to handle connection terminations and ensure the correctness and consistency of the server's view of which connections are still active.

Question:

I have a simple server that has a main thread and accepts the Clients, and starts a new thread per client. So in this thread I want to make a another connection( UDP) with the client, but I am confused. If there are 10 Threads(Clients) running and all ten try to open a DatagramSocket with the same port, that will throw SocketBindException right? So how can i do this?


Answer:

  • The client connects to the server over TCP.
  • Decides which UDP port to listen to. Sends that information to Server over TCP.
  • Spawns a thread, binds to the UDP Port Becomes UDP Server

  • Server receives the UDP port information on TCP socket.
  • Spawns a UDP thread receiving the port information. Becomes UDP client.
  • The UDP thread connects to the UDP server (which is also a TCP client).

Question:

My problem is that I have ssl connection between java iso client and test server. Connection is ok, no problems with handshake, but server receives incorrect data.

As I see in log server receives just partial data during one read operation and some strange data also present in inputstream - maybe it is related to certificate information.

Note that without ssl this client and server works without any problems. Also when I create jks standart certificate simple by java keyTool everything is ok and problem not happen.

But when I work with x509 problems happens no matter if I send certificate as parameter for server jvm by generating jks from cmd or use code below to generate jks in code. Connection and handshake always ok, but data in inputstream is broken.

This how I get certificate using boucycastle library. Almost the same for client and server

private SSLServerSocketFactory handleCertificate() throws KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException {
    Security.addProvider(new BouncyCastleProvider());

    PEMReader pr = new PEMReader(new FileReader("p.pem"));
    X509CertificateObject cert = (X509CertificateObject) pr.readObject();

    PEMReader pr2 = new PEMReader(new FileReader("klient.cer"));
    X509CertificateObject cert2 = (X509CertificateObject) pr2.readObject();

    PEMReader kr = new PEMReader(new FileReader("001.key"),
            new PasswordFinder() {
                public char[] getPassword() {
                    return "password".toCharArray();
                }
            });

    KeyStore trustKeys = KeyStore.getInstance("JKS");
    trustKeys.load(null, "".toCharArray());
    trustKeys.setCertificateEntry("1", cert);

    KeyStore ksKeys = KeyStore.getInstance("JKS");
    ksKeys.load(null, "password".toCharArray());
    ksKeys.setCertificateEntry("1", cert2);

    org.bouncycastle.jce.provider.JCERSAPrivateCrtKey key;
    Object PK = kr.readObject();

    if (PK instanceof KeyPair) {
        key = (JCERSAPrivateCrtKey) ((KeyPair) PK).getPrivate();
    } else {
        key = (JCERSAPrivateCrtKey) PK;
    }

    ksKeys.setKeyEntry("1", key, "password".toCharArray(), new Certificate[] { cert2 });

    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    kmf.init(ksKeys, "password".toCharArray());

    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
    tmf.init(trustKeys);

    SSLContext sslContext = SSLContext.getInstance("SSLv3");
    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new java.security.SecureRandom());

    SSLServerSocketFactory factory = sslContext.getServerSocketFactory();
    return factory;
}

Code of server :

    InputStream is = new BufferedInputStream(socket.getInputStream());
        while (!Thread.currentThread().isInterrupted()) {
            int size = 0;
            String mess_length = "";
            byte[] lenbuf = new byte[4];
            if (socket != null && socket.isConnected()) {
                socket.getInputStream().read(lenbuf);
                mess_length = new String(lenbuf);
                log.debug("Lenth of received message: " + mess_length);
            }
            int responseSize = 0;
            try {
                responseSize = Integer.valueOf(mess_length);
                size = responseSize;
            } catch (Exception int_e) {
                log.debug("Error of message lenth numbering: ", int_e);

            }
            byte[] buf = new byte[size];
            if (socket.isConnected() && socket.getInputStream().read(buf) == size) {
                log.debug("Message received.");
            }

            // -----------------------------------------------------------------------------------------------------------
            OutputStream out = new BufferedOutputStream(socket.getOutputStream());
            if ("echo".equals(EnvironmentProperties.getMode())) {
                log.info("responsing in echo mode");
                log.debug("Data to send from server: {} in connection id={}", new String(buf,
                        "UTF-8"), uuid);
                out.write(buf);
            }
            out.flush();
            bytesSet.clear();
            log.info("responded");

log from server:


    17:37:26.166 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - Mess
    age received.
    17:37:26.166 [pool-1-thread-13] INFO  r.b.t.app.server.ConnectionCallable - resp
    onsing in echo mode
    17:37:26.166 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - Data
     to send from server:  in connection id=ee7f73ac-6be9-4e7b-876f-35d31845d69e
    17:37:26.166 [pool-1-thread-13] INFO  r.b.t.app.server.ConnectionCallable - resp
    onded
    17:37:26.166 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - Lent
    h of received message: 200r
    17:37:26.167 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - :
    java.lang.NumberFormatException: For input string: "200r"
            at java.lang.NumberFormatException.forInputString(Unknown Source) ~[na:1
    .8.0_05]
            at java.lang.Integer.parseInt(Unknown Source) ~[na:1.8.0_05]
            at java.lang.Integer.valueOf(Unknown Source) ~[na:1.8.0_05]
            at ru.billing.tcpipServerDummy.app.server.ConnectionCallable.call(Connec
    tionCallable.java:87) [TcpipServerDummy-0.0.1-SNAPSHOT.jar:na]
            at ru.billing.tcpipServerDummy.app.server.ConnectionCallable.call(Connec
    tionCallable.java:1) [TcpipServerDummy-0.0.1-SNAPSHOT.jar:na]
            at java.util.concurrent.FutureTask.run(Unknown Source) [na:1.8.0_05]
            at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na
    :1.8.0_05]
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [n
    a:1.8.0_05]
            at java.lang.Thread.run(Unknown Source) [na:1.8.0_05]
    17:37:26.167 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - Mess
    age received.
    17:37:26.167 [pool-1-thread-13] INFO  r.b.t.app.server.ConnectionCallable - resp
    onsing in echo mode
    17:37:26.167 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - Data
     to send from server:  in connection id=ee7f73ac-6be9-4e7b-876f-35d31845d69e
    17:37:26.168 [pool-1-thread-13] INFO  r.b.t.app.server.ConnectionCallable - resp
    onded
    17:37:26.168 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - Lent
    h of received message: 4♦А
    17:37:26.168 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - ╬°шс
    ър яЁхюсЁрчютрэш  фышэ√ ёююс∙хэш :
    java.lang.NumberFormatException: For input string: "4♦А "
            at java.lang.NumberFormatException.forInputString(Unknown Source) ~[na:1
    .8.0_05]
            at java.lang.Integer.parseInt(Unknown Source) ~[na:1.8.0_05]
            at java.lang.Integer.valueOf(Unknown Source) ~[na:1.8.0_05]
            at ru.billing.tcpipServerDummy.app.server.ConnectionCallable.call(Connec
    tionCallable.java:87) [TcpipServerDummy-0.0.1-SNAPSHOT.jar:na]
            at ru.billing.tcpipServerDummy.app.server.ConnectionCallable.call(Connec
    tionCallable.java:1) [TcpipServerDummy-0.0.1-SNAPSHOT.jar:na]
            at java.util.concurrent.FutureTask.run(Unknown Source) [na:1.8.0_05]
            at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na
    :1.8.0_05]
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [n
    a:1.8.0_05]
            at java.lang.Thread.run(Unknown Source) [na:1.8.0_05]
    17:37:26.168 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - Mess
    age received.
    17:37:26.168 [pool-1-thread-13] INFO  r.b.t.app.server.ConnectionCallable - resp
    onsing in echo mode
    17:37:26.168 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - Data
     to send from server:  in connection id=ee7f73ac-6be9-4e7b-876f-35d31845d69e
    17:37:26.168 [pool-1-thread-13] INFO  r.b.t.app.server.ConnectionCallable - resp
    onded
    17:37:26.168 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - Lent
    h of received message: ┴А 2
    17:37:26.169 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - ╬°шс
    ър яЁхюсЁрчютрэш  фышэ√ ёююс∙хэш :
    java.lang.NumberFormatException: For input string: "┴А 2"
            at java.lang.NumberFormatException.forInputString(Unknown Source) ~[na:1
    .8.0_05]
            at java.lang.Integer.parseInt(Unknown Source) ~[na:1.8.0_05]
            at java.lang.Integer.valueOf(Unknown Source) ~[na:1.8.0_05]
            at ru.billing.tcpipServerDummy.app.server.ConnectionCallable.call(Connec
    tionCallable.java:87) [TcpipServerDummy-0.0.1-SNAPSHOT.jar:na]
            at ru.billing.tcpipServerDummy.app.server.ConnectionCallable.call(Connec
    tionCallable.java:1) [TcpipServerDummy-0.0.1-SNAPSHOT.jar:na]
            at java.util.concurrent.FutureTask.run(Unknown Source) [na:1.8.0_05]
            at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na
    :1.8.0_05]
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [n
    a:1.8.0_05]
            at java.lang.Thread.run(Unknown Source) [na:1.8.0_05]
    17:37:26.169 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - Mess
    age received.
    17:37:26.169 [pool-1-thread-13] INFO  r.b.t.app.server.ConnectionCallable - resp
    onsing in echo mode
    17:37:26.169 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - Data
     to send from server:  in connection id=ee7f73ac-6be9-4e7b-876f-35d31845d69e
    17:37:26.169 [pool-1-thread-13] INFO  r.b.t.app.server.ConnectionCallable - resp
    onded
    17:37:26.169 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - Lent
    h of received message: 1194
    17:37:26.169 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - ╧Ёхю
    сЁрчютрээр  фышээр ёююс∙хэш : 1194
    17:37:26.169 [pool-1-thread-13] INFO  r.b.t.app.server.ConnectionCallable - resp
    onsing in echo mode
    17:37:26.169 [pool-1-thread-13] DEBUG r.b.t.app.server.ConnectionCallable - Data
     to send from server: 6817121021052420000000000000000100000730173724000048001121
    101581111310001749439  749138         00809203123643













                     in connection id=ee7f73ac-6be9-4e7b-876f-35d31845d69e


Answer:

Usual problem. You're ignoring the result returned by read() at one point and assuming it fills the length buffer, and then if the next read doesn't return exactly that number of bytes you're ignoring the bytes actually returned as well. You need to store the result returned by read() into a variable, and:

  • test it for -1, indicating end of stream
  • otherwise keep looping until you get an entire message, however that's defined in your application protocol.

Other problems:

  • The Socket.isConnected() test here is pointless. It won't magically become false if the peer disconnects. You have to detect that by getting -1 from read(), null from readLine(), etc.

  • Ditto the socket == null test. It already must be non-null otherwise you would have thrown an NPE in socket.getOutputStream().

  • You're creating a new BufferedOutputStream every time. You should use one for the life of the socket.

Question:

I'm trying to implement a TCP client/server application with Spring Integration where I need to open one TCP client socket per incoming TCP server connection.

Basically, I have a bunch of IoT devices that communicate with a backend server over raw TCP sockets. I need to implement extra features into the system. But the software on both the devices and the server are closed source so I can't do anything about that. So my thought was to place middleware between the devices and the server that will intercept this client/server communication and provide the added functionality.

I'm using a TcpNioServerConnectionFactory and a TcpNioClientConnectionFactory with inbound/outbound channel adapters to send/receive messages to/from all parties. But there's no information in the message structure that binds a message to a certain device; therefore I have to open a new client socket to the backend every time a new connection from a new device comes on the server socket. This client connection must be bound to that specific server socket's lifecycle. It must never be reused and if this client socket (backend to middleware) dies for any reason, the server socket (middleware to device) must also be closed. How can I go about this?

Edit: My first thought was to subclass AbstractClientConnectionFactory but it appears that it doesn't do anything except provide a client connection when asked. Should I rather look into subclassing inbound/outbound channel adapters or elsewhere? I should also mention that I'm also open to non-Spring integration solutions like Apache Camel, or even a custom solution with raw NIO sockets.

Edit 2: I got halfway there by switching to TcpNetServerConnectionFactory and wrapping the client factory with a ThreadAffinityClientConnectionFactory and the devices can reach the backend fine. But when the backend sends something back, I get the error Unable to find outbound socket for GenericMessage and the client socket dies. I think it's because the backend side doesn't have the necessary header to route the message correctly. How can I capture this info? My configuration class is as follows:

@Configuration
@EnableIntegration
@IntegrationComponentScan
public class ServerConfiguration {

    @Bean
    public AbstractServerConnectionFactory serverFactory() {
        AbstractServerConnectionFactory factory = new TcpNetServerConnectionFactory(8000);
        factory.setSerializer(new MapJsonSerializer());
        factory.setDeserializer(new MapJsonSerializer());
        return factory;
    }

    @Bean
    public AbstractClientConnectionFactory clientFactory() {
        AbstractClientConnectionFactory factory = new TcpNioClientConnectionFactory("localhost", 3333);
        factory.setSerializer(new MapJsonSerializer());
        factory.setDeserializer(new MapJsonSerializer());
        factory.setSingleUse(true);
        return new ThreadAffinityClientConnectionFactory(factory);
    }

    @Bean
    public TcpReceivingChannelAdapter inboundDeviceAdapter(AbstractServerConnectionFactory connectionFactory) {
        TcpReceivingChannelAdapter inbound = new TcpReceivingChannelAdapter();
        inbound.setConnectionFactory(connectionFactory);
        return inbound;
    }

    @Bean
    public TcpSendingMessageHandler outboundDeviceAdapter(AbstractServerConnectionFactory connectionFactory) {
        TcpSendingMessageHandler outbound = new TcpSendingMessageHandler();
        outbound.setConnectionFactory(connectionFactory);
        return outbound;
    }

    @Bean
    public TcpReceivingChannelAdapter inboundBackendAdapter(AbstractClientConnectionFactory connectionFactory) {
        TcpReceivingChannelAdapter inbound = new TcpReceivingChannelAdapter();
        inbound.setConnectionFactory(connectionFactory);
        return inbound;
    }

    @Bean
    public TcpSendingMessageHandler outboundBackendAdapter(AbstractClientConnectionFactory connectionFactory) {
        TcpSendingMessageHandler outbound = new TcpSendingMessageHandler();
        outbound.setConnectionFactory(connectionFactory);
        return outbound;
    }

    @Bean
    public IntegrationFlow backendIntegrationFlow() {
        return IntegrationFlows.from(inboundBackendAdapter(clientFactory()))
                .log(LoggingHandler.Level.INFO)
                .handle(outboundDeviceAdapter(serverFactory()))
                .get();
    }

    @Bean
    public IntegrationFlow deviceIntegrationFlow() {
        return IntegrationFlows.from(inboundDeviceAdapter(serverFactory()))
                .log(LoggingHandler.Level.INFO)
                .handle(outboundBackendAdapter(clientFactory()))
                .get();
    }
}

Answer:

It's not entirely clear what you are asking so I am going to assume that you mean you want a spring integration proxy between your clients and servers. Something like:

iot-device -> spring server -> message-transformation -> spring client -> back-end-server

If that's the case, you can implement a ClientConnectionIdAware client connection factory that wraps a standard factory.

In the integration flow, bind the incoming ip_connectionId header in a message to the thread (in a ThreadLocal).

Then, in the client connection factory, look up the corresponding outgoing connection in a Map using the ThreadLocal value; if not found (or closed), create a new one and store it in the map for future reuse.

Implement an ApplictionListener (or @EventListener) to listen for TcpConnectionCloseEvents from the server connection factory and close() the corresponding outbound connection.

This sounds like a cool enhancement so consider contributing it back to the framework.

EDIT

Version 5.0 added the ThreadAffinityClientConnectionFactory which would work out of the box with a TcpNetServerConnectionFactory since each connection gets its own thread.

With a TcpNioServerConnectionFactory you would need the extra logic to dynamically bind the connection to the thread for each request.

EDIT2

@SpringBootApplication
public class So51200675Application {

    public static void main(String[] args) {
        SpringApplication.run(So51200675Application.class, args).close();
    }

    @Bean
    public ApplicationRunner runner() {
        return args -> {
            Socket socket = SocketFactory.getDefault().createSocket("localhost", 1234);
            socket.getOutputStream().write("foo\r\n".getBytes());
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println(reader.readLine());
            socket.close();
        };
    }

    @Bean
    public Map<String, String> fromToConnectionMappings() {
        return new ConcurrentHashMap<>();
    }

    @Bean
    public Map<String, String> toFromConnectionMappings() {
        return new ConcurrentHashMap<>();
    }

    @Bean
    public IntegrationFlow proxyInboundFlow() {
        return IntegrationFlows.from(Tcp.inboundAdapter(serverFactory()))
                .transform(Transformers.objectToString())
                .<String, String>transform(s -> s.toUpperCase())
                .handle((p, h) -> {
                    mapConnectionIds(h);
                    return p;
                })
                .handle(Tcp.outboundAdapter(threadConnectionFactory()))
                .get();
    }

    @Bean
    public IntegrationFlow proxyOutboundFlow() {
        return IntegrationFlows.from(Tcp.inboundAdapter(threadConnectionFactory()))
                .transform(Transformers.objectToString())
                .<String, String>transform(s -> s.toUpperCase())
                .enrichHeaders(e -> e
                        .headerExpression(IpHeaders.CONNECTION_ID, "@toFromConnectionMappings.get(headers['"
                                + IpHeaders.CONNECTION_ID + "'])").defaultOverwrite(true))
                .handle(Tcp.outboundAdapter(serverFactory()))
                .get();
    }

    private void mapConnectionIds(Map<String, Object> h) {
        try {
            TcpConnection connection = threadConnectionFactory().getConnection();
            String mapping = toFromConnectionMappings().get(connection.getConnectionId());
            String incomingCID = (String) h.get(IpHeaders.CONNECTION_ID);
            if (mapping == null || !(mapping.equals(incomingCID))) {
                System.out.println("Adding new mapping " + incomingCID + " to " + connection.getConnectionId());
                toFromConnectionMappings().put(connection.getConnectionId(), incomingCID);
                fromToConnectionMappings().put(incomingCID, connection.getConnectionId());
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Bean
    public ThreadAffinityClientConnectionFactory threadConnectionFactory() {
        return new ThreadAffinityClientConnectionFactory(clientFactory()) {

            @Override
            public boolean isSingleUse() {
                return false;
            }

        };
    }

    @Bean
    public AbstractServerConnectionFactory serverFactory() {
        return Tcp.netServer(1234).get();
    }

    @Bean
    public AbstractClientConnectionFactory clientFactory() {
        AbstractClientConnectionFactory clientFactory = Tcp.netClient("localhost", 1235).get();
        clientFactory.setSingleUse(true);
        return clientFactory;
    }

    @Bean
    public IntegrationFlow serverFlow() {
        return IntegrationFlows.from(Tcp.inboundGateway(Tcp.netServer(1235)))
                .transform(Transformers.objectToString())
                .<String, String>transform(p -> p + p)
                .get();
    }

    @Bean
    public ApplicationListener<TcpConnectionCloseEvent> closer() {
        return e -> {
            if (fromToConnectionMappings().containsKey(e.getConnectionId())) {
                String key = fromToConnectionMappings().remove(e.getConnectionId());
                toFromConnectionMappings().remove(key);
                System.out.println("Removed mapping " + e.getConnectionId() + " to " + key);
                threadConnectionFactory().releaseConnection();
            }
        };
    }

}

EDIT3

Works fine for me with a MapJsonSerializer.

@SpringBootApplication
public class So51200675Application {

    public static void main(String[] args) {
        SpringApplication.run(So51200675Application.class, args).close();
    }

    @Bean
    public ApplicationRunner runner() {
        return args -> {
            Socket socket = SocketFactory.getDefault().createSocket("localhost", 1234);
            socket.getOutputStream().write("{\"foo\":\"bar\"}\n".getBytes());
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println(reader.readLine());
            socket.close();
        };
    }

    @Bean
    public Map<String, String> fromToConnectionMappings() {
        return new ConcurrentHashMap<>();
    }

    @Bean
    public Map<String, String> toFromConnectionMappings() {
        return new ConcurrentHashMap<>();
    }

    @Bean
    public MapJsonSerializer serializer() {
        return new MapJsonSerializer();
    }

    @Bean
    public IntegrationFlow proxyRequestFlow() {
        return IntegrationFlows.from(Tcp.inboundAdapter(serverFactory()))
                .<Map<String, String>, Map<String, String>>transform(m -> {
                    m.put("foo", m.get("foo").toUpperCase());
                    return m;
                })
                .handle((p, h) -> {
                    mapConnectionIds(h);
                    return p;
                })
                .handle(Tcp.outboundAdapter(threadConnectionFactory()))
                .get();
    }

    @Bean
    public IntegrationFlow proxyReplyFlow() {
        return IntegrationFlows.from(Tcp.inboundAdapter(threadConnectionFactory()))
                .<Map<String, String>, Map<String, String>>transform(m -> {
                    m.put("foo", m.get("foo").toLowerCase() + m.get("foo"));
                    return m;
                })
                .enrichHeaders(e -> e
                        .headerExpression(IpHeaders.CONNECTION_ID, "@toFromConnectionMappings.get(headers['"
                                + IpHeaders.CONNECTION_ID + "'])").defaultOverwrite(true))
                .handle(Tcp.outboundAdapter(serverFactory()))
                .get();
    }

    private void mapConnectionIds(Map<String, Object> h) {
        try {
            TcpConnection connection = threadConnectionFactory().getConnection();
            String mapping = toFromConnectionMappings().get(connection.getConnectionId());
            String incomingCID = (String) h.get(IpHeaders.CONNECTION_ID);
            if (mapping == null || !(mapping.equals(incomingCID))) {
                System.out.println("Adding new mapping " + incomingCID + " to " + connection.getConnectionId());
                toFromConnectionMappings().put(connection.getConnectionId(), incomingCID);
                fromToConnectionMappings().put(incomingCID, connection.getConnectionId());
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Bean
    public ThreadAffinityClientConnectionFactory threadConnectionFactory() {
        return new ThreadAffinityClientConnectionFactory(clientFactory()) {

            @Override
            public boolean isSingleUse() {
                return false;
            }

        };
    }

    @Bean
    public AbstractServerConnectionFactory serverFactory() {
        return Tcp.netServer(1234)
                .serializer(serializer())
                .deserializer(serializer())
                .get();
    }

    @Bean
    public AbstractClientConnectionFactory clientFactory() {
        AbstractClientConnectionFactory clientFactory = Tcp.netClient("localhost", 1235)
                .serializer(serializer())
                .deserializer(serializer())
                .get();
        clientFactory.setSingleUse(true);
        return clientFactory;
    }

    @Bean
    public IntegrationFlow backEndEmulatorFlow() {
        return IntegrationFlows.from(Tcp.inboundGateway(Tcp.netServer(1235)
                    .serializer(serializer())
                    .deserializer(serializer())))
                .<Map<String, String>, Map<String, String>>transform(m -> {
                    m.put("foo", m.get("foo") + m.get("foo"));
                    return m;
                })
                .get();
    }

    @Bean
    public ApplicationListener<TcpConnectionCloseEvent> closer() {
        return e -> {
            if (fromToConnectionMappings().containsKey(e.getConnectionId())) {
                String key = fromToConnectionMappings().remove(e.getConnectionId());
                toFromConnectionMappings().remove(key);
                System.out.println("Removed mapping " + e.getConnectionId() + " to " + key);
                threadConnectionFactory().releaseConnection();
            }
        };
    }

}

and

Adding new mapping localhost:56998:1234:55c822a4-4252-45e6-9ef2-79263391f4be to localhost:1235:56999:3d520ca9-2f3a-44c3-b05f-e59695b8c1b0 {"foo":"barbarBARBAR"} Removed mapping localhost:56998:1234:55c822a4-4252-45e6-9ef2-79263391f4be to localhost:1235:56999:3d520ca9-2f3a-44c3-b05f-e59695b8c1b0

Question:

I've a TCP client which was built using spring integration TCP and the server supports a keep alive message (ping/pong style). The connections were configured using a CachingClientConnectionFactory and I'd like to take advantage on this server feature. Here's my bean configuration:

private static final int SERIALIZER_HEADER_SIZE = 2;

/**
 * Serializer used by connection factory to send and receive messages
 */
@Bean
public ByteArrayLengthHeaderSerializer byteArrayLengthHeaderSerializer() {
    return new ByteArrayLengthHeaderSerializer(SERIALIZER_HEADER_SIZE);
}

@Bean
public AbstractClientConnectionFactory tcpClientConnectionFactory() {
    TcpNetClientConnectionFactory connFactory =
        new TcpNetClientConnectionFactory(props.getUrl(), props.getPort());
    connFactory.setSerializer(byteArrayLengthHeaderSerializer());
    connFactory.setDeserializer(byteArrayLengthHeaderSerializer());
    connFactory.setSoTimeout(props.getSoTimeout());
    if (props.isUseSSL()) {
        connFactory.setTcpSocketFactorySupport(new DefaultTcpNetSSLSocketFactorySupport(() -> {
            return SSLContext.getDefault();
        }));
    }

    return connFactory;
}

/**
 * Connection factory used to create TCP client socket connections
 */
@Bean
public AbstractClientConnectionFactory tcpCachedClientConnectionFactory() {
    CachingClientConnectionFactory cachingConnFactory =
        new CachingClientConnectionFactory(tcpClientConnectionFactory(), props.getMaxPoolSize());
    cachingConnFactory.setConnectionWaitTimeout(props.getMaxPoolWait());
    return cachingConnFactory;
}

Using the solution posted here Configure keep alive to keep connection alive all the time I can keep the connection opened but I also wanted to take leverage on those server keep alive messages and send those messages from time to time to check if the connection is still alive. This can improve the performance on the client side since it won't need to re-connect/create a new connection if the socket was closed.

Based on that, does anyone has a suggestion on how to implement this using spring integration?


Answer:

When using a simple client connection factory, it's easy enough to set up application-level heartbeat messages with an @InboundChannelAdapter.

Simple example:

@SpringBootApplication
public class So46918267Application {

    public static void main(String[] args) throws IOException {
        // Simulated Server
        final ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(1234);
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(() -> {
            try {
                Socket socket = server.accept();
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println(line);
                    if (line.equals("keep_alive")) {
                        socket.getOutputStream().write("OK\r\n".getBytes());
                    }
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        });
        ConfigurableApplicationContext context = SpringApplication.run(So46918267Application.class, args);
        System.out.println("Hit enter to terminate");
        System.in.read();
        executor.shutdownNow();
        context.close();
        server.close();
    }

    @Bean
    public TcpNetClientConnectionFactory client() {
        return new TcpNetClientConnectionFactory("localhost", 1234);
    }

    @ServiceActivator(inputChannel = "toTcp")
    @Bean
    public TcpOutboundGateway gateway() {
        TcpOutboundGateway gateway = new TcpOutboundGateway();
        gateway.setConnectionFactory(client());
        return gateway;
    }

    // HEARTBEATS

    private final Message<?> heartbeatMessage = MessageBuilder.withPayload("keep_alive")
            .setReplyChannelName("heartbeatReplies")
            .build();

    @InboundChannelAdapter(channel = "toTcp", poller = @Poller(fixedDelay = "25000"))
    public Message<?> heartbeat() {
        return this.heartbeatMessage;
    }

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

}

When using the CachingClientConnectionFactory, though, it's not clear why you would want to keep a pool of idle connections open. However, the way the pool works is the idle connections are kept in a queue so each request would go to the oldest connection and the connection is returned to the end of the queue.

Adding maxMessagesPerPoll would emit that number of messages on each poll and...

@InboundChannelAdapter(channel = "toTcp", 
    poller = @Poller(fixedDelay = "25000", maxMessagesPerPoll = "5"))

would keep up to 5 connections open. It won't open new connections (if there's at least one) but if the pool contains 5 or more connections, at least 5 will be kept open. If there are no open connections, it will open just one.

Question:

I've been looking at the Netty javadocs for hours and I still can't figure this out. How do I open a plain old TCP connection, e.g. to an IRC server, in Netty?


Answer:

you can find many demo in github of netty

Assumeing that you are using the netty5 in server . you should add the decoder and encoder to your pipeline. like below

 socketChannel.pipeline().addLast(new StringEncoder() ,new StringDecoder() ,new LineBasedFrameDecoder(1024));

here is my server demo

String  ip ;
int port  = 9999;

NioEventLoopGroup   workGroup = new NioEventLoopGroup(8);
NioEventLoopGroup  bossGroup = new NioEventLoopGroup();
try {
    bootstrap = new ServerBootstrap();
    bootstrap.group(bossGroup, workGroup);
    bootstrap.channel(NioServerSocketChannel.class);
    bootstrap.option(ChannelOption.SO_BACKLOG, 100);
    bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {
            socketChannel.pipeline().addLast(new StringEncoder() ,new StringDecoder() ,new LineBasedFrameDecoder(1024));
            socketChannel.pipeline().addLast(new ChannelHandlerAdapter() {
                @Override
                public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
                    System.out.println("the num" +num.getAndIncrement());
                }

                @Override
                public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                    System.out.println("what i say is :" + msg.toString());
                    ctx.channel().writeAndFlush("from server " + "reply message is " +msg.toString()+"\n");

                }
            });
        }
    });
   ChannelFuture future =  bootstrap.bind(port).sync();
    System.out.println("Server start at port : " + port);
    future.channel().closeFuture().sync();
}catch (Exception e){
    System.out.println("error");
}finally {
    bossGroup.shutdownGracefully();
    workGroup.shutdownGracefully();
}


}

then you can use the blocking socket to connect it as normal . here is my client demo.

Socket socket = new Socket();
    try {
        socket.connect(new InetSocketAddress("localhost" , 9999));
        InputStream inputStream = socket.getInputStream();
        OutputStream outputStream  = socket.getOutputStream();
        outputStream.write("hello".getBytes());
        outputStream.flush();
        InputStreamReader reader = new InputStreamReader(inputStream) ;
        char [] temChar  = new char[40];
        StringBuffer buffer = new StringBuffer( );

        while (reader.read(temChar) != -1){
            buffer.append(temChar);
            System.out.println(buffer.toString() +"\n");
        }

    } catch (IOException e) {
        e.printStackTrace();
    }

then i send "hello" and it reply the same word .

here is my client netty demo

int port  = 9999;
Bootstrap bootstrap ;
NioEventLoopGroup workGroup = new NioEventLoopGroup(8);



    try {
        bootstrap = new Bootstrap();
        bootstrap.group(workGroup);
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                socketChannel.pipeline().addLast( new StringDecoder() ,new StringEncoder( )  , new LineBasedFrameDecoder(1024), new ChannelHandlerAdapter(){
                    @Override
                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                        System.out.println("recieve method of client : " +msg.toString());
                    }
                });
            }
        });


       NioSocketChannel nioSocketChannel ;

        ChannelFuture future = bootstrap.connect("localhost" , 9999).sync();

        //you can also invoke writeAndFlush() in other thread with channel ,
        //  it is the same as  server   
        System.out.println("try to write hello");
        Channel  channel = future.channel();
        channel.writeAndFlush("hello\n\r");


        future.channel().closeFuture().sync();   //it will block until 
                                                  //   you invoke 
                                                   //   channel.close(); 




        System.out.println("finish: " + port);

    }catch (Exception e){
        e.printStackTrace();
        System.out.println("error");
    }finally {

        workGroup.shutdownGracefully();
    }


}

Question:

Jetty connections in CLOSE_WAIT are not getting closed. Embedded jetty(9.4.11) is used with Glassfish for container & with dependency injection. Ngnix load balancer is forwarding request to jetty acting as a client. At Ngnix server(Client) the jetty TCP request/connection is going in FIN_WAIT2 state and then finally getting closed however on jetty(Server) connection are going in close_wait forever and not getting closed.

Any possible solution or configuration change to resolve it?

Reference: Jetty open issue link. Jetty-9.2 connections in CLOSE_WAIT are not closed

Http configuration(jetty.xml):

<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
    <Set name="secureScheme">http</Set>
    <Set name="securePort"><Property name="jetty.secure.port" default="8443" /></Set>
    <Set name="outputBufferSize"><Property name="jetty.output.buffer.size" default="32768" /></Set>
    <Set name="outputAggregationSize"><Property name="jetty.output.aggregation.size" default="8192" /></Set>
    <Set name="requestHeaderSize"><Property name="jetty.request.header.size" default="8192" /></Set>
    <Set name="responseHeaderSize"><Property name="jetty.response.header.size" default="8192" /></Set>
    <Set name="sendServerVersion"><Property name="jetty.send.server.version" default="false" /></Set>
    <Set name="sendDateHeader"><Property name="jetty.send.date.header" default="false" /></Set>
    <Set name="headerCacheSize"><Property name="jetty.header.cache.size" default="512" /></Set>
    <Set name="delayDispatchUntilContent"><Property name="jetty.delayDispatchUntilContent" default="false"/></Set>
    <Set name="persistentConnectionsEnabled"><Property name="jetty.persistentConnectionsEnabled" default="false"/>false</Set>
    <Call name="addCustomizer">
        <Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
    </Call>
</New>

<Call id="httpsConnector" name="addConnector">
    <Arg>
        <New class="org.eclipse.jetty.server.ServerConnector">
            <Arg name="server"><Ref refid="Server" /></Arg>
            <Arg name="acceptors" type="int"><Property name="ssl.acceptors" default="5"/></Arg>
            <Arg name="selectors" type="int"><Property name="ssl.selectors" default="0"/></Arg>
            <Arg name="factories">
                <Array type="org.eclipse.jetty.server.ConnectionFactory">         
                    <Item>
                        <New class="org.eclipse.jetty.server.HttpConnectionFactory">
                            <Arg name="config"><Ref refid="httpConfig"/></Arg>
                        </New>
                    </Item>
                </Array>
            </Arg> 
            <Set name="host"><Property name="jetty.host" /></Set>
            <Set name="port"><Property name="http.port" default="8443" /></Set>
            <Set name="idleTimeout"><Property name="https.timeout" default="30000"/></Set>
            <Set name="acceptorPriorityDelta"><Property name="ssl.acceptorPriorityDelta" default="0"/></Set>
            <Set name="acceptQueueSize"><Property name="https.acceptQueueSize" default="150"/></Set>
        </New>
    </Arg>
</Call>

Answer:

By analysing thread dump I figured out application threads are going in waiting state ( java.lang.Thread.State: WAITING (parking)) causing total lockup. Other library used by the application deployed in Jetty cause the thread wait not jetty.

Question:

My Java application establishes TCP connection with a server and communicates with it every second by sending and receiving messages. Both server and client are run on the same Mac. In about 15-20 minutes, my server crashes with error "Errno::EMFILE Too many files open". Here is my client code:

package testtcp;

import java.awt.Dimension;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class TestTCP extends  JPanel
{
    JFrame frame = new JFrame("Button Demo");

    ScheduledExecutorService executorService;

    private Socket socket = null;
    private DataInputStream input = null;
    private DataOutputStream output = null;
    private BufferedReader br = null;

    private boolean isMapUpdating = false;


    public TestTCP() 
    {
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setPreferredSize(new Dimension(300,300));
        frame.add(this);

        JButton b1 = new JButton("BLACK");
        b1.setPreferredSize(new Dimension(150,50));
        b1.setFocusPainted(false); // get rid of border around text
        add(b1);
        b1.addActionListener((java.awt.event.ActionEvent evt) -> 
        {
            startAcarsConnection();
        });

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

    }


    public void startAcarsConnection()
    {
        start();

    }

    public void start() 
    {
        System.out.println("THREAD START");

        // Default timer rate
        int timerRate = 1;

        executorService = Executors.newSingleThreadScheduledExecutor();

        executorService.scheduleAtFixedRate(new Runnable() 
        {
            @Override
            public void run() 
            {
                // Create new TCP connection if the map is not currently updating
                if(isMapUpdating == false)
                {
                    isMapUpdating = true;

                    communicateWithServer();
                }
            }
        }, 0, timerRate, TimeUnit.SECONDS);
    }


    public void stop() 
    {
        executorService.shutdown();
    }

    public void communicateWithServer()
    {
        // Create a message to the server
        String messageToServer = makeMessageToServer();

        // Connect to the client and receive the response    
        String messageFromServer = connectToClient(messageToServer);

        SwingUtilities.invokeLater(() ->
        {
            messageReceived(messageFromServer);
        });

    }


    public String connectToClient(String messageToServer)
    {
        String data = "";
        // Message from the server that should terminate TCP connection
        String  terminator = "END_IGOCONNECT_DATA";

        try
        {
            // Create socket and streams
            socket = new Socket("192.168.1.2", 7767);
            input = new DataInputStream( socket.getInputStream());
            output = new DataOutputStream( socket.getOutputStream());

            //Send message to the server
            output.writeBytes(messageToServer);


            System.out.println("MESSAGE TO SERVER FROM CONNECT TO CLIENT: "+messageToServer);


            //Read Response
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            StringBuilder sb = new StringBuilder();
            String s = "";
            int value;

            // Process the message from the server and add to the StringBuilder
            while((value = br.read()) != -1) 
            {
                // converts int to character
                char c = (char)value;

                sb.append(c);

                if(sb.toString().contains(terminator))
                {
                    break;
                }
            }

            // Create the final string
            data = sb.toString();
        }

        catch (UnknownHostException e)
        {
            System.out.println("Sock:"+e.getMessage());

            // Close Connection
            cancelConnection();

            // Pop-up message that the airport was not found
            String message = "Application was not able to establish connection with X-Plane.\n"
                    + "Check whether IP Address and Port number were correctly entered in Settings.\n"
                    + "Check whether connection is not being blocked by your firewall.";
            JOptionPane.showMessageDialog(new JFrame(), message, "TCP Connection Error: UnknownHostException",
            JOptionPane.ERROR_MESSAGE);

            data = "ERROR";
        }

        catch (EOFException e)
        {
            System.out.println("EOF:"+e.getMessage()); 

            // Close Connection
            cancelConnection();

            // Pop-up message that the airport was not found
            String message = "Application was not able to establish connection with X-Plane.\n"
                    + "Check whether IP Address and Port number were correctly entered in Settings.\n"
                    + "Check whether connection is not being blocked by your firewall.";
            JOptionPane.showMessageDialog(new JFrame(), message, "TCP Connection Error: EOFException",
            JOptionPane.ERROR_MESSAGE);

            data = "ERROR";
        }

        catch (IOException e)
        {
            System.out.println("IO:"+e.getMessage());

            // Close Connection
            cancelConnection();

            // Pop-up message that the server was not found
            if(!e.getMessage().equals("Socket closed"))
            {
                String message = "Application was not able to establish connection with X-Plane.\n"
                    + "Check whether IP Address and Port number were correctly entered in Settings.\n"
                    + "Check whether connection is not being blocked by your firewall.";
                JOptionPane.showMessageDialog(new JFrame(), message, "TCP Connection Error: IOException",
                JOptionPane.ERROR_MESSAGE);
            }
            // "Connection reset"

            data = "ERROR";
        }

        finally 
        {
            // TO DO!!! DISABLED FOR NOW!! closeSocketPax();
        }

        return data;
    } 


    public void cancelConnection()
    {

        executorService.shutdown();

        closeSocketPax();

        SwingUtilities.invokeLater(() ->
        {
            System.out.println("Cancel Connection");
        });
    }


    private void closeSocketPax()
    {
        try
        {   
            if(socket!=null) { socket.close();}
            if(input != null) { input.close();}
            if(output != null) { output.close();}
            if(br != null) { br.close();}
        }
        catch (IOException ex) 
        {
            String message = "Error closing socket.";
            JOptionPane.showMessageDialog(new JFrame(), message, "TCP Connection Error: IOException",
            JOptionPane.ERROR_MESSAGE);
        }
        socket = null;
        input = null;
        output = null;
        br = null;
    }

    private String makeMessageToServer()
    {
        return "MESSAGE TO SERVER";
    }

    private void messageReceived(String message)
    {
        System.out.println("MESSAGE RECEIVED: "+message);

        isMapUpdating = false;
    }


    public static void main(String[] args) 
    {    
       new TestTCP();
   }
}

I have been trying to solve this for almost a month already! Does anyone see a problem in the code and know how to mitigate the problem? Greatly appreciated!


Answer:

Each connection you create uses a file descriptor. In any operating system there is a limit to the number of descriptors your process can have. For example, in the Linux environment I'm on the limit is 1024. Different O/S's have different limits but in Unix derived environments like Linux and Mac O/S you can run ulimit -n to see what the limit is.

In your code you do:

socket = new Socket("192.168.1.2", 7767);

in the connectToClient method. Each time you do that and you don't close the socket you use up a file descriptor. Eventually you reach the O/S defined limit and you get, in Mac O/S the Errno::EMFILE error.

You have two choices to fix this. The first is pretty much what you have commented out - close the connection when you're done with it. However, as you indicate in the comments this is occurring very frequently and you don't want to incur the overhead of opening and closing constantly.

That brings us to the second choice - reuse the connection. A socket can send data over and over again if the protocol you're designing handles it. Send the data back and forth over the protocol and reuse the Socket.

A warning though - if your physical connection is somehow severed - for example, you switch from Ethernet to Wi-Fi - your service will still need to deal with possible errors. Your code has most of that but you may want to consider closing and attempting to reconnect when this occurs.

Question:

Here is use case I need to implement in Java:

  1. Server is listening for push messages from some clients
  2. If client has some data to push into server, it opens TCP connection and sends all messages
  3. When client sends last message (special message saying that this is the last one) server should close connection by starting TCP closing handshake

I have problem with last step because I don't know how to close connection from server site. My current code is bellow. How to initiate connection closing TCP handshake form server site? Thank you for any help.

public class Server{

public static void main(String[] args) throws Exception {

    while (true) {
        int port = AppConfig.getInstance().getPort();

        try (ServerSocket socket = new ServerSocket(port)) {
            Socket server = socket.accept();

            InetAddress ipAddress = server.getInetAddress();

            MessageHandler handler = new MessageHandler(ipAddress);

            InputStream in = server.getInputStream();

            // reads all bytes from input stream and process them by given handler
            processStream(in, handler);
            in.close();

            server.close();
        } catch (Exception e) {
            LoggingUtils.logException(e);
        }   
    }
}

private static void processStream(InputStream in, MessageHandler handler) throws Exception {
    // implementation is omitted
}

}


Answer:

You've done it. in.close() closes the input stream, the socket output stream, and the socket.

What you should really close is whatever output stream was attached to the socket, to ensure it gets flushed, and you should probably do that in the processStream() method, with a saver server .close() in a finally block in the calling method.

NB Your socket names are really the wrong way round. It is customary to use ServerSocket serverSocket, and Socket socket = serverSocket.accept().

Question:

I'm creating a game server for a University project so I'm doing this without using any libraries / frameworks.

After a lot of research I want the client and server to do the bulk of communication such as character movement and timers using the UDP protocol as the reliability of this aspect of the game is not so important and lost packets can be compensated for.

But I also want to use the TCP protocol for some other aspects of the game such as actions and events where it is critical the information reaches the client.

My problem is that I don't know much about using UDP in general and in Java, from my understanding it is completely different to just having an open Socket object for TCP. I'm thinking that the initial connection between the client and server will be done by TCP then once this connection has been established should the server send a port number back to the client that the client will use to communicate with the server via UDP?

Which brings me to the issue of having multiple clients, do they all need to be allocated different port numbers to connect via UDP to the server? So the server will have 1 different port number for each client connected?

My plan for the server is to have for every client connected 1 sending thread and 1 receiving thread - would I be able to handle both TCP and UDP communications in each of these threads or would there need to be 4 threads for each client with 2 for tcp and 2 for udp?

Again these are just my first thoughts and I don't know much about UDP so sorry if I've got the complete wrong end of the stick! Thanks if anyone can help with any of this though!


Answer:

Should the server send a port number back to the client that the client will use to communicate with the server via UDP?

You can do this, or you can load it from a properties file. Depends on your implementation.

Do [multiple clients] all need to be allocated different port numbers to connect via UDP to the server? So the server will have 1 different port number for each client connected?

No. A server can differentiate which client a packet belongs to from the IP address on the Datagram (UDP) packet that was received.

Would I be able to handle both TCP and UDP communications in each of these threads or would there need to be 4 threads for each client with 2 for tcp and 2 for udp?

You do not need a separate thread for sending data, because this doesn't cause the thread to block. Only receiving causes the thread to block, so your client program would only need 2 communication threads; One to receive TCP, and another to receive UDP communications.

NOTE: Java does handle TCP and UDP communications quite differently. TCP is a stream that you write to (which automatically handles handshaking and packet lose for you), while UDP uses a DatagramPacket object that is populated with bytes and sent.

Question:

I am trying to run the code in a windows comman line and received exception :

D:\dasi\java\javaLab>java ServerClient
java.net.ConnectException: Connection refused: connect
java.lang.StringIndexOutOfBoundsException: String index out of range: -2

D:\dasi\java\javaLab>

in another command line windw :

D:\dasi\java\javaLab>java SocketClient
java.net.ConnectException: Connection timed out: connect

D:\dasi\java\javaLab>

Server code :

import java.io.*;
import java.net.*;
public class ServerClient {
    public ServerClient(int port) {
        Server server = new Server(port);
        server.start();
        Client client = new Client(port);
        client.start();
    }
    public static void main(String[] args) {
        ServerClient s1 = new ServerClient(7777);
    }
}

class Server extends Thread {
    int port;
    ServerSocket server;
    Socket socket;
    DataOutputStream outStream = null;
    DataInputStream inStream = null;
    public Server(int poort) {
        try {
            this.port = port;
            server = new ServerSocket(port);
        }
        catch(Exception e) {
            System.out.println(e.toString());
        }
    }
    public void run() {
        try {
            socket = server.accept();
            outStream = new DataOutputStream(socket.getOutputStream());
            inStream = new DataInputStream(socket.getInputStream());
            System.out.println("server is ok, please continue!");
            while(true) {
                String str = inStream.readUTF();
                System.out.println("The server receive String:"+str);
                outStream.writeUTF(str);
            }
        }
        catch(Exception e) {
            System.out.println(e.toString());
        }
    }
}

class Client extends Thread {
    int port;
    Socket socket;
    DataInputStream inStream = null;
    DataOutputStream outStream = null;
    public Client(int port) {
        try {
            this.port = port;
            socket = new Socket(InetAddress.getLocalHost(),port);
            inStream = new DataInputStream(socket.getInputStream());
            outStream = new DataOutputStream(socket.getOutputStream());
            System.out.println("client is ok, please continue!");
        }
        catch(Exception e) {
            System.out.println(e.toString());
        }
    }
    public void run() {
        try {
            while(true) {
                byte[] b = new byte[1024];
                String str = "";
                int m = System.in.read(b);
                str = new String(b,0,0,m-1);
                outStream.writeUTF(str);
                str = inStream.readUTF();
                System.out.println("The client receive String:"+str);
            }
        }
        catch(Exception e) {
            System.out.println(e.toString());
        }
    }
}

Client code :

import java.net.*;
import java.io.*;
public class SocketClient {
    Socket s = null;
    DataInputStream inStream = null;
    DataOutputStream outStream = null;
    public SocketClient() {
        try {
            init();
            waitData();
        }
        catch(Exception e) {
            System.out.println(e.toString());
        }
    }
    void init() throws Exception {
        s=new Socket("10.15.43.216",8765);
        inStream = new DataInputStream(s.getInputStream());
        outStream = new DataOutputStream(s.getOutputStream());
        s.setSoTimeout(3000);
    }
    void waitData() {
        while(true) {
            try {
                String str = inStream.readUTF();
                System.out.println("Client accept:" +str);
                str = Integer.toString(Integer.parseInt(str)+1);
                outStream.writeUTF(str);
            }
            catch(Exception e) {
                System.out.println(e.toString());
                break;
            }
        }
    }
    public static void main(String[] args) {
        new SocketClient();
    }
}

I am wodering if there's anything wrong in my code or if it was my computer port that cause the problem. Because when I checked my computer port I didn't see 7777. When I issued command netstat -nao | findstr 7777, it returned nothing.

D:\dasi\java\javaLab>netstat -nao | findstr 7777

D:\dasi\java\javaLab>

If it was the port problem, then how to open the 7777 port. I am a newbie here, please help. Thanks a lot!


Answer:

replace

 public Server(int poort) {
    try {
        this.port = port;
        ...
    }
}

with

 public Server(int poort) {
    try {
        this.port = port;
        ...
    }
}

or rather the default value of port is zero, then your serverSocket will bind with 0 port rather than 7777.

and as for this code segment:

public ServerClient(int port) {
    Server server = new Server(port);
    server.start();
    Client client = new Client(port);
    client.start();
}

I am afraid it is easy to make you in trouble, because we cant ensure the server thread will execute before client thread and if client thread execute first when server havent run it will cause error. And you already have a client in another java file, so I cant understand why you have an Client here. Maybe you could remove them, the code can be this:

public ServerClient(int port) {
    Server server = new Server(port);
    server.start();
}

as for Client Code your server socket is 7777 so you should connect 7777 port rather than 8765 in you init method maybe the code can be this:

void init() throws Exception {
    s=new Socket(server name,7777);
    ...
}

Question:

I want to know when and why the "java.net.SocketTimeoutException readtime out" is raised.

    URL obj = new URL(url);
        HttpURLConnection con = (HttpURLConnection) obj.openConnection();
        con.setConnectTimeout(5000);
        con.setReadTimeout(421);

        int responseCode = con.getResponseCode();

        InputStream is =    con.getInputStream();
        System.out.println("Inputstream done");

        FileOutputStream fos = fos = new FileOutputStream("D:\\tryfile\\file1.csv");

        byte[] buffer = new byte[4096];              //declare 4KB buffer
            int len;

            while ((len = is.read(buffer)) > 0) {

                fos.write(buffer, 0, len);
            }

          fos.close();
          is.close();

Here is the question.I set read timeout value 421 and I take "java.net.SocketTimeoutException readtime out" exception at that line 55.

while ((len = is.read(buffer)) > 0) {

So I take the inputstream succesfuly but when I start reading/writing it I take this exception.And I check that the 732 Kb of the file is transfered until the exception.

So I really confused about it.Please explain readtimeout method exactly.


Answer:

It is raised when no data arrives between the inception of the read() call and the expiration of the specified timeout starting at that point. In other words, no data arrived within the timeout period.

So I take the inputstream succesfully

Not surprising. It takes zero time and does nothing on the network, as you have already called getResponseCode() (and done nothing with it).

but when I start reading/writing it I take this exception.

So the data was slow arriving.

And I check that the 732 Kb of the file is transfered until the exception.

So the end of the data was slow arriving.

NB 421ms is far too short for a read timeout. It should be tens of seconds.

Question:

I have a part in code that checks port availability (opens connection and immediately close it) :

try{
   new ServerSocket(currentConnector.getPort()).close();
 }

The porblem here is that the port enters a state of TIME_WAIT which differs from system to system. I want to make sure that after close() the port is available.

One way I can think of is adding 60-90 seconds of sleep. But it doesn't seem very elegant.

Can I validate with Java (w/o bash/batch) that the port was released from TIME_WAIT?

Thanks!


Answer:

  1. The port only enters TIME-WAIT if someone has connected to it.

  2. You can overcome the BindException that results by:

    ServerSocket ss = new ServerSocket();
    ss.setReuseAddress(true);
    ss.bind(new InetSocketAddress(port));
    
  3. However I question the objective. If you want to listen at the port, listen at it, and catch the exception then. If you want to see whether you can connect to it, connect to it, and handle the exception as it arises. The technique of trying to predict the future is just fortune-telling in the end. Unsound technique. The correct way to detect whether any resource is available for use is just to try to use it in the normal way. Anything else is liable to false negatives, false positives, and timing-window problems.

Question:

I have created client server application in the client side when i send multiple requests to the server some time later it gives below error.When i monitor TCPview there are lot of port connections on CLOSE_WAIT status.Has any one come across with such issue.Please find the bellow error log

 java.net.SocketException: No buffer space available (maximum connections reached?): connect
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351)
    at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
    at java.net.Socket.connect(Socket.java:529)
    at java.net.Socket.connect(Socket.java:478)
    at java.net.Socket.<init>(Socket.java:375)
    at java.net.Socket.<init>(Socket.java:189)
    at com.lk.cc.socketserver.Main.isHostRunning(Main.java:90)
    at com.lk.cc.socketserver.Main.main(Main.java:43)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
    Exception in thread "main" java.lang.NullPointerException
        at com.lk.cc.socketserver.Main.isHostRunning(Main.java:102)
        at com.lk.cc.socketserver.Main.main(Main.java:43)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

Server Host class

public class ServerHost extends Thread {

  private ServerSocket serverSocket;

      public ServerHost(int port) throws IOException {
        serverSocket = new ServerSocket(port);

      }

      public void run() throws IOException{
        while (true) {
          Socket server = null;
          DataInputStream in = null;
          DataOutputStream out = null;
          try {
            System.out.println("Host 1 Established .. ");
            System.out.println("Waiting for client on port " +
                               serverSocket.getLocalPort() + "...");
            server = serverSocket.accept();
            System.out.println("Just connected to "
                               + server.getRemoteSocketAddress());
            in =
                new DataInputStream(server.getInputStream());

            if (in.available() > 0) {
              System.out.println("Recieved client message  :" + in.readUTF());

              out =  new DataOutputStream(server.getOutputStream());

              // send recieved response from host X to client

              out.writeUTF("Response from Host 1 " + server.getLocalSocketAddress() + " \nGoodbye!");

              System.out.println("client socket isClosed()    " + server.isClosed());
            }
          } catch (SocketTimeoutException s) {
            System.out.println("Socket timed out!");
            // break;
          } catch (IOException e) {
            e.printStackTrace();
            // break;
          } finally {
            if (out != null) {
              try {
                out.flush();
              } catch (IOException e) {
                e.printStackTrace();
              }
            }
            if (out != null) {
              try {
                out.close();
              } catch (IOException e) {
                e.printStackTrace();
              }
            }
            if (in != null) {
              try {
                in.close();
              } catch (IOException e) {
                e.printStackTrace();
              }
            }

            if (server != null) {
              try {
                server.close();
              } catch (IOException e) {
                e.printStackTrace();
              }
            }
          }
        }
      }

      public static void main(String[] args) {
        int port = 7881;
        try {
          Thread t = new ServerHost(port);
          t.start();
        } catch (IOException e) {
          e.printStackTrace();
      }
   }
}

Client

    public class Main {

  private static ArrayList<HostConnections> hostList;


  public static void init() {
    hostList = new ArrayList<HostConnections>();
    hostList.add(new HostConnections("localhost", 7881));
    hostList.add(new HostConnections("localhost", 7882));
    hostList.add(new HostConnections("localhost", 7883));
    hostList.add(new HostConnections("localhost", 7884));
  }

  public static void main(String[] args) {
    // write your code here
    boolean hostStatus=true;
    init();
    while (hostStatus) {
      System.out.println("Used " + hostList.get(0));
      HostConnections nextHost = hostList.get(0);
      //Collections.rotate(hostList, -1);
      System.out.println(hostList);

      hostStatus = isHostRunning(nextHost);
      System.out.println(hostStatus);
    }
  }


  private static boolean isHostRunning(HostConnections availableHost) {
    boolean isAlive = false;
    Socket client=null;
    try {
        client = new Socket(availableHost.getHostIpAddress(), availableHost.getHostPort());
      //client.getInputStream().close();

     // client.getOutputStream().close();
      isAlive = true;

    } catch ( Exception e) {
      e.printStackTrace();

    }finally {
      try {
        //client.getOutputStream().flush();
        client.close();
        client.isClosed();
        System.out.println(client.isClosed());
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

    return isAlive;
  }
}

My requirement is to check all the connections in the list are available everytime. Thanks


Answer:

You're leaking sockets somewhere. CLOSE_WAIT means that TCP has received a close from the peer and is waiting for the local application to close the socket.

You should also try a sleep in that testing loop. You're burnng sockets like there is no tomorrow.

In fact I question the entire purpose. The only reliable way to know whether any resource is available is to try to use it and handle the errors as they arise in the normal course of execution. Anything else is tantamount to fortune-telling.

NB:

  1. flush() before close() is redundant.
  2. Calling isClosed() and available() is usually a waste of time, and this is no exception.
  3. Are you aware that this code only tests one host?

Question:

Hello I have a code written in Java and I need to create an TCP Connection with GPS device in android studio, where you can type in IP/PORT addresses, if someone can help me thanks in advance.

public class TCPConnection implements Runnable {

/**
 * <h1>TCP Connection construct</h1>
 * <p>The tcp connection requires two parameters socket and view model. </p>
 * @param socket to establish connection.
 * */





TCPConnection(Socket socket) {
    super();
    this.socket = socket;
    converter = new Converter();
    crc16 = new Crc16();
}






/**
 * <h1>Run function to start listener</h1>
 * <p>Simply runs the runnable thread to listen everything from client</p>
 * */

public void run() {
    try {
        inputStream = new DataInputStream(socket.getInputStream());
        outputStream = new DataOutputStream(socket.getOutputStream());
        Listen();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Probably I need to create an button to start Listen incoming connections, also use Log class .....

 /**
 * <h1>Listen</h1>
 * <p>Function for listening connected client</p>
 * @throws IOException throws exception if input stream is interrupted
 * */
private void Listen() throws IOException {
    while (flag) {
        System.out.println("listening...");
        while (!socket.isClosed() && inputStream.available() == 0) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
        Communicate();
    }
    inputStream.close();
    outputStream.close();
    socket.close();
}











/**
 * <h1>Get Number Of Records</h1>
 * <p>Reads the number of records to send back to the sender</p>
 * @param data the parameter is a received hex data
 * @return String format number of records
 * */
private String GetNumberOfRecords(String data) {
    return data.substring(18, 20);
}

Everything is written in a comments line, why stackoverflow says add more details :D...

/**
 * <h1>Communicate</h1>
 * <p>A reader and sender with client, first it reads imei, then sends back 01.
 * It receives data, as soon it receives it sends back number of records.
 * The while loop initializes and runs until it get interrupted or client disconnects.</p>
 * */
private void Communicate()  {

    imei =  Objects.requireNonNull(ReadInput()).substring(4);
    imei = converter.ReadImei(imei);
    String path = System.getProperty("user.home") + "/Desktop";
    logger = new Logger(path+"/Logs/TCPLogs/"+imei);
    logger.PrintToLOG(GetTime()+" IMEI: " +imei);
    if(imei.length() < 15){
        SendOutput("00");
    }
    else{
        SendOutput("01");
        logger.PrintToLOG("\tResponse: [0" + 1 + "]");
        String input = ReadInput();
        Log(Objects.requireNonNull(input));
        while(flag){
            String recordsCount = GetNumberOfRecords(input);
            SendOutput("000000" + recordsCount);
            logger.PrintToLOG("\tCrc: " + Integer.toHexString(CRC(input)));
            logger.PrintToLOG("\tResponse: [000000" + recordsCount + "]\n");
            input = ReadInput();
            Log(Objects.requireNonNull(input));
        }
    }


/**
 * <h1>Send Output</h1>
 * <p>Sends output to the client</p>
 * @param message the parameter is a received hex data
 * */
private void SendOutput(String message)  {
    try {
        outputStream.write(converter.StringToByteArray(message));
        outputStream.flush();
    } catch (IOException e) {
        System.out.println("Output stream was interrupted");
    }
}








/**
 * <h1>CRC</h1>
 * <p>Calculates CRC of received data</p>
 * @param str the parameter is a received hex data
 * @return int of crc16
 * */
private int CRC(String str) {
    str = str.substring(16, str.length() - 8);
    byte[] bytes = converter.StringToByteArray(str);
    return crc16.getCRC(bytes);
}












/**
 * <h1>Read Input</h1>
 * <p>Reads the input from client. Currently maximum message byte is set up to 8192,
 * if message is bigger then message will not be properly readable and displayed.</p>
 * @return String of received data
 * */
private String ReadInput() {
    byte[] messageByte = new byte[8192];
    int dataSize;
    try {
        dataSize = inputStream.read(messageByte);
        String finalInput = converter.BytesArrayToHex(messageByte, dataSize);
        SendToConsole(finalInput);
        return finalInput;
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}














/**
 * <h1>Send To Console</h1>
 * <p>Simply prints out the results to the text area for user</p>
 * @param input the parameter is String format to print in text area
 * */
private void SendToConsole(String input) {
    if(imei!=null)
    {
        String message = viewModel.getClientMessage() + "\r\nFrom imei - "+imei+" : " + input + "\n" + repeatChar();
        Platform.runLater(() -> viewModel.setClientMessage(message));
    }
    else {
        String message = viewModel.getClientMessage() + "\r\nReceived imei - : " + input + "\n" + repeatChar();
        Platform.runLater(() -> viewModel.setClientMessage(message));
    }
}        









/**
 * <h1>Log</h1>
 * <p>Given String is being written to log file.</p>
 * @param data the parameter is a received data
 * */
private void Log(String data) {
    logger.PrintToLOG("\tcodec             : " + data.substring(16, 18));
    logger.PrintToLOG("\tNumber of Records : " + GetNumberOfRecords(data));
    logger.PrintToLOG("\tAVL data          : " + data + "\n");
}

/**
 * <h1>Set Running</h1>
 * <p>Sets flag to run or stop while loop in order to interrupt the thread.</p>
 * */
void setRunning() {
    this.flag = false;
}

/**
 * <h1>Repeat Char</h1>
 * <p>Repeats the '=' character multiple times.</p>
 * @return String is being returned.
 * */
private String repeatChar() {
    char[] data = new char[50];
    Arrays.fill(data, '=');
    return new String(data);
}

/**
 * <h1>Get Time</h1>
 * <p>Gets time when method is being called</p>
 * @return Time in String format
 * */
private String GetTime()
{
    LocalDateTime localDateTime = LocalDateTime.now();
    LocalTime localTime = localDateTime.toLocalTime();
    return localTime.toString();
}


}

public class TCPServer implements Runnable {
private int port;
private Socket socket;
private ServerSocket ss;
private boolean running = true;
private ArrayList<TCPConnection> tcpConnections;

/**
 * <h1>TCP server construct</h1>
 * <p>The tcp server takes port parameter </p>
 * @param port is required for server to listen all incoming connections
 * */
public TCPServer(int port) {
    this.port = port;
}

/**
 * <h1>Run</h1>
 * <p>Runs the runnable thread to listen connections, it accepts a connection, if accept was successful,
 * the connection is added to tcpConnections list and runs the TCPConnection for further listening.
 * The server is running in while loop and stops when Running is set to false,
 * then break is called and shutdowns every connected client.</p>
 * */




public void run() {
    tcpConnections = new ArrayList<>();
    try {
        ss = new ServerSocket(port);
        System.out.println("Listening on port : " + ss.getLocalPort());
        ExecutorService executorService;
        while (true) {
            executorService = Executors.newSingleThreadExecutor();
            socket = ss.accept();
            TCPConnection connection = new TCPConnection(socket);
            executorService.submit(connection);
            tcpConnections.add(connection);
            if (!running) {
                StopConnections();
                break;
            }
        }
        executorService.shutdownNow();
        Thread.sleep(100);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    } catch (IOException e) {
        System.out.println("socket is closed");
    }
}

/**
 * <h1>Set Flag</h1>
 * <p>Function is being called when we want to interrupt server thread and stop it.</p>
 * @param flag the parameter sets whenever to true(run server) or false(stop server)
 * */
public void setFlag(boolean flag) {
    running = flag;
    if (!running) {
        try {
            ss.close();
            if (socket != null)
                socket.close();
        } catch (IOException e) {
            System.out.println("Socket is " + socket.isClosed());
        }
    }
}

/**
 * <h1>Stop Connections</h1>
 * <p>Function is being called when we are stopping server,
 * this function iterates through every connection and stops it.</p>
 * */
private void StopConnections() {
    if (!tcpConnections.isEmpty()) {
        for (TCPConnection connections : tcpConnections) {
            connections.setRunning();
        }
        tcpConnections.clear();
    }
}
}

Answer:

Android supports Java code as long as your android API level supports the Java version you are using. There shouldn't be any reason why you cannot use this in Android.

Just note that Android will throw an exception if you run any network tasks on the UI thread. E.g. Creating a socket should be run as an IntentService or AsyncTask, there are other options as well.

Question:

I have a simple FTP server and client. For now, the client can send a file, and the server can accept it, but after i run a sendFile() command, it transfers the file, and the server and the client terminate, making it unable to run any other commands after that.

SERVER

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;

import mmd.filetransfer.FileEvent;

public class Server {
    private ServerSocket serverSocket = null;
    private Socket socket = null;
    private ObjectInputStream inputStream = null;
    private FileEvent fileEvent;
    private File dstFile = null;
    private FileOutputStream fileOutputStream = null;

   public Server() {

    }

    /**
     * Accepts socket connection
     */
    public void doConnect() {
        try {
            serverSocket = new ServerSocket(4445);
            socket = serverSocket.accept();
            inputStream = new ObjectInputStream(socket.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Reading the FileEvent object and copying the file to disk.
     */
    public void downloadFile() {
        try {
            fileEvent = (FileEvent) inputStream.readObject();
            if (fileEvent.getStatus().equalsIgnoreCase("Error")) {
                System.out.println("Error occurred ..So exiting");
                System.exit(0);
            }
            String outputFile = fileEvent.getDestinationDirectory() + fileEvent.getFilename();
            if (!new File(fileEvent.getDestinationDirectory()).exists()) {
                new File(fileEvent.getDestinationDirectory()).mkdirs();
            }
            dstFile = new File(outputFile);
            fileOutputStream = new FileOutputStream(dstFile);
            fileOutputStream.write(fileEvent.getFileData());
            fileOutputStream.flush();
            fileOutputStream.close();
            System.out.println("Output file : " + outputFile + " is successfully saved ");
            //Thread.sleep(0);
            //System.exit(0);

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } 

    }

    public static void main(String[] args) {
        Server server = new Server();
        server.doConnect();
        server.downloadFile();
    }
}

CLIENT

package mmd.client;

import java.io.*;
import java.net.Socket;

import mmd.filetransfer.FileEvent;


public class Client {
    private Socket socket = null;
    private ObjectOutputStream outputStream = null;
    private boolean isConnected = false;
    private String sourceFilePath = "/home/jovan/Desktop/videot.mpg";
    private FileEvent fileEvent = null;
    private String destinationPath = "/home/jovan/Desktop/tp/";

    public Client() {

    }

    /**
     * Connect with server code running in local host or in any other host
     */
    public void connect() {
        while (!isConnected) {
            try {
                socket = new Socket("localHost", 4445);
                outputStream = new ObjectOutputStream(socket.getOutputStream());
                isConnected = true;

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void sendFile()  {
        fileEvent = new FileEvent();
        String fileName = sourceFilePath.substring(sourceFilePath.lastIndexOf("/") + 1, sourceFilePath.length());
        String path = sourceFilePath.substring(0, sourceFilePath.lastIndexOf("/") + 1);
        fileEvent.setDestinationDirectory(destinationPath);
        fileEvent.setFilename(fileName);
        fileEvent.setSourceDirectory(sourceFilePath);
        File file = new File(sourceFilePath);
        if (file.isFile()) {
            try {
                DataInputStream diStream = new DataInputStream(new FileInputStream(file));
                long len = (int) file.length();
                byte[] fileBytes = new byte[(int) len];
                int read = 0;
                int numRead = 0;
                while (read < fileBytes.length && (numRead = diStream.read(fileBytes, read,
                        fileBytes.length - read)) >= 0) {
                    read = read + numRead;
                }
                fileEvent.setFileSize(len);
                fileEvent.setFileData(fileBytes);
                fileEvent.setStatus("Success");
            } catch (Exception e) {
                e.printStackTrace();
                fileEvent.setStatus("Error");
            }
        } else {
            System.out.println("path specified is not pointing to a file");
            fileEvent.setStatus("Error");
        }
        //Now writing the FileEvent object to socket
        try {
            outputStream.writeObject(fileEvent);
            System.out.println("Done...Going to exit");
            Thread.sleep(0);
            //System.exit(0);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 

    }

    /**
     * Sending FileEvent object.
     
     * @throws IOException */


    public static void main(String[] args){
        Client client = new Client();
        client.connect();
        client.sendFile();
        client.sendFile();


    }
}

How to prevent this?


Answer:

Calling it an FTP server is a bit confusing, as this does not implement RFC 959.

Your main() in the server code does not have any loop. It just listens, transfers one file and exits. Put it in an infinite loop as ravindra suggests.

Question:

I am doing an android app allowing users to play online.

Currently, I use a TCP server: when two persons are connected, the server takes care of forwarding the packets between the two clients.

I would like to replace my server by a java servlet with google app engine. This new server will just be used to connect the two players.

It would work in that way: Player A opens a server socket and then post to the server the connection details. When a player B wants to play against A, he asks to the server the port number of A and he connects directly to A.

The problem is that I am not sure that it will work if player A is behind a NAT. When player A opens a server socket, that opens one port of its 192.168.x.y address, but does it ask to the box a port forwarding? I assume it doesn't...

So two questions: Is it possible to make a direct connection TCP between two devices even when there is a NAT or a firewall (I don't know how firewalls work on Android...) If it isn't possible, what is the best solution: Is it possible to make a TCP server to ensure the exchange of the messages with app engine?

Thank you by advance.

game


Answer:

Creating direct TCP connection between users under different NAT is mostly possible. There are 4 types of NAT. FC, ARC, PRC, Symmetric. If one of player A or B has symmetric NAT then it is impossible to create TCP P2P connection. In this case you will have to use a server in the middle for exchanging data between two players.

For other types of NAT combinations it is very much possible but not guaranteed. The technique that is used to create TCP P2P connection is called TCP hole punching. Read this answer to know in details about this technique.

Also creating TCP P2P connection is not related to any platform.

Question:

I am using Spring RestTemplate to make a HTTP Calls to my RestService. I am using spring framework 3.2.8 version of RestTemplate. I cannot upgrade this since in our company we have a parent POM in which we are using Spring Framework version 3.2.8 so I need to stick to that.

Let's say I have two machines:

  • machineA: This machine is running my code which uses RestTemplate as my HttpClient and from this machine I make HTTP Calls to my RestService which is running on a different machine (machineB). I have wrapped the below code around multithreaded application so that I can do load and performance testing on my client code.
  • machineB: On this machine, I am running my RestService.

Now the problem I am seeing is whenever I run a load and performance testing on machineA - Meaning, my client code will make lot of HTTPClient calls to the RestService running on machineB very fast since the client code is getting called in a multithreaded way.

I always see lot of TIME_WAIT connections on machineA as shown below:

   298 ESTABLISHED
    14 LISTEN
     2 SYN_SENT
 10230 TIME_WAIT

  291 ESTABLISHED
   14 LISTEN
    1 SYN_SENT
17767 TIME_WAIT

    285 ESTABLISHED
   14 LISTEN
    1 SYN_SENT
24055 TIME_WAIT

I don't think it's a good sign that we have lot of TIME_WAIT connections here. Problem Statement:-

  • What does this high TIME_WAIT connection mean here in a simple language on machineA?
  • Is there any reason why this is happening with RestTemplate or is it just the way I am using RestTemplate? If I am doing anything wrong in the way I am using RestTemplate, then what's the right way to use it?

Do I need to set any keep-alive header or Connection:Close thing while using RestTemplate? Any inputs/suggestions are greatly appreciated as I am confuse what's going on here.

Below is how I am using RestTemplate in my code base in a simple way (just to explain the whole idea of how I am using RestTemplate):

public class DataClient implements Client {

    private final RestTemplate restTemplate = new RestTemplate();
    private ExecutorService executor = Executors.newFixedThreadPool(10);

    // for synchronous call
    @Override
    public String getSyncData(DataKey key) {        
        String response = null;
        Future<String> handler = null;
        try {
            handler = getAsyncData(key);
            response = handler.get(100, TimeUnit.MILLISECONDS); // we have a 100 milliseconds timeout value set
        } catch (TimeoutException ex) {
            // log an exception
            handler.cancel(true);
        } catch (Exception ex) {
            // log an exception
        }

        return response;
    }

    // for asynchronous call
    @Override
    public Future<String> getAsyncData(DataKey key) {
        Future<String> future = null;

        try {
            Task task = new Task(key, restTemplate);
            future = executor.submit(task); 
        } catch (Exception ex) {
            // log an exception
        }

        return future;
    }
}

And below is my simple Task class

class Task implements Callable<String> {

    private final RestTemplate restTemplate;
    private final DataKey key;

    public Task(DataKey key, RestTemplate restTemplate) {
        this.key = key;
        this.restTemplate = restTemplate;
    }

    public String call() throws Exception {
        ResponseEntity<String> response = null;

        String url = "some_url_created_by_using_key";

        // handling all try catch here
        response = restTemplate.exchange(url, HttpMethod.GET, null, String.class);

        return response.getBody();
    }
}

Answer:

"TIME_WAIT" is the state that a TCP connection mantains during a configurable amount of time after closed (FIN/FIN reception). In this way, a possible "delayed" packet of one connection can not be mixed with a latter connection that reuses same port.

In a high-traffic test, it is normal to have a lot of them, but they should disappear after a few minutes test finished.

Question:


Answer:

It is not the ServerSocket that breaks.

The EchoServer reads from the client socket's InputStream in the loop while ((inputLine = in.readLine()) != null). When the socket connection is terminated, attempting to read will throw an exception. Since the loop isn't inside a try-catch-block, the exception kills the server process.

To prevent that, you need to handle the exception.

try {
    while ((inputLine = in.readLine()) != null) { 

        System.out.println ("received: " + inputLine); 
        out.println(inputLine); 

        if (inputLine.equals("Bye.")) 
            break; 

    } 
} catch (IOException ex) {
    System.out.println("Connection error... terminating.");
}

Question:

I created a distributed application in Java for a Android client and PC server (in my case Windows). Android is supposed to hold the connection permanently to be able to receive push notifications. So there is a background service which survives switching off the screen. (Please do not tell me to use GCM. It is out-of-scope because I have to Internet connection.) For testing, the client sends every 5 minutes a self-made (application layer) ping packet to the server, which the server sends (after a delay) back as pong which in return is acknowledged (ack). When Server receives ack, delay is increased by 25 seconds.

However, randomly - as it seems - the server claims that the client has ungracefully closed the connection with this error message:

android java.io.IOException: An existing connection was forcibly closed by the remote host

I noticed that there are some factors which delay (not solve!) this problem:

  • Other wifi network activity on the same wireless network AP.
  • Activating and starting the Google Services Framework on the Android device.
  • Setup a SSH tunnel via cygwin/ssh and connecting to server via this tunnel.

Following components I determined to have no impact:

  • Oracle JDK versus openJDK (both version 7, 32bit, Windows)
  • Network card (tried different USB wifi sticks as well as cable)
  • Wifi APs (used DWL-2100AP, Netgear WGT624 v2, FritzBox 6360)
  • Using Galaxy Nexus (4.3) vs using Galaxy Nexus 4 (4.2.2)

If I run the server program on a Linux (Ubuntu) machine, there are no connection failures.

What could be the reason for these connection problems? How can I get rid of them without switching to Linux?


Answer:

I experienced the same problem on OS Version 4.3. I am assuming that you are working on service this snippet might help you to keep your connection alive

private PowerManager.WakeLock mWakeLock;
public override void OnCreate ()
{
   PowerManager pm = (PowerManager) GetSystemService(Context.PowerService);
   mWakeLock = pm.NewWakeLock (WakeLockFlags.Partial, "PartialWakeLockTag");
   mWakeLock.Acquire();
}

public override void OnDestroy ()
{
     mWakeLock.Release();
}

Obviously by keeping your device CPU active you will drink your battery juice fast

Question:

I want to create a sample TCP client-server pair. The client will take input string from console and send it to server, server will print the request string and respond back with some string. I don't want close the connection once a transaction is done, using the same connection I want to keep on sending request and getting response from server.

I have written the following client-server code , first transaction happens correctly but when I try to send second request, nothing is received by server and client hangs. I tried to google for solution but could not find anything helpful. Please help.

Client Code

public class Client {

    public static void main( String[] args ) throws UnknownHostException, IOException {
         Socket clientSocket = new Socket( "localhost", 81 );
         DataOutputStream out = new DataOutputStream( clientSocket.getOutputStream() );
         BufferedReader in =
            new BufferedReader( new InputStreamReader( clientSocket.getInputStream() ) );
         System.out.println( "connected to server" );

         while ( true ) {
             System.out.println( "enter data to send" );
             Scanner sc = new Scanner( System.in );
             String msg = sc.nextLine();
             out.writeBytes( msg + "\n" );
             System.out.println( "response from server : "+in.readLine() );

        }

    }
}

Server Code

public class Server {

    public static void main(String args[]) throws IOException{
        ServerSocket ss = new ServerSocket(81);
        System.out.println( "server started" );
        while(true){
            System.out.println( "waiting for client" );
            Socket s = ss.accept();
            System.out.println( "connected to client" );
            BufferedReader in = new BufferedReader( new InputStreamReader( s.getInputStream() ) );
            DataOutputStream out = new DataOutputStream( s.getOutputStream() );
            out.flush();
            System.out.println( "recieved: "+ in.readLine()  );
            out.writeBytes( "200\n" );
        }
    }
}

Answer:

When your server begins, it creates a server socket bound on port 81 and enters an infinite loop. Within this loop, you start in an "accepting" state, where you listen for a connection to be made and accept it. Upon accept, you wait for a line of input from the client, print it to System.out, and respond with a "200" response. The problem you have is that after you have responded, the loop 'resets', and you start listening for a new connection.

The simplest solution is to continuously check for incoming data in your server.

public class Server {

    public static void main(String args[]) throws IOException{
        ServerSocket ss = new ServerSocket(81);
        while(true){
            Socket s = ss.accept();
            BufferedReader in = new BufferedReader( new InputStreamReader( s.getInputStream() ) );
            DataOutputStream out = new DataOutputStream( s.getOutputStream() );
            while (true) {
                System.out.println( "recieved: "+ in.readLine()  );
                out.writeBytes( "200\n" );
                out.flush();
            }
        }
    }
}

While this would work for a single client, this would prevent you from establishing new connections while you are listening for data. You may want to create a new thread for each connection to handle reading/writing for each distinct socket connections.

Question:

I'm doing a simple login/signup module using TCP with multithreaded server. I want to make my server possible to handle multiple access from client. My first idea was to use a list of client socket to keep track of which client is connecting: accept() a socket - if it's in the list then find it the list and pass it to function to proceed - if it's not, then add it to the list then pass it to function to proceed. It works for the first time access, but in the second time, it's jammed and the client never receive the result. Could you tell me what did I do wrong and what should I do to handle this kind of problem? Thanks!

Server run() method:

@Override
public void run() {
    Socket socket = new Socket();

    try {
        Socket clientSocket = myServer.accept();

        if (!listSocket.contains(clientSocket)) {
            socket = clientSocket;
            listSocket.add(clientSocket);
        } else {
            for (Socket s : listSocket) {
                if (s == clientSocket) {
                    socket = clientSocket;
                    break;
                }
            }
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    while (true) {
        ReceiveObject(socket);
    }
}

ReceiveObject() method:

// Receive an object[2]
// the object[0] contains Account object
// the object[1] contains Customer object
// if the object[0] is not null and the object[1] is null => this is a login request
// if both object[0] and object[1] are not null => signup request

public void ReceiveObject(Socket clientSocket) {
    try {
        ObjectInputStream ois = new ObjectInputStream(clientSocket.getInputStream());
        Object o = ois.readObject();

        if (o instanceof Object[]) {
            Object[] arr = (Object[]) o;
            if (arr[0] != null && arr[0] instanceof Account && arr[1] == null) {
                Account acc = (Account) arr[0];
                if (CheckAccountExist(acc)) {
                    SendResult("OK", clientSocket);
                } else {
                    SendResult("FAILED", clientSocket);
                }
            } else if (arr[0] != null && arr[1] != null && arr[0] instanceof Account && arr[1] instanceof Customer) {
                Account acc = (Account) arr[0];
                Customer cus = (Customer) arr[1];

                String result = "";

                if (!CheckAccountExist(acc)) {
                    result = "OK";

                    if (AddAccount(acc)) {
                        if (!CheckCustomerExist(cus)) {
                            if (AddCustomer(cus)) {
                                SendResult(result, clientSocket);
                            } else {
                                result = "FAILED";
                                SendResult(result, clientSocket);
                            }
                        }
                    } else {
                        result = "FAILED";
                        SendResult(result, clientSocket);
                    }
                } else {
                    result = "FAILED";
                    SendResult(result, clientSocket);
                }
            }
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

Answer:

My first idea was to use a list of client socket to keep track of which client is connecting: accept() a socket - if it's in the list then find it the list and pass it to function to proceed - if it's not, then add it to the list then pass it to function to proceed.

Why? It won't be in the list. It's a new connection. It can't possibly be in the list. So, therefore, what exactly is the list for? You don't need it. Just start a new and completely independent thread per accepted socket.

It works for the first time access, but in the second time, it's jammed and the client never receive the result. Could you tell me what did I do wrong and what should I do to handle this kind of problem? Thanks!

Throw it away and have a good look at the Custom Networking section of the Java Tutorial.

NB You should use the same object streams for the life of the socket. You shouldn't need methods with a Socket parameter: the Socket should be a member variable of the Runnable class that handles the connection. So should the object streams.

Question:

I use this Thread at server side in order to receive Strings from client:

int clientNumber = 0;
        ServerSocket listener = new ServerSocket(6543);
        try {
            while (true) {
                new Capitalizer(listener.accept(), clientNumber++).start();
            }
        } finally {
            listener.close();
        }
...

private static class Capitalizer extends Thread {

    private Socket socket;
    private int clientNumber;

    public Capitalizer(Socket socket, int clientNumber) {
        this.socket = socket;
        this.clientNumber = clientNumber;
    }

    public void run() {
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            while (true) {
                String input = in.readLine();
                System.out.println("Am Server: " + input);
                out.println(input.toUpperCase());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

And the client looks like this:

try {
        Socket client = new Socket("localhost", 6543);
        OutputStream outToServer = client.getOutputStream();
        DataOutputStream out = new DataOutputStream(outToServer);

        final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        while (true) {
            System.out.print("Enter something : ");
            String input = br.readLine();
            out.write(input.getBytes());
            out.flush();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

It is not clear for me that at server side no string is received. I enter a string in Eclipse console and at client this string is sent to server but at server side nothing happens. Does anyone have a hint what I'm doing wrong?


Answer:

Your server expects to receive lines, so your client must send lines. But your client does not send lines. Why?

From the docs:

Return Value A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached.

Thus the return value of readline is not a line since, as that same page says:

A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed.

To avoid this mistake in the future, before you use TCP, specify in writing precisely what information will be sent and received. If you're using TCP to exchange messages, defined precisely what a message is -- at the byte level.

For this application, you should have precisely specified that the messages will consist of a sequence of characters not including any line terminator characters whose end is marked with a line ending. That would have made it clear that the client was buggy, since it's obviously not sending messages as specified by the protocol.

Question:

I am currently working on a product which has its own JMS provider whose implementation is not well documented. I have to prepare a stand alone client application in Java that will post messages to the JMS queue. I am expecting a huge data volume and hence I am thinking about implementing a JMS connection pool and session pool.

In any object pool, we need to determine if the object is healthy before returning it to the client. JMS does not seem to provide an "isHealthy()" method. Also, I am not able to rely on the ExceptionListener mainly because I am not sure about the JMS provider implementation and also ExceptionListener call is asynchronous. I wonder what will happen if the connection is handed over to the client before the onException is invoked.

As a solution, I am planning to use the TCP idle connection timeout. My understanding is, a connection will become unhealthy only if the TCP idle time connection timeout is over or if the JMS provider is down.

Hence I am planning to create a pooled Connection wrapper object which will store a "last use time" when the connection is created or is returned to the pool by the client. Before handing over the connection to the client, the pool will check if the time interval since the "last use time" is less than 3 minutes (assuming default TCP idle connection timeout is 5 minutes).

Is my understanding and implementation correct?


Answer:

Here is what I would do:

If this fail, then my connection is dead. GenericObjectPool would then automatically invoke the factory to create a brand new connection (#makeObject) to replace the dead one.

Question:

By setting a ChannelOption I can specify the backlog size of the queue handling incoming connections.

.option(ChannelOption.SO_BACKLOG, 100)

I want to instrument my code so that I can measure the capacity in the queue. Does Netty provide any means of exposing the current state of the backlog?


Answer:

No it does not as it is completely handled within the kernel of your OS.

Question:

I am writing a simple TCP Server application with Spring Boot Integration Framework that has to send a greeting to the client on connection establishment. The workflow should be as follows:

  1. Client connects to server
  2. Server sends a greeting message to the client "Hello client"
  3. Client sends a message to the server "Any string"
  4. Server responds with "OK"
  5. ...

Currently steps 1, 3 and 4 are working, but I'm failing on step 2. My code so far:

@SpringBootApplication
@EnableIntegration
public class ExampleApp {

    public static void main(String[] args) {
        SpringApplication.run(ExampleApp.class, args);
    }

    // Create listener on port 1234
    @Bean
    public AbstractServerConnectionFactory serverConnectionFactory() {
        TcpNetServerConnectionFactory tcpNetServerConnectionFactory = new TcpNetServerConnectionFactory(1234);
        return tcpNetServerConnectionFactory;
    }

    // Inbound channel
    @Bean
    public MessageChannel requestChannel() {
        return new DirectChannel();
    }

    // Outbound channel
    @Bean
    public MessageChannel replyChannel() {
        return new DirectChannel();
    }

    // Inbound gateway
    @Bean
    public TcpInboundGateway tcpInboundGateway(AbstractServerConnectionFactory serverConnectionFactory, MessageChannel requestChannel, MessageChannel replyChannel) {
        TcpInboundGateway tcpInboundGateway = new TcpInboundGateway();
        tcpInboundGateway.setConnectionFactory(serverConnectionFactory);
        tcpInboundGateway.setRequestChannel(requestChannel);
        tcpInboundGateway.setReplyChannel(replyChannel);
        return tcpInboundGateway;
    }

    // Send reply for incoming message -> working
    @ServiceActivator(inputChannel = "requestChannel", outputChannel = "replyChannel")
    public Message<String> processMessage(Message<String> message) {
        Message reply = MessageBuilder
                .withPayload("OK")
                .setHeader(IpHeaders.CONNECTION_ID, message.getHeaders().get(IpHeaders.CONNECTION_ID, String.class))
                .build();
        return reply;
    }

    // Send greeting -> not working
    @Bean
    public ApplicationListener<TcpConnectionEvent> listener(MessageChannel replyChannel) {
        return tcpConnectionEvent -> {
            if (tcpConnectionEvent instanceof TcpConnectionOpenEvent) {
                Message<String> message = MessageBuilder
                        .withPayload("Hello client")
                        .setHeader(IpHeaders.CONNECTION_ID, tcpConnectionEvent.getConnectionId())
                        .build();
                replyChannel.send(message);
            }
        };
    }
}

If I connect to the server with

nc -C localhost 1234

connection is established, but I'm getting the following error in the log:

Failed to publish TcpConnectionOpenEvent [source=TcpNetConnection:localhost:37656:1234:187cfbc2-7e5d-4f4e-97de-1a3b55a4e264], [factory=serverConnectionFactory, connectionId=localhost:37656:1234:187cfbc2-7e5d-4f4e-97de-1a3b55a4e264] OPENED:Dispatcher has no subscribers for channel 'application.replyChannel'

If I send a String to the server he replies with "OK" as intended.

What am I missing to get this greeting message working?

Solution

Thanks to the comment of Gary Russel I found a solution. The Inbound gateway must be "split" into a Inbound/Outbound channel adapter pair. Here is the fully working example:

@SpringBootApplication
@EnableIntegration
public class ExampleApp {

    public static void main(String[] args) {
        SpringApplication.run(ExampleApp.class, args);
    }

    // Create listener on port 1234
    @Bean
    public AbstractServerConnectionFactory serverConnectionFactory() {
        TcpNetServerConnectionFactory tcpNetServerConnectionFactory = new TcpNetServerConnectionFactory(1234);
        return tcpNetServerConnectionFactory;
    }

    // Inbound channel
    @Bean
    public MessageChannel requestChannel() {
        return new DirectChannel();
    }

    // Outbound channel
    @Bean
    public MessageChannel replyChannel() {
        return new DirectChannel();
    }

    // Inbound channel adapter
    @Bean
    public TcpReceivingChannelAdapter receivingChannelAdapter(AbstractServerConnectionFactory serverConnectionFactory, MessageChannel requestChannel) {
        TcpReceivingChannelAdapter tcpReceivingChannelAdapter = new TcpReceivingChannelAdapter();
        tcpReceivingChannelAdapter.setConnectionFactory(serverConnectionFactory);
        tcpReceivingChannelAdapter.setOutputChannel(requestChannel);
        return tcpReceivingChannelAdapter;
    }

    // Outbound channel adapter
    @Bean
    @ServiceActivator(inputChannel = "replyChannel")
    public TcpSendingMessageHandler tcpSendingMessageHandler(AbstractServerConnectionFactory serverConnectionFactory) {
        TcpSendingMessageHandler tcpSendingMessageHandler = new TcpSendingMessageHandler();
        tcpSendingMessageHandler.setConnectionFactory(serverConnectionFactory);
        return tcpSendingMessageHandler;
    }

    // Send reply for incoming message -> working
    @ServiceActivator(inputChannel = "requestChannel", outputChannel = "replyChannel")
    public Message<String> processMessage(Message<String> message) {
        Message<String> reply = MessageBuilder
                .withPayload("OK")
                .setHeader(IpHeaders.CONNECTION_ID, message.getHeaders().get(IpHeaders.CONNECTION_ID, String.class))
                .build();
        return reply;
    }

    // Send greeting -> now working
    @Bean
    public ApplicationListener<TcpConnectionEvent> listener(MessageChannel replyChannel) {
        return tcpConnectionEvent -> {
            if (tcpConnectionEvent instanceof TcpConnectionOpenEvent) {
                Message<String> message = MessageBuilder
                        .withPayload("Hello client")
                        .setHeader(IpHeaders.CONNECTION_ID, tcpConnectionEvent.getConnectionId())
                        .build();
                replyChannel.send(message);
            }
        };
    }
}

Now the client gets the greeting "Hello client" on connection establishment and an "OK" as reply on each send message.


Answer:

replyChannel.send(message);

You can't do that; the reply channel is wired up when the first request comes in.

In any case, you can't use a gateway like that, the reply channel is for a reply to a request not for sending some arbitrary message.

You have to use a pair of inbound/outbound channel adapters, instead of a gateway, to enable arbitrary two-way communication.

Question:

Suppose we have chat application which allows us to have contacts and we can chat to anyone from our contacts. Our application should behave like server when receiving messages and client when sending messages. In Java when we want to make a TCP connection client, we use sockets as:

Socket client = new Socket(hostIPAddress, portNumber);

Now, I have learnt using sockets using my local machine as a server, but for a chat application to be practical it should allow communication b/w two different devices.

Now, the client must have the IP address of the other device we want to communicate to. Should I maintain a list of IP addresses of all the contacts in chat application. Also, IP addresses may be dynamic and may change time to time. How can such problem be tackled? Intuitively, it seems that IP addresses won't work.

Edit:

The aim is to setup peer to peer connection rather than using centralized servers. I want to make a simple application with not much complications.


Answer:

You will need to use a technology called WebSockets. It is built precisely for the use case you have at the moment. See https://www.baeldung.com/java-websockets for more information.

Question:

Scenario: client connect to a server using TCP and then the server sends 3 messages.

The server successfully sends 3 messages to the client. Meanwhile, the client machine receives the messages but the client didn't read any of them using dataInputStream.read/...

Then, while the client starts reading the first message he received, the server closes the connection or the connection is lost for any other reason.

My question - Does the client will be able to read the data he didn't yet read but is available to him? or all the remaining data in the socket is unavailable for the client anymore?


Answer:

These are two different scenarios.

Then, while the client starts reading the first message he received, the server closes the connection

No data is lost. The client will read all the data that was sent and then receive an end of stream.

or the connection is lost for any other reason.

All pending data is discarded.

Question:

I have 2 components, A and B, on different LANs with a Linux server between which acts as gateway for both LANs.

A sends TCP traffic to B using a gateway deployed on the public Internet. Therefore, no SYN is sent from A to B via the Linux server. However, C sends TCP traffic back to A using a local TCP connection (the gateway is not involved). By sniffing the traffic, I can see that C is not establishing a regular TCP connection (SYN) but starts by sending (SYN+ACK).

I'm using iptables on the Linux server to redirect locally the TCP traffic sent by C to A. Traffic is redirected to local port 9000.

However, I would also like to intercept this traffic, therefore I've built a simple Netty proxy which listens on port 9000. For some reason, Netty doesn't receive or ignore this traffic.

I wonder if Netty is able to manage the case of a SYN-ACK without SYN.

Any idea?


Answer:

The question is whether the TCP protcool implementation stack in the kernel will manage it.

Netty won't even see it, whether managed by TCP/IP or not.

Netty isn't an implementation of TCP/IP. It is an API layered over the Java API, which is layered over the BSD Sockets API, and none of those is an implementation of TCP/IP either. It can't see any further into the network than calling listen() and accept() in this case.

Question:

I am recently testing tcp ip communication with Spring. The problem I am having occurs while receiving a packet from the ip i connect to.

Below is the Application (pretty similiar to DynamicTcpClientApplication with a few changes by myself for testing reasons.

What am I doing wrong, I have an adapter for receiving messages but it seems, only the messages sent from my server wont reach them. Please tell me if there is an issue with my client.

This is giving me a headache....

@SpringBootApplication
@EnableMessageHistory
public class ClientApplication {

    public static ConfigurableApplicationContext context;


    public static void main(String[] args) throws IOException, InterruptedException {
        SpringApplicationBuilder builder = new SpringApplicationBuilder(ClientApplication.class);
        builder.headless(false);
        context = builder.run(args);
        new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();
    }

    @Bean
    public ClientConfiguration config() {
        File file = new File(Paths.getInstallationFolder() + File.separator + "client.properties");
        if (!file.exists())
            try {
                if (file.createNewFile()) {
                    Logger.getLogger("Client").warning("Properties not found! New properties created." +
                            "Please restart the application!");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        try {
            return new ClientConfiguration(Paths.getInstallationFolder().getAbsolutePath());
        } catch (ConfigurationException | IOException e) {
            e.printStackTrace();
            return null;
        }
    }


    @Bean(name = PollerMetadata.DEFAULT_POLLER)
    public PollerMetadata defaultPoller() {
        PollerMetadata pollerMetadata = new PollerMetadata();
        pollerMetadata.setTrigger(new PeriodicTrigger(10));
        return pollerMetadata;
    }

    // Client side

    @MessagingGateway(defaultRequestChannel = "toTcp.input")
    public interface ToTCP {

        void send(String data, @Header("host") String host, @Header("port") int port);
    }

    @Bean
    public IntegrationFlow toTcp() {
        return f -> f.route(new TcpRouter());
    }

    @Bean
    public TcpNetServerConnectionFactory cf() {
        TcpNetServerConnectionFactory factory = new TcpNetServerConnectionFactory(6666);
        factory.setSingleUse(false);
        ByteArrayCrLfSerializer serializer = (ByteArrayCrLfSerializer) factory.getSerializer();
        serializer.setMaxMessageSize(20480);
        ByteArrayCrLfSerializer deserializer = (ByteArrayCrLfSerializer) factory.getDeserializer();
        deserializer.setMaxMessageSize(20480);
        return factory;
    }

    @Bean
    public TcpReceivingChannelAdapter inbound(AbstractServerConnectionFactory cf) {
        TcpReceivingChannelAdapter messageHandler = new TcpReceivingChannelAdapter();
        messageHandler.setConnectionFactory(cf);
        messageHandler.setOutputChannel(outputChannel());
        messageHandler.setAutoStartup(true);
        messageHandler.start();
        return messageHandler;
    }

    @Bean
    public QueueChannel outputChannel() {
        return new QueueChannel();
    }

    @Transformer(inputChannel = "outputChannel", outputChannel = "serviceChannel")
    @Bean
    public ObjectToStringTransformer transformer() {
        return new ObjectToStringTransformer();
    }


    public static class TcpRouter extends AbstractMessageRouter {


        @SuppressWarnings("SpringJavaAutowiringInspection")
        @Autowired
        private IntegrationFlowContext flowContext;

        private final static int MAX_CACHED = 10; // When this is exceeded, we remove the LRU.

        @SuppressWarnings("serial")
        private final LinkedHashMap<String, MessageChannel> subFlows =
                new LinkedHashMap<String, MessageChannel>(MAX_CACHED, .75f, true) {

                    @Override
                    protected boolean removeEldestEntry(Map.Entry<String, MessageChannel> eldest) {
                        if (size() > MAX_CACHED) {
                            removeSubFlow(eldest);
                            return true;
                        } else {
                            return false;
                        }
                    }

                };

        private MessageChannel createNewSubflow(Message<?> message) {
            String host = (String) message.getHeaders().get("host");
            Integer port = (Integer) message.getHeaders().get("port");
            Assert.state(host != null && port != null, "host and/or port header missing");
            String hostPort = host + port;

            TcpNetClientConnectionFactory cf = new TcpNetClientConnectionFactory(host, port);
            TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
            handler.setConnectionFactory(cf);
            IntegrationFlow flow = f -> f.handle(handler);
            IntegrationFlowRegistration flowRegistration =
                    this.flowContext.registration(flow)
                            .addBean(cf)
                            .id(hostPort + ".flow")
                            .register();
            MessageChannel inputChannel = flowRegistration.getInputChannel();
            this.subFlows.put(hostPort, inputChannel);
            return inputChannel;
        }

        private void removeSubFlow(Map.Entry<String, MessageChannel> eldest) {
            String hostPort = eldest.getKey();
            this.flowContext.remove(hostPort + ".flow");
        }

        @Override
        protected Collection<MessageChannel> determineTargetChannels(Message<?> message) {
            MessageChannel channel = this.subFlows
                    .get(message.getHeaders().get("host", String.class) + message.getHeaders().get("port"));
            if (channel == null) {
                channel = createNewSubflow(message);
            }
            return Collections.singletonList(channel);
        }
    }
}

Error:

    2017-11-20 16:54:10.712  WARN 6816 --- [pool-2-thread-1] o.s.i.i.tcp.connection.TcpNetConnection  : Unexpected message - no endpoint registered with connection interceptor: 192.168.200.107:6666:46707:a02d3f05-8e32-4215-8130-29c56d25ab36 - GenericMessage [payload=byte[40], headers={ip_tcp_remotePort=6666, ip_connectionId=192.168.200.107:6666:46707:a02d3f05-8e32-4215-8130-29c56d25ab36, ip_localInetAddress=/192.168.200.88, ip_address=192.168.200.107, id=9031c426-438d-535d-affa-09caa09b9e22, ip_hostname=192.168.200.107, timestamp=1511193250712}]
    2017-11-20 16:54:10.712  WARN 6816 --- [pool-2-thread-1] o.s.i.i.tcp.connection.TcpNetConnection  : Unexpected message - no endpoint registered with connection interceptor: 192.168.200.107:6666:46707:a02d3f05-8e32-4215-8130-29c56d25ab36 - GenericMessage [payload=byte[0], headers={ip_tcp_remotePort=6666, ip_connectionId=192.168.200.107:6666:46707:a02d3f05-8e32-4215-8130-29c56d25ab36, ip_localInetAddress=/192.168.200.88, ip_address=192.168.200.107, id=63ff31e2-8f25-8282-fec4-f3c4cfc38cd6, ip_hostname=192.168.200.107, timestamp=1511193250712}]

DEBUG-LOG : Client

19:00:35.878 [main] INFO  o.s.i.config.IntegrationRegistrar - No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created.
19:00:35.879 [main] DEBUG o.s.i.config.IntegrationRegistrar - The '#jsonPath' SpEL function cannot be registered: there is no jayway json-path.jar on the classpath.
19:00:35.879 [main] DEBUG o.s.i.config.IntegrationRegistrar - SpEL function '#xpath' isn't registered: there is no spring-integration-xml.jar on the classpath.
19:00:35.949 [main] INFO  o.s.i.c.DefaultConfiguringBeanFactoryPostProcessor - No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created.
19:00:35.950 [main] INFO  o.s.i.c.DefaultConfiguringBeanFactoryPostProcessor - No bean named 'taskScheduler' has been explicitly defined. Therefore, a default ThreadPoolTaskScheduler will be created.
C:\Users\Sebas\<myApp>\client.properties
19:00:36.088 [main] DEBUG o.s.i.h.ServiceActivatingHandler - Unable to attempt conversion of Message payload types. Component 'fileManager.service.serviceActivator.handler' has no explicit ConversionService reference, and there is no 'integrationConversionService' bean within the context.
19:00:36.132 [main] INFO  o.s.i.i.t.c.TcpNetServerConnectionFactory - started cf, port=6666
19:00:36.132 [main] INFO  o.s.i.i.t.TcpReceivingChannelAdapter - started org.springframework.integration.ip.tcp.TcpReceivingChannelAdapter@2dd29a59
19:00:36.133 [pool-1-thread-1] INFO  o.s.i.i.t.c.TcpNetServerConnectionFactory - cf, port=6666 Listening
19:00:36.282 [main] DEBUG o.s.i.c.GlobalChannelInterceptorProcessor - No global channel interceptors.
19:00:36.283 [main] INFO  o.s.i.h.MessageHistoryConfigurer - Enabling MessageHistory tracking for component 'inbound'
19:00:36.283 [main] INFO  o.s.i.h.MessageHistoryConfigurer - Enabling MessageHistory tracking for component 'outputChannel'
19:00:36.283 [main] INFO  o.s.i.h.MessageHistoryConfigurer - Enabling MessageHistory tracking for component '<myApp>ClientApplication$ToTCP'
19:00:36.283 [main] INFO  o.s.i.h.MessageHistoryConfigurer - Enabling MessageHistory tracking for component 'errorChannel'
19:00:36.283 [main] INFO  o.s.i.h.MessageHistoryConfigurer - Enabling MessageHistory tracking for component '_org.springframework.integration.errorLogger'
19:00:36.283 [main] INFO  o.s.i.h.MessageHistoryConfigurer - Enabling MessageHistory tracking for component '<myApp>ClientApplication.transformer.transformer.handler'
19:00:36.283 [main] INFO  o.s.i.h.MessageHistoryConfigurer - Enabling MessageHistory tracking for component 'fileManager.service.serviceActivator.handler'
19:00:36.283 [main] INFO  o.s.i.h.MessageHistoryConfigurer - Enabling MessageHistory tracking for component 'serviceChannel'
19:00:36.283 [main] INFO  o.s.i.h.MessageHistoryConfigurer - Enabling MessageHistory tracking for component 'toTcp.input'
19:00:36.283 [main] INFO  o.s.i.h.MessageHistoryConfigurer - Enabling MessageHistory tracking for component 'de.iutp.<myApp>.<myApp>client.<myApp>ClientApplication$TcpRouter#0'
19:00:36.283 [main] INFO  o.s.i.endpoint.EventDrivenConsumer - Adding {service-activator:fileManager.service.serviceActivator} as a subscriber to the 'serviceChannel' channel
19:00:36.283 [main] INFO  o.s.i.channel.DirectChannel - Channel 'application.serviceChannel' has 1 subscriber(s).
19:00:36.283 [main] INFO  o.s.i.endpoint.EventDrivenConsumer - started fileManager.service.serviceActivator
19:00:36.283 [main] INFO  o.s.i.g.GatewayProxyFactoryBean$MethodInvocationGateway - started <myApp>ClientApplication$ToTCP
19:00:36.283 [main] INFO  o.s.i.g.GatewayCompletableFutureProxyFactoryBean - started <myApp>ClientApplication$ToTCP
19:00:36.283 [main] INFO  o.s.i.endpoint.EventDrivenConsumer - Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
19:00:36.283 [main] INFO  o.s.i.c.PublishSubscribeChannel - Channel 'application.errorChannel' has 1 subscriber(s).
19:00:36.283 [main] INFO  o.s.i.endpoint.EventDrivenConsumer - started _org.springframework.integration.errorLogger
19:00:36.283 [main] INFO  o.s.i.endpoint.EventDrivenConsumer - Adding {router} as a subscriber to the 'toTcp.input' channel
19:00:36.283 [main] INFO  o.s.i.channel.DirectChannel - Channel 'application.toTcp.input' has 1 subscriber(s).
19:00:36.283 [main] INFO  o.s.i.endpoint.EventDrivenConsumer - started org.springframework.integration.config.ConsumerEndpointFactoryBean#0
19:00:36.284 [main] INFO  o.s.i.endpoint.PollingConsumer - started <myApp>ClientApplication.transformer.transformer
19:00:37.285 [task-scheduler-1] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:38.296 [task-scheduler-2] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:39.307 [task-scheduler-1] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:40.318 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:41.329 [task-scheduler-2] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:42.341 [task-scheduler-4] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:43.352 [task-scheduler-1] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:44.363 [task-scheduler-5] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:45.374 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:46.385 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:47.396 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:48.407 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:49.419 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:50.430 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:51.441 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:52.453 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:53.297 [Timer-0] DEBUG o.s.i.channel.DirectChannel - preSend on channel 'toTcp.input', message: GenericMessage [payload=64198e68-c701-44ae-856a-f5bf9a765e11::7d670b67-3605-4faa-908f-b9843e227b26::01717546021         ,R-Muehle            D_M72.7 keine Silovorwahl   
, headers={host=192.168.200.107, history=<myApp>ClientApplication$ToTCP,toTcp.input, id=f70a3c7b-e419-eea5-945b-0531d4acf2e0, port=6666, timestamp=1511200853297}]
19:00:53.302 [Timer-0] INFO  o.s.i.endpoint.EventDrivenConsumer - Adding {ip:tcp-outbound-channel-adapter} as a subscriber to the '192.168.200.1076666.flow.input' channel
19:00:53.302 [Timer-0] INFO  o.s.i.channel.DirectChannel - Channel 'application.192.168.200.1076666.flow.input' has 1 subscriber(s).
19:00:53.302 [Timer-0] INFO  o.s.i.i.t.c.TcpNetClientConnectionFactory - started 192.168.200.1076666.floworg.springframework.integration.ip.tcp.connection.TcpNetClientConnectionFactory#0, host=192.168.200.107, port=6666
19:00:53.302 [Timer-0] INFO  o.s.i.endpoint.EventDrivenConsumer - started org.springframework.integration.config.ConsumerEndpointFactoryBean#1
19:00:53.302 [Timer-0] DEBUG o.s.i.channel.DirectChannel - preSend on channel '192.168.200.1076666.flow.input', message: GenericMessage [payload=64198e68-c701-44ae-856a-f5bf9a765e11::7d670b67-3605-4faa-908f-b9843e227b26::01717546021         ,R-Muehle            D_M72.7 keine Silovorwahl   
, headers={host=192.168.200.107, history=<myApp>ClientApplication$ToTCP,toTcp.input,de.iutp.<myApp>.<myApp>client.<myApp>ClientApplication$TcpRouter#0, id=0e1ead22-e947-6ae4-bb5c-13b8fa80c5e1, port=6666, timestamp=1511200853297}]
19:00:53.302 [Timer-0] DEBUG o.s.i.i.tcp.TcpSendingMessageHandler - org.springframework.integration.ip.tcp.TcpSendingMessageHandler#0 received message: GenericMessage [payload=64198e68-c701-44ae-856a-f5bf9a765e11::7d670b67-3605-4faa-908f-b9843e227b26::01717546021         ,R-Muehle            D_M72.7 keine Silovorwahl   
, headers={host=192.168.200.107, history=<myApp>ClientApplication$ToTCP,toTcp.input,de.iutp.<myApp>.<myApp>client.<myApp>ClientApplication$TcpRouter#0, id=0e1ead22-e947-6ae4-bb5c-13b8fa80c5e1, port=6666, timestamp=1511200853297}]
19:00:53.302 [Timer-0] DEBUG o.s.i.i.t.c.TcpNetClientConnectionFactory - Opening new socket connection to 192.168.200.107:6666
19:00:53.464 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:54.475 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:55.486 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:56.497 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:57.509 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:58.520 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:00:58.961 [Timer-0] DEBUG o.s.i.i.t.c.TcpNetConnection - New connection 192.168.200.107:6666:51251:94af931e-65e3-498d-a88b-b7389b1df65a
19:00:58.961 [Timer-0] DEBUG o.s.i.i.t.c.TcpNetClientConnectionFactory - 192.168.200.1076666.floworg.springframework.integration.ip.tcp.connection.TcpNetClientConnectionFactory#0: Added new connection: 192.168.200.107:6666:51251:94af931e-65e3-498d-a88b-b7389b1df65a
19:00:58.962 [pool-2-thread-1] DEBUG o.s.i.i.t.c.TcpNetConnection - 192.168.200.107:6666:51251:94af931e-65e3-498d-a88b-b7389b1df65a Reading...
19:00:58.962 [pool-2-thread-1] DEBUG o.s.i.i.t.s.ByteArrayCrLfSerializer - Available to read: 0
19:00:58.962 [Timer-0] DEBUG o.s.i.i.tcp.TcpSendingMessageHandler - Got Connection 192.168.200.107:6666:51251:94af931e-65e3-498d-a88b-b7389b1df65a
19:00:58.963 [Timer-0] DEBUG o.s.i.i.t.c.TcpNetConnection - 192.168.200.107:6666:51251:94af931e-65e3-498d-a88b-b7389b1df65a Message sent GenericMessage [payload=64198e68-c701-44ae-856a-f5bf9a765e11::7d670b67-3605-4faa-908f-b9843e227b26::01717546021         ,R-Muehle            D_M72.7 keine Silovorwahl   
, headers={host=192.168.200.107, history=<myApp>ClientApplication$ToTCP,toTcp.input,de.iutp.<myApp>.<myApp>client.<myApp>ClientApplication$TcpRouter#0, id=0e1ead22-e947-6ae4-bb5c-13b8fa80c5e1, port=6666, timestamp=1511200853297}]
19:00:58.963 [Timer-0] DEBUG o.s.i.channel.DirectChannel - postSend (sent=true) on channel '192.168.200.1076666.flow.input', message: GenericMessage [payload=64198e68-c701-44ae-856a-f5bf9a765e11::7d670b67-3605-4faa-908f-b9843e227b26::01717546021         ,R-Muehle            D_M72.7 keine Silovorwahl   
, headers={host=192.168.200.107, history=<myApp>ClientApplication$ToTCP,toTcp.input,de.iutp.<myApp>.<myApp>client.<myApp>ClientApplication$TcpRouter#0, id=0e1ead22-e947-6ae4-bb5c-13b8fa80c5e1, port=6666, timestamp=1511200853297}]
19:00:58.963 [Timer-0] DEBUG o.s.i.channel.DirectChannel - postSend (sent=true) on channel 'toTcp.input', message: GenericMessage [payload=64198e68-c701-44ae-856a-f5bf9a765e11::7d670b67-3605-4faa-908f-b9843e227b26::01717546021         ,R-Muehle            D_M72.7 keine Silovorwahl   
, headers={host=192.168.200.107, history=<myApp>ClientApplication$ToTCP,toTcp.input, id=f70a3c7b-e419-eea5-945b-0531d4acf2e0, port=6666, timestamp=1511200853297}]
19:00:59.214 [pool-2-thread-1] DEBUG o.s.i.i.t.c.TcpNetConnection - Message received GenericMessage [payload=byte[40], headers={ip_tcp_remotePort=6666, ip_connectionId=192.168.200.107:6666:51251:94af931e-65e3-498d-a88b-b7389b1df65a, ip_localInetAddress=/10.0.8.2, ip_address=192.168.200.107, id=efd1d331-7289-5074-e6e4-d85458d0abae, ip_hostname=192.168.200.107, timestamp=1511200859214}]
19:00:59.215 [pool-2-thread-1] WARN  o.s.i.i.t.c.TcpNetConnection - Unexpected message - no endpoint registered with connection interceptor: 192.168.200.107:6666:51251:94af931e-65e3-498d-a88b-b7389b1df65a - GenericMessage [payload=byte[40], headers={ip_tcp_remotePort=6666, ip_connectionId=192.168.200.107:6666:51251:94af931e-65e3-498d-a88b-b7389b1df65a, ip_localInetAddress=/10.0.8.2, ip_address=192.168.200.107, id=efd1d331-7289-5074-e6e4-d85458d0abae, ip_hostname=192.168.200.107, timestamp=1511200859214}]
19:00:59.215 [pool-2-thread-1] DEBUG o.s.i.i.t.s.ByteArrayCrLfSerializer - Available to read: 2
19:00:59.215 [pool-2-thread-1] DEBUG o.s.i.i.t.c.TcpNetConnection - Message received GenericMessage [payload=byte[0], headers={ip_tcp_remotePort=6666, ip_connectionId=192.168.200.107:6666:51251:94af931e-65e3-498d-a88b-b7389b1df65a, ip_localInetAddress=/10.0.8.2, ip_address=192.168.200.107, id=a6807249-9f8f-16f1-53e2-e4c1b7076483, ip_hostname=192.168.200.107, timestamp=1511200859215}]
19:00:59.215 [pool-2-thread-1] WARN  o.s.i.i.t.c.TcpNetConnection - Unexpected message - no endpoint registered with connection interceptor: 192.168.200.107:6666:51251:94af931e-65e3-498d-a88b-b7389b1df65a - GenericMessage [payload=byte[0], headers={ip_tcp_remotePort=6666, ip_connectionId=192.168.200.107:6666:51251:94af931e-65e3-498d-a88b-b7389b1df65a, ip_localInetAddress=/10.0.8.2, ip_address=192.168.200.107, id=a6807249-9f8f-16f1-53e2-e4c1b7076483, ip_hostname=192.168.200.107, timestamp=1511200859215}]
19:00:59.215 [pool-2-thread-1] DEBUG o.s.i.i.t.s.ByteArrayCrLfSerializer - Available to read: 0
19:00:59.531 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:01:00.542 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:01:01.553 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:01:02.565 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:01:03.577 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:01:04.588 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'
19:01:05.599 [task-scheduler-3] DEBUG o.s.i.endpoint.PollingConsumer - Received no Message during the poll, returning 'false'

Answer:

The error indicates one of the connection factories is receiving data and doesn't have a TcpListener.

Please edit the question to attach a DEBUG log showing both sides.

EDIT

19:00:59.214 [pool-2-thread-1] DEBUG o.s.i.i.t.c.TcpNetConnection - Message received GenericMessage [payload=byte[40], headers={ip_tcp_remotePort=6666, ip_connectionId=192.168.200.107:6666:51251:94af931e-65e3-498d-a88b-b7389b1df65a, ip_localInetAddress=/10.0.8.2, ip_address=192.168.200.107, id=efd1d331-7289-5074-e6e4-d85458d0abae, ip_hostname=192.168.200.107, timestamp=1511200859214}]
19:00:59.215 [pool-2-thread-1] WARN  o.s.i.i.t.c.TcpNetConnection - Unexpected message - no endpoint registered with connection interceptor: 192.168.200.107:6666:51251:94af931e-65e3-498d-a88b-b7389b1df65a - GenericMessage [payload=byte[40], headers={ip_tcp_remotePort=6666, ip_connectionId=192.168.200.107:6666:51251:94af931e-65e3-498d-a88b-b7389b1df65a, ip_localInetAddress=/10.0.8.2, ip_address=192.168.200.107, id=efd1d331-7289-5074-e6e4-d85458d0abae, ip_hostname=192.168.200.107, timestamp=1511200859214}]

Your client is not configured to handle replies.

If you are in a request/reply scenario, you need to use a TcpOutboundGateway instead of the sending channel adapter.

If you want to handle arbitrary inbound/outbound messages, you need a receiving channel adapter in the client.

Question:

I am trying to receive acceleration data from my android phone to my PC.

I have tried using this JAVA code for accessing and sending data from my android:

 import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;


public class MainActivity extends Activity implements SensorEventListener{

    String mClientMsg = "";
    Thread myCommsThread = null;
    public static final String TAG = "SocketServer";
    private CommsThread commsThread = null;
    TextView tv;
    PrintWriter out;
    private float ax, ay, az;
    private long timenow = 0, timeprev = 0, timestamp =0 ;

    private SensorManager sm;
    private Sensor sensor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.textView1);
        sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        sensor = sm.getSensorList(Sensor.TYPE_LINEAR_ACCELERATION).get(0);
    }

    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        sm.registerListener(this, sensor, SensorManager.SENSOR_DELAY_UI);
        this.commsThread = new CommsThread();
        this.myCommsThread = new Thread(this.commsThread);
        this.myCommsThread.start();
    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        sm.unregisterListener(this);
        if (commsThread != null) {
            commsThread.stopComms();
        }
    }

    Handler myHandler = new Handler(){
        public void handleMessage(Message msg){
            TextView status = (TextView) findViewById(R.id.textView3);
            status.setText("Status: Streaming Now!");
        }
    };

    class CommsThread implements Runnable {
        private volatile boolean stopFlag = false;
        private ServerSocket ss = null;
        private static final int SERVERPORT = 6000;
        public void run() {
            Socket s = null;
            try {
                ss = new ServerSocket(SERVERPORT);
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                s = ss.accept();
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            myHandler.sendEmptyMessage(0);

            while(!stopFlag){
                try {
                    out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(s.getOutputStream())), true);
                    out.printf("*#%3.2f#%3.2f#%3.2f#%2d#*\n",ax,ay,az,(int)timestamp );
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        public void stopComms() {
            // TODO Auto-generated method stub
            this.stopFlag = true;
            if(ss != null){
                try {
                    ss.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void onAccuracyChanged(Sensor arg0, int arg1) {
        // TODO Auto-generated method stub
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        // TODO Auto-generated method stub
        ax = event.values[0];
        ay = event.values[1];
        az = event.values[2];
        timenow = event.timestamp;
        timestamp = (timenow - timeprev)/1000000;
        refreshDisplay();
    }

    private void refreshDisplay() {
        // TODO Auto-generated method stub
        String output = String.format("time: %d -- x:%03.2f | Y:%03.2f | Z:%03.2f", timestamp, ax,ay,az);
        timeprev = timenow;
        tv.setText(output);
    }
}

and this python script as server at my PC:

    import socket
from time import *
import sys

serv=socket.socket()

HOST=''
PORT = 7000 
#HOST="78.91.80.123" //here I use my IP
#ADDR = (HOST,PORT)    
BUFSIZE = 4096   


#bind our socket to the address
try:
    serv.bind((HOST, PORT))
    serv.listen(5)
    conn,addr = serv.accept()
except KeyboardInterrupt:
    print "Keyboard Interrupt"
    serv.close()
    exit(1)
try:
    for i in range(0,3100):
        data=conn.recv(4096)
        sys.stdout.flush()
        chunk=data.split()
        sys.stdout.write("0:%s\n" % chunk[-1]) # writes the last element in the list
        sleep(0.03)

    conn.close()
    sleep(10)

except KeyboardInterrupt:
    conn.close()
    print "bye!"
except IndexError:
    conn.close()
    print "indexError"

I have tested the python script and it works, however when I open the app, Nothing is being sent to the PC. I am kind of new in protocols so i am still trying to figure out what happens.


Answer:

  1. First, you are using two different port numbers. In your Python script, you have PORT = 7000 and in your Java code you have private static final int SERVERPORT = 6000;. These must match in order to create a connection, and make sure you aren't using this port for anything else on your machine.

  2. If your Python script is running the server, then you shouldn't use a ServerSocket in your Java code. The ServerSocket waits for incoming connections from a client. To establish a connection to your server, you'd instead want to use:

    Socket s = new Socket("78.91.80.123", SERVERPORT);
    

From there, you can write to the socket by viewing some examples in the corresponding Java Documentation.

Question:

While integrating to a TCP endpoint, we created an application using Spring integration TCP where we've a pooled connection using the following beans:

<!-- Pooled Connection factory -->
<int-ip:tcp-connection-factory id="client" type="client" host="${gateway.url}" port="${gateway.port}"
    single-use="true" so-timeout="${gateway.socket.timeout}" serializer="appSerializerDeserializer" deserializer="appSerializerDeserializer" />
<bean id="cachedClient" class="org.springframework.integration.ip.tcp.connection.CachingClientConnectionFactory">
    <constructor-arg ref="client" />
    <constructor-arg value="${gateway.pool.size}" />
</bean>

Does anyone have a suggestion on how to implement a socket re-connection in case a socket loses the connection?


Answer:

It will automatically reconnect the next time you send something.

Question:

I'm trying to implement a client-server application in which the server may accept some Objects from the clients and for each Object it must interpret it as a message and handle it properly.

Here is the code:

(server)

public class GlobalServer{
GlobalServer(){new Thread(() ->{
    try {
        serverSocket = new ServerSocket(1234);
        Socket clientSocket;
        while (true) {
            clientSocket = serverSocket.accept();
            handleClient(clientSocket);
        }
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
}).start();
}

public void handleClient(Socket clientSocket) throws IOException, ClassNotFoundException{
    ObjectInputStream is = new ObjectInputStream(clientSocket.getInputStream());
    Object [] objArr = (Object[]) is.readObject();
    msgHandler(objArr, clientSocket);
}

public void msgHandler(Object [] objArr, Socket clientSocket){
    int msg_type = (int) objArr[0];
    switch (msg_type) {
    case 1:
        System.out.println("type 1 received");
        break;
    case 2:
        System.out.println("type 2 received");
        break;
    case 3:
        System.out.println("type 3 received");
        break;

    default:
        break;
    }
}
public static void main(String [] args){
    GlobalServer s = new GlobalServer();
}
}

OBS: on the application it makes sense to receive a array of objects as each message carries its header (the type) and its content

(client)

public class Client {
    public static void main(String [] args){
        try {
            Socket client = new Socket("192.168.0.105", 1234);

            ObjectOutputStream os = new ObjectOutputStream(client.getOutputStream());
            Object [] objArr = {3, "Type 3 message"};
            os.writeObject(objArr);

            Object []objArr1 = {1, "Type 1 message"};
            os.writeObject(objArr1);        
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
   }

I run a instance of the GlobalServer on a separate machine and on another machine I connect to the server and send two messages sequentially. The probleme is that the server receives and handle only the first message and the second one get lost and the client finish without the server receive this second message. The strange thing is that if I send this two messagens as two diferent aplications the server handles it fine. It has something to do with the two messagens beeing sent on the same process?

Code working as diferent aplications:

(message 1)

public class Message1 {
    public static void main(String [] args){
        try {
            Socket client = new Socket("192.168.0.105", 1234);

            ObjectOutputStream os = new ObjectOutputStream(client.getOutputStream());

            Object [] objArr = {3, "Type 3 message"};
            os.writeObject(objArr);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
   }

(message 2)

public class Message2 {
    public static void main(String [] args){
        try {
            Socket client = new Socket("192.168.0.105", 1234);

            ObjectOutputStream os = new ObjectOutputStream(client.getOutputStream());

            Object []objArr1 = {1, "Type 1 message"};
            os.writeObject(objArr1);        
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
   }

Answer:

Problem is in following code block:

public void handleClient(Socket clientSocket) throws IOException, ClassNotFoundException{
    ObjectInputStream is = new ObjectInputStream(clientSocket.getInputStream());
    Object [] objArr = (Object[]) is.readObject();
    msgHandler(objArr, clientSocket);
}

You are only reading one object. (Object[]) is.readObject(); shall be called in a loop in order to read multiple objects and call msgHandler method for each object.

Hope this helps

Question:

I know spring integration has TcpInboundGateway and ByteArrayStxEtxSerializer to handle data coming through TCP port.

ByteArrayStxEtxSerializer works great if the TCP server needs to read all the data sent from the client and then processes it. (request and response model) I am using single-use=false so that multiple requests can be processed in the same connection.

For example if the client sends 0x02AAPL0x03 then Server can send the AAPL price.

My TCP Server is working if the client sends 0x02AAPL0x030x02GOOG0x03. It sends the price of AAPL and GOOG price.

Sometimes clients can send EOT (0x04). If the client sends EOT, I would like to close the socket connection.

For example: Client request can be 0x02AAPL0x030x02GOOG0x03 0x020x040x03. Note EOT came in the last packet.

I know ByteArrayStxEtxSerializer deserializer can be customized to read the bytes sent by the client.

is deserializer good place to close socket connection? if not, how should spring integration framework be notified to close socket connection?

Please help.

Here is my spring configuration:

<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: Adding throw new SoftEndOfStreamException("Stream closed") to close the stream in serializer works and I can see the CLOSED log entry in EventListener. When the server closes the connection, I expect to receive java.io.InputStream.read() as -1 in the client. But the client is receiving the

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)

is there anything else to close the connection on the server side and propagate it to client?

I appreciate your help.

Thank you


Answer:

The deserializer doesn't have access to the socket, just the input stream; closing it would probably work, but you will likely get a lot of noise in the log.

The best solution is to throw a SoftEndOfStreamException; that signals that the socket should be closed and everything cleaned up.

EDIT

Add a listener to detect/log the close...

@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);
        }

    }

}

With XML, just add a <bean/> for your listener class.

Result:

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

EDIT2

It worked as expected for me...

@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();
        }

    }

}

Result:

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.springframework.integration.ip.tcp.connection.TcpNetConnection@fee3774], [factory=server, connectionId=localhost:54984:1234:f79a6826-0336-4823-8844-67054903a094] **CLOSED**

Question:

I'm having a problem with a Java SocketServer, i'm building a very basic Java handled Web Server.

So i'm creating a socket server, this is the code from the run method as i have made the server threaded. The problem i'm having is that the server code seems to freeze as while((line = reader.readLine()) != null) until the remote client closes the connection. I'm using the chrome plugin ARC (Advanced REST Client) to do the testing with.

   public void start() throws ServerException{
        this.running = true;

        try{
            this.server = new ServerSocket(this.port);
        }catch(IOException ex){
            System.err.println("Failed to create Server Port is inuse!");
            throw new ServerException("Unable to bind to port '" + this.port + "'", ex);
        }

        while(!isStopped()){
            Socket client = null;
            try{
                client = this.server.accept();
            }catch(IOException ex){
                if(isStopped()) {
                    return;
                }
                throw new ServerException("Error accepting client connection", ex);
            }
            new Thread(
                new ServerWorker(client, this)
            ).start();
        }
    }

This is the ServerWorker

public void run(){
        try {
            InputStream input  = clientSocket.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            OutputStream output = clientSocket.getOutputStream();
            long time = System.currentTimeMillis();
            ArrayList<String> lines = new ArrayList<String>();
            String line;

            while((line = reader.readLine()) != null){
                lines.add(line);
            }
            String[] msg = new String[lines.size()];
            msg = lines.toArray(msg);

            output.write("HTTP/1.1 200\r\n".getBytes());
            output.write("\r\n".getBytes());

            new HandleConnection(msg).begin(output);

            reader.close();
            output.close();
            System.out.println("Request processed: " + time);
        } catch (IOException e) {
        }
    }

and finally this is the handler:

public void begin(OutputStream output){
    for(int i = 0; i < lines.length; i++){
        System.out.println(lines[i]);
    }
    try{
        output.write("{\"Response\":\"Ok\"}\r\n".getBytes());
    }catch(IOException e){}
}

Answer:

The problem i'm having is that the server code seems to freeze as while((line = reader.readLine()) != null) until the remote client closes the connection.

That's not a problem: it is the correct, specified behaviour.

The problem is that you aren't implementing HTTP correctly. You need a good knowledge of RFC 2616 and its successors, particularly the parts about content length add transfer encoding. This code doesn't exhibit any knowledge of it whatsoever.

And why for example are you sending HTTP 200 before processing the request? How do you know the request processor won't want to return a different code?

Question:

Basically, I am not aware of port before hand. I will make a REST request to a host to send the port number. I am getting the port number, but not able to move ahead as I am not able to set connection factory into inBoundClient with received port number. Please have a look at the code below, to understand the problem.

I have tcp connections defined as below:

<?xml version="1.0" encoding="UTF-8"?>
<context:component-scan base-package="com.tcpclient" />
<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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
    http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd">
<context:annotation-config />
<!--Deserializer for incoming data on the socket -->
<bean
class="org.springframework.integration.ip.tcp.serializer.ByteArraySingleTerminatorSerializer"
id="serializeAndDeserializer">
<constructor-arg type="byte" value="0" />
</bean>



<!-- TCP Client configuration -->

<!-- Channels for communication -->

<int:channel id="tcp-client-input" />

<int:channel id="message" />

<int:channel id="message-serviceActivator" />

<int:gateway id="gateway" service-interface="com.tcpclient.ClientGateway"
default-request-channel="tcp-client-input" default-reply-channel="message" />



<int-ip:tcp-outbound-channel-adapter
id="outBoundClient" channel="tcp-client-input" 
retry-interval="60000" auto-startup="false" />

<int-ip:tcp-inbound-channel-adapter
id="inBoundClient" channel="message" 
client-mode="true" auto-startup="false" retry-interval="60000" />


<int:object-to-string-transformer
input-channel="message" output-channel="message-serviceActivator" />
<int:service-activator input-channel="message-serviceActivator"
method="onRtlsMessageArrival">
<bean class="com.tcpclient.HandleMessage" />
</int:service-activator>
</beans>

Config manager

In my class, I am trying below:

@component
public class ConfigManager {

@Autowired
@Qualifier("clientFactory")
TcpConnectionFactoryFactoryBean connFactory;

@Autowired
@Qualifier("inBoundClient")
SmartLifecycle inboundClient;

@Autowired
@Qualifier("outBoundClient")
SmartLifecycle outBoundClient;

public void initialize(Boolean canStart) {

try {
   if (canStart) {
                    String portResponse = restTemplate.postForObject(SYSTEM_OPEN_SOCK_URI, openSockeEntity,
                            String.class);
                    int portNumber = parsePortFromJson(portResponse);
                    connFactory.setPort(portNumber);
                    TcpReceivingChannelAdapter receiver = (TcpReceivingChannelAdapter) inboundClient;
                     receiver.setConnectionFactory(connFactory);
                     receiver.start();
                    EventDrivenConsumer sender = (EventDrivenConsumer) outBoundClient;
                    sender.start();
    }

} catch (Exception e) {
    logger.error("Error occured while fetching data.");
}
}
}

But, at the line receiver.setConnectionFactory(connFactory);, I have compiler error, The method setConnectionFactory(AbstractConnectionFactory) in the type TcpReceivingChannelAdapter is not applicable for the arguments (TcpConnectionFactoryFactoryBean). Is there anyway I could set port dynamically.

EDIT: As per Gary's suggestion,

@Autowired
@Qualifier("outboundClient.handler")
TcpSendingMessageHandler outBoundClient;`,

outBoundClient.setConnectionFactory(connFactory);
outBoundClient.setRetryInterval(60000);
outBoundClient.afterPropertiesSet();
outBoundClient.start();

But, I have this below error:

Dispatcher has no subscribers for channel 'application.tcp-client-input'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers

when I try gateway.send("ACK"); one of my beans. but I have my outBoundClient having channel="tcp-client-input"


Answer:

Since the port is set in a constructor, you can't change it after the bean is created.

You also can't change the port on a connection factory bean after is has already created its connection factory.

You need to create the connection factory yourself (new TcpNetClientConnectionFactory(...)) rather than have Spring create it - be sure to call afterPropertiesSet() after creating and configuring it and before you add it to the adapter.

Question:

I'm developing an application on android studio. I'm trying to open a socket connection.

When the user enters the right IP address, everything works fine, but if the address is not the right IP, the Socket is not connected.

But the problem is that the Socket does not throw an catch Exception, the app is running and now if the user enters the right ip address, the socket is not connected.

My question is why it does not throw an catch Exception if the IP address is not the right IP and how can I make it work?

Here is the code

   try {
        sockettcp = new Socket(Address, Port);
    } catch (Exception e) {
        valid = false;
    }

Answer:

Normal way of Socket is that it tries to connect to the given IP on the given Port.

If for some reason the IP is not the right one, the Socket will not throw an err, instead it will "timeout" trying to reconnect every minute or so (Main thread or the GUI thread).

The 4 errors that are Thrown by this type of constructor public Socket(String host, int port) are:

IOException //- if an error occurs during the connection

SocketTimeoutException //- if timeout expires before connecting

IllegalBlockingModeException //- if this socket has an associated channel, and the channel is in non-blocking mode

IllegalArgumentException //- if endpoint is null or is a SocketAddress subclass not supported by this socket

To "Fix" your problem, you can set the timeout to your value (this cannot exceed the platform default)

Socket sck = new Socket();
sck.connect(new InetSocketAddress(ip, port), timeout);

To "Check" if your Socket is connected, you could try this:

Socket.isConnected(); //Returns the connection state of the socket.

Note: Closing a socket doesn't clear its connection state, which means this method will return true for a closed socket (see isClosed()) if it was successfully connected prior to being closed.

See the javadoc for more info about theSocket.

Question:

I have some code here to connect to a server and I'm getting the error java.net.ConnectException: Connection Refused.

I tried using ping on the command line and I received packets of data so I know that it's working.

I also tried using telnet to connect to my IP Address and it gave me the same Connection Refused error. Is there something wrong with my code? I'm unsure as to why my connection is getting refused.

Client:

public class InstantMessagingClient 
{
    private Socket socket;

    public InstantMessagingClient(String serverName, int port)
    {

        new Thread() {
            public void run()
            {
                try
                {
                    System.out.println("Connecting to " + serverName + " and port: " + port);
                    //socket.setSoTimeout(10000);
                    socket = new Socket(serverName, port);
                    System.out.println("Client: connected to server at address: " + socket.getLocalAddress() + " and port: " + socket.getPort());
                }
                catch(Exception e)
                {
                    System.out.println(e.toString());
                }

            }
        }.start();
    }
}

Server:

    public class InstantMessagingServer 
{
    private int port;
    private Socket clientSocket;
    private ServerSocket serverSocket;

    public InstantMessagingServer(int port)
    {
        try
        {
            this.port = port;
            serverSocket = new ServerSocket(port);
            serverSocket.setSoTimeout(10000);
            System.out.println("Server: Connected to port");
            new Thread() 
            {
                public void run()
                {
                    while(true)
                    {
                        try
                        {
                            System.out.println("Server: Waiting for port " + serverSocket.getLocalPort());
                            System.out.println(serverSocket.getLocalSocketAddress());
                            clientSocket = serverSocket.accept();
                            System.out.println("Server: Just connected to " + clientSocket.getRemoteSocketAddress());

                        }
                        catch(Exception e)
                        {
                            System.out.println(e.toString());
                            break;
                        }
                    }
                }
            }.start();
        }
        catch(Exception e)
        {
            System.out.println(e.toString());
        }
    }

}

Main:

public void main()
{
InstantMessagingServer server = new InstantMessagingServer(18638);
InstantMessagingClient client = new InstantMessagingClient("(My IP Address)", 18638);
}

Answer:

I'm getting the error java.net.ConnectException: Connection Refused.

That has exactly one meaning. Nothing was listening at the IP:port you tried to connect to.

I tried using ping on the command line and I received packets of data so I know that it's working.

You know that the host is working. Doesn't prove anything about the port or the service you're trying to connect to.

I also tried using telnet to connect to my IP Address and it gave me the same Connection Refused error.

For the same reason.

Is there something wrong with my code?

Either the IP:port is wrong or the server simply hasn't been started.

Question:

I have a connection from client to server over websocket. I was just checking the netstat o/p to understand network level details. I found that when i run netstat -anpt on both client and server , i get different client port . For e.g. On server ,

tcp6 0 0 172.34.10.158:8080 121.71.171.152:28301 ESTABLISHED 13250/java

On client,

tcp6 0 0 192.168.0.111:35129 51.74.132.142:8080 ESTABLISHED 8209/java

So the client port from server is "28301" but when i check on my client, its "35129". I am bit confused on this. P.S. 192.168.0.111 is my local ip , 51.74.132.142 is my server's public ip , 121.71.171.152 is my ISP ip and 172.34.10.158 is my server's private ip. Would be great to know more about this so any docs,resources would be useful.


Answer:

Both the client and the server are behind NAT (Network Address Translation) firewalls.

You listed:

Client: tcp6 0 0   192.168.0.111:35129   51.74.132.142:8080

Server: tcp6 0 0   172.34.10.158:8080   121.71.171.152:28301

Your client has an IP of 192.168.0.111 on your local network, and wants to talk to a server at 51.74.132.142 on port 8080, so it allocates a dynamic port for the conversation (port 35129).

The TCP/IP packets leave the local network through a firewall with source-NAT, which maps the source IP:Port to 121.71.171.152:28301. That is the external IP of your office/home. You can confirm that at http://www.whatsmyip.org/.

The TCP/IP packets arrive at the firewall protecting the server network, which is configured with destination-NAT, so it maps the destination IP:Port to 172.34.10.158:8080.

The server receives the packet and establishes a connection.

Packets flowing the other way are then un-mapped by the firewalls. The firewalls maintain state to remember how to reverse the mapping. To conserve resources, the state has a timeout, so if the server is really slow and takes longer to respond than the timeout, the response will get lost even if the client is still waiting. The network admin controls the timeout. I've seen them as low as 5 minutes, so any response time > 5 mins never arrived back at client. Moral: Setting client timeout higher than firewall NAT timeout just delays the inevitable.

Recap

Network                      Source                Destination
YourPC   --lan--> Firewall   192.168.0.111:35129   51.74.132.142:8080
Firewall --web--> Firewall   121.71.171.152:28301  51.74.132.142:8080
Firewall --lan--> Server     121.71.171.152:28301  172.34.10.158:8080

Question:

Objective - I want to send the entered text in the java (PC) project to the android app which displays this text.The PC is connected to wifi hotspot created by the android mobile.

The PC/client java project code:

public class EcsDemo {

    public static void main(String[] args) {

        System.out.println("Enter SSID to connect :");
        Scanner in = new Scanner(System.in);
        String ssid = in.nextLine();
        System.out.println("You entered ssid " + ssid);
        System.out.println("Connecting to ssid ..");
        DosCommand.runCmd(DosCommand.connectToProfile(ssid));
        // netsh wlan connect name=
        System.out.println("initializing tcp client ..");

            try {
                TCPClient.startTCpClient();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
}

public class TCPClient {
  public static void startTCpClient() throws UnknownHostException, IOException{
      String FromServer;
      String ToServer;

      Socket clientSocket = new Socket("localhost", 5000);

      BufferedReader inFromUser = new BufferedReader(new InputStreamReader(
              System.in));

      PrintWriter outToServer = new PrintWriter(
              clientSocket.getOutputStream(), true);

      BufferedReader inFromServer = new BufferedReader(new InputStreamReader(
              clientSocket.getInputStream()));

      while (true) {

          FromServer = inFromServer.readLine();

          if (FromServer.equals("q") || FromServer.equals("Q")) {
              clientSocket.close();
              break;
          } else {
              System.out.println("RECIEVED:" + FromServer);
              System.out.println("SEND(Type Q or q to Quit):");

              ToServer = inFromUser.readLine();

              if (ToServer.equals("Q") || ToServer.equals("q")) {
                  outToServer.println(ToServer);
                  clientSocket.close();
                  break;
              } else {
                  outToServer.println(ToServer);
              }
          }
      }
  }
  }

Android app/Server code:

public class MainActivity extends Activity {

    private String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        Log.i(TAG, "starting server");

        new ServerAsyncTask().execute();
    }
}

public class ServerAsyncTask extends AsyncTask<Void, Void, Void> {

    @Override
    protected Void doInBackground(Void... params) {
        try {
            TCPServer.startTCPServer();// initTCPserver();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}


public static void startTCPServer() throws IOException{
    String fromclient;
    String toclient;

    ServerSocket Server = new ServerSocket(5000);

    System.out.println("TCPServer Waiting for client on port 5000");
    Log.i("startTCPServer","TCPServer Waiting for client on port 5000");

    while (true) {
        Socket connected = Server.accept();
        System.out.println(" THE CLIENT" + " " + connected.getInetAddress()
                + ":" + connected.getPort() + " IS CONNECTED ");
        Log.i("startTCPServer"," THE CLIENT" + " " + connected.getInetAddress()
                + ":" + connected.getPort() + " IS CONNECTED ");

        BufferedReader inFromUser = new BufferedReader(
                new InputStreamReader(System.in));

        BufferedReader inFromClient = new BufferedReader(
                new InputStreamReader(connected.getInputStream()));

        PrintWriter outToClient = new PrintWriter(
                connected.getOutputStream(), true);

        while (true) {

//            System.out.println("SEND(Type Q or q to Quit):");
//            toclient = inFromUser.readLine();
//
//            if (toclient.equals("q") || toclient.equals("Q")) {
//                outToClient.println(toclient);
//                connected.close();
//                break;
//            } else {
//                outToClient.println(toclient);
//            }


            fromclient = inFromClient.readLine();

            if (fromclient.equals("q") || fromclient.equals("Q")) {
                connected.close();
                break;
            } else {
                System.out.println("RECIEVED:" + fromclient);
            }

        }

    }
}
}

After running the android app and then when I run the java project I get the following exception:

java.net.ConnectException: Connection refused: connect
    at java.net.DualStackPlainSocketImpl.connect0(Native Method)
    at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
    at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
    at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
    at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
    at java.net.PlainSocketImpl.connect(Unknown Source)
    at java.net.SocksSocketImpl.connect(Unknown Source)
    at java.net.Socket.connect(Unknown Source)
    at java.net.Socket.connect(Unknown Source)
    at java.net.Socket.<init>(Unknown Source)
    at java.net.Socket.<init>(Unknown Source)
    at com.expressecs.javademo.TCPClient.startTCpClient(TCPClient.java:15)
    at com.expressecs.javademo.EcsDemo.main(EcsDemo.java:41)

I have referred to the following links:

java.net.ConnectException: Connection refused

Thanks!


Answer:

There is nothing listening at the IP:port you are trying to connect to.

Your server didn't start, or is listening to a different port, or is bound to 127.0.0.1 instead of 0.0.0.0 or a public IP address.

Question:

I have some problem with spring-integration. Lets say, that there is my outgoing communication configuration:

<int:channel id="outputChannel">
    <int:queue /> 
</int:channel>

<int:channel id="outputChannel-in"> <!-- for response from server -->
    <int:queue /> 
</int:channel>

<int-ip:tcp-connection-factory 
    id="outputSocket"
    type="client" 
    single-use="true"
    host="localhost"
    port="666" />

<int-ip:tcp-outbound-gateway id="outGateway"
    request-channel="outputChannel"
    reply-channel="outputChannel-in"
    connection-factory="outputSocket"
    reply-timeout="20000" />

<int:gateway id="myGateway"
     service-interface="some.package.SocketGateway"
     default-request-channel="outputChannel"
     default-reply-channel="outputChannel-in" />

<int:service-activator
    id="myServiceActivator" 
    input-channel="outputChannel-in" 
    ref="myService"
    method="incomingDataHandlingMethod" />

No matter what I'll do with interface some.package.SocketGateway:

option #1:

public interface SocketGateway{
    byte[] send(String text);
}

option #2:

public interface SocketGateway{
    Future<byte[]> send(String text);
}

It doesn't receive any message. I played with configuration a lot. It is only one version of my solutions, but none of them worked.

Here is a server mock:

ServerSocket someSocket = new ServerSocket(666);
Socket socket = someSocket.accept();

PrintWriter  out =
    new PrintWriter (socket.getOutputStream(), true);
BufferedReader in =
    new BufferedReader(
        new InputStreamReader(socket.getInputStream()));

System.out.println("socket accepted");

String data = in.readLine();
while (data != null) {
    System.out.println(data);
    data = in.readLine();
} 

System.out.println("data received");
out.println("ACK");

out.flush();  
System.out.println("data sent");
socket.close();
someSocket.close();

When out.println("ACK"); is after while, connection closes and ACK is not sent. When out.println("ACK"); is before while or inside, it sends message.

What should I do to receive this message?

EDIT: I tried also with:

<int-ip:tcp-outbound-channel-adapter
    id="outboundClient"
    channel="outputChannel"
    connection-factory="outputSocket" />

<int-ip:tcp-inbound-channel-adapter
    id="outboundClient-in"
    channel="outputChannel-in"
    connection-factory="outputSocket" />

Without good results.

EDIT: I've this client side code:

Socket echoSocket = new Socket("10.20.30.40", 11111);
PrintWriter out = new PrintWriter(echoSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));

String encodedMessage = "someMessage";

String result = String.format("%c%s%c%c", (char) 11, encodedMessage, (char) 28, (char) 13);

            out.println(result);
out.flush();
System.out.println("data sent");

File file = new File("result.txt");
BufferedWriter output = new BufferedWriter(new FileWriter(file));

String data;
while ((data = in.readLine()) != null) {
    output.write(data);
}

output.flush();
output.close();

System.out.println("after while");
out.close();
in.close();
echoSocket.close();

And this works fine with external server (server is synchronously sending ACK message, which is received in String data. How to achieve this result with Spring Integration? I can't receive anything...


Answer:

TCP is a stream; it needs structure to delimit messages. The default deserializer expects CRLF at the end.

Send out.println("ACK\r\n");.

You can read about Serializers and Deserializers here.

EDIT:

Your logic is flawed in several ways.

  1. Using PrintWriter.println() only appends LF; you need CRLF unless you change the deserializer.
  2. Your "server" is hung on readLine() until the socket is closed.

This works fine:

ServerSocket someSocket = new ServerSocket(1666);
Socket socket = someSocket.accept();

OutputStream out = socket.getOutputStream();
BufferedReader in =
    new BufferedReader(
        new InputStreamReader(socket.getInputStream()));

System.out.println(Thread.currentThread().getName() +  " socket accepted");

String data = in.readLine();
System.out.println(data);

System.out.println("data received");
out.write("ACK\r\n".getBytes());

out.flush();
System.out.println("data sent");
socket.close();
someSocket.close();

Question:

This is my code:

public class TestClass {
    public static void main(String[] args) throws Exception {
        Socket socket = new Socket("198.252.206.16",80);
        DataOutputStream outToServer = new DataOutputStream(socket.getOutputStream());
        outToServer.writeBytes("GET http://stackoverflow.com:80 HTTP/1.1\n\nHost: http://stackoverflow.com\n");
        InputStream inputStream = socket.getInputStream();
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        int x;
        while((x = inputStreamReader.read()) != -1) {
            System.out.print((char) x);
        }
    }
}

And the response I am getting is:

HTTP/1.1 400 Bad Request
Content-Type: text/html; charset=us-ascii
Date: Thu, 09 Oct 2014 18:47:26 GMT
Content-Length: 334

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Bad Request - Invalid Hostname</h2>
<hr><p>HTTP Error 400. The request hostname is invalid.</p>
</BODY></HTML>
HTTP/1.0 400 Bad request
Cache-Control: no-cache
Connection: close
Content-Type: text/html

<html><body><h1>400 Bad request</h1>
Your browser sent an invalid request.
</body></html>

What is it that I am doing wrong?


Answer:

You're sending the Host header as part of the body of your GET request.

outToServer.writeBytes("GET http://stackoverflow.com:80 HTTP/1.1\n\nHost: http://stackoverflow.com\n");
//                                                               ^ notice two new lines

So your GET is like

GET http://stackoverflow.com:80 HTTP/1.1  // << request method and headers

Host: http://stackoverflow.com  // << request body

Instead, only put one new line there, and two at the end

outToServer.writeBytes("GET http://stackoverflow.com:80 HTTP/1.1\nHost: http://stackoverflow.com\n\n");

It will be correct like

GET http://stackoverflow.com:80 HTTP/1.1  // << request method and headers
Host: http://stackoverflow.com  

Question:

I was trying to create a Client-Server application where the client generates a random number and sends to the server n strings. The connection is closed sending the string "BYE". After that the server has to calculate the total length of the received strings and print it.

The problem is that when my client tries to connect to the server this one throws "java.net.SocketException: Connection reset" exception and crashes.

Here's my Client code:

import java.net.*;
import java.io.*;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ClientStringa {

    public static void main(String[] args) {
        try{
            Socket socket = new Socket("localhost", 5555);
            PrintWriter out = new PrintWriter(socket.getOutputStream());
            Random r = new Random();

            int N = r.nextInt(100);

            for(int i=1;i<=N;i++){
                out.println("String" +i);    
            }
            out.flush();
        }
        catch (IOException ex) {
            Logger.getLogger(ClientStringa.class.getName()).log(Level.SEVERE, null, ex);    
        }
    }
}

My Server code:

import java.io.*;
import java.net.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ServerStringa {
    public static void main(String[] args) {
        try {
            ServerSocket socket = new ServerSocket(5555);

            while(true){
                System.out.println("Waiting for client connections...");
                Socket client = socket.accept();    //connessione dei client
                ThreadStringa thread = new ThreadStringa(client);
                thread.start();             
            }

        } catch (IOException ex) {
            Logger.getLogger(ServerStringa.class.getName()).log(Level.SEVERE, null, ex);
        }   
    }  
}

And my Thread code (since the server must be able to answer more clients):

import java.net.*;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ThreadStringa extends Thread{
    Socket client;

    public ThreadStringa(Socket client) {
        this.client = client;
    }

    public void run(){
        try {
           // DataInputStream input = new DataInputStream(client.getInputStream());
            String message;
            int sum=0;

            InputStream input = client.getInputStream();
            InputStreamReader input2 = new InputStreamReader(input);
            BufferedReader in = new BufferedReader(input2);

            while((message= in.readLine()) != null){
                if(message.equals("BYE")){
                    break;
                }
                sum+=message.length();              
            }

            System.out.println("Total length of received strings: " + sum);   
            input.close();
            client.close();
        } 
        catch (IOException ex) {
            Logger.getLogger(ThreadStringa.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

The full error I get on the server console is:

java.net.SocketException: Connection reset
        at java.net.SocketInputStream.read(Unknown Source)
        at java.net.SocketInputStream.read(Unknown Source)
        at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
        at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
        at sun.nio.cs.StreamDecoder.read(Unknown Source)
        at java.io.InputStreamReader.read(Unknown Source)
        at java.io.BufferedReader.fill(Unknown Source)
        at java.io.BufferedReader.readLine(Unknown Source)
        at java.io.BufferedReader.readLine(Unknown Source)
        at serverstringa.ThreadStringa.run(ThreadStringa.java:27)

Answer:

Instead of PrintWriter in client program, you should use DataOutputStream to communicate with Server in socket programming. Also remember to perform close() from client side. I have only modified your client program, you can check this.

import java.net.*;
import java.io.*;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ClientStringa {

    public static void main(String[] args) {
        try{
            Socket socket = new Socket("localhost", 5555);
            DataOutputStream out=new DataOutputStream(socket.getOutputStream());
//            PrintWriter out = new PrintWriter(socket.getOutputStream());
            Random r = new Random();
            int N = r.nextInt(100);
            for(int i=1;i<=N;i++){
//                out.println("String" +i);
                out.writeUTF("String" +i);
            }
            out.flush();
            out.close();
        }
        catch (IOException ex) {
            Logger.getLogger(ClientStringa.class.getName()).log(Level.SEVERE, null, ex);    
        }
    }
}

Question:

I have some simple client and server code, where the client sends some bytes to the server, and the server responds with some bytes. The client prints the received bytes, and then closes the socket.

This works fine the first time the client runs, but subsequent calls get no response.

package sockets.com;

// Client Side
import java.io.*;
import java.net.*;

public class ClientSideTCPSocket {
    public void run() {
        try {
            int serverPort = 4023;
            InetAddress host = InetAddress.getByName("localhost");

            System.out.println("Connecting to server on port " + serverPort);

            Socket socket = new Socket(host, serverPort);

            System.out.println("Just connected to " + socket.getRemoteSocketAddress());


            OutputStream out = socket.getOutputStream();
            InputStream in = socket.getInputStream();

            String s = "HELLO SERVER";
            byte[] bytes = s.getBytes("US-ASCII");

            for (byte b : bytes) {

                out.write(b);

            }

            int ch = 0;
            while ((ch = in.read()) >= 0) {

                System.out.println("Got byte " + ch);
            }

            out.flush();
            out.close();

            socket.close();

        } catch (UnknownHostException ex) {
            ex.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ClientSideTCPSocket client = new ClientSideTCPSocket();
        client.run();
    }
}

Server code

package sockets.com;

//Server Side
import java.net.*;
import java.io.*;

public class ServerSideTCPSocket {
    public void run() {
        try {
            int serverPort = 4023;
            ServerSocket serverSocket = new ServerSocket(serverPort);
            serverSocket.setSoTimeout(900000);
            while (true) {
                System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");

                Socket server = serverSocket.accept();
                System.out.println("Just connected to " + server.getRemoteSocketAddress());

                //
                int ch = 0;
                while ((ch = server.getInputStream().read()) >= 0) {

                    System.out.println("Got byte " + ch);
                }
                // Write to output stream

                OutputStream out = server.getOutputStream();

                String s = "HELLO CLIENT";
                byte[] bytes = s.getBytes("US-ASCII");

                for (byte b : bytes) {
                    System.out.println(b);

                    out.write(b);

                }

            }
        } catch (UnknownHostException ex) {

            ex.printStackTrace();
        } catch (IOException e) {

            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ServerSideTCPSocket srv = new ServerSideTCPSocket();
        srv.run();
    }

}

Would be grateful for any comments regarding why this is the case. Thank you.


Answer:

A few things:

This block of code will loop forever until after the client closes his connection:

            while ((ch = server.getInputStream().read()) >= 0) {

                System.out.println("Got byte " + ch);
            }

Then after the client closes his connection, the subsequent attempt to send "HELLO CLIENT" to the socket will generate an IO exception. That will trigger your server loop to exit.

The easy fix is to adjust your protocol such that the "message" is completed on some sentinel char. In my easy fix, I just adjusted it to break out when a ! was received.

Better to have each client session terminate on an ioexception instead of the entire server block. My refactor of your code:

public class ServerSideTCPSocket {

    public void tryCloseSocketConnection(Socket socket) {
        try {
            socket.close();
        }
        catch(java.io.IOException ex) {
        }
    }

    public void processClientConnection (Socket clientConnection) throws java.io.IOException {

        int ch = 0;
        while ((ch = clientConnection.getInputStream().read()) >= 0) {

            System.out.println("Got byte " + ch);
            if (ch == '!') {
                break;
            }
        }
        // Write to output stream

        OutputStream out = clientConnection.getOutputStream();

        String s = "HELLO CLIENT!";
        byte[] bytes = s.getBytes("US-ASCII");

        for (byte b : bytes) {
            System.out.println(b);
            out.write(b);
        }
    }

    public void run() {
        try {
            int serverPort = 4023;
            ServerSocket serverSocket = new ServerSocket(serverPort);
            serverSocket.setSoTimeout(900000);
            while (true) {
                System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");

                Socket clientConnection = serverSocket.accept();

                try {
                    System.out.println("Just connected to " + clientConnection.getRemoteSocketAddress());
                    processClientConnection(clientConnection);
                }
                catch (java.io.IOException ex) {
                    System.out.println("Socket connection error - terminating connection");
                }
                finally {
                    tryCloseSocketConnection(clientConnection);
                }
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ServerSideTCPSocket srv = new ServerSideTCPSocket();
        srv.run();
    }
}

Then adjust your client code's message to be:

        String s = "HELLO SERVER!";  // the exclamation point indicates "end of message".

Question:

I am writing a server for a game which I am coding in java. The output stream won't actually send the information back to the client for some reason. I have tried everything, however closing the socket ends up in the program erroring because of the socket closing before it has written to the output stream. I am unable to figure out why.

EDIT: I have put a lot of the code in this gist. Also, for clarification, the response wasn't sending at all, even if I didn't close the socket. The client was simply waiting for an answer, and not receiving one.

Here is my code.

public class ServerThread extends Thread {

private Socket clientSocket;
private List<Player> players;
public Player player = null;

public ServerThread (Socket clientSocket, List<Player> players)
{
    this.clientSocket = clientSocket;
    this.players = players;
}

public void run()
{
    try {
        BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        DataOutputStream os = new DataOutputStream(clientSocket.getOutputStream());

        String req = br.readLine();
        br.close();
        String response = buildResponse(req);

        os.writeBytes(response);
        os.flush();
        System.out.println("Sending [ " + response + " ] to " + clientSocket.getInetAddress().getHostAddress());

        player = addPlayerFromRequest(req);
    } catch (IOException ex) {
        Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
    } 

    try {
        clientSocket.close();
    } catch (IOException ex) {
        Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
    }
}

public String buildResponse(String req)
{
    List<Player> plays;
    plays = players;

    String name = req.split(",")[0];

    String response = "";

    if (plays.size() <= 1) {
        return response;
    }

    for (int i = 0; i < plays.size(); i++) {
        Player p = plays.get(i);
        if (!p.name.equals(name)) {
            response += p.name + "," + p.x + "," + p.y + "," + p.z + "," + p.rx + "," + p.rx + "," + p.rz + ";";
        }
    }
    return response;
}

public Player addPlayerFromRequest (String req)
{
    String[] list = req.split(",");
    String user = list[0];
    float x = Float.parseFloat(list[1]);
    float y = Float.parseFloat(list[2]);
    float z = Float.parseFloat(list[3]);
    float rx = Float.parseFloat(list[4]);
    float ry = Float.parseFloat(list[5]);
    float rz = Float.parseFloat(list[6]);

    return new Player(x, y, z, rx, ry, rz, user);
}
}

Answer:

This code will throw SocketException: Socket closed because of br.close(), but assuming you've removed that, I suggest that your client is reading lines but you aren't sending lines. Add a line terminator to the message, or use BufferedWriter.newLine().

Question:

I created a small Tcp communication application linked below.

si_tcp_sample

It is based on TCP Sample in spring-integration-samples. The message generated by the Gateway is sent over TCP by the Outbound Gateway to the Inbound Channel Adapter. In turn the Outbound Channel Adapter echo response comes back over TCP. This application has two TcpNetClientConnectionFactories, the one is set a interceptor factory chain and another is not. Running this application, the log like below is outputted.

TcpConnectionOpenEvent with TcpConnection wrapped Interceptor↓
16:50:01.411 [main] DEBUG com.neriudon.example.tcp.listener.TcpConnectionEventsListener - ★OPEN★ TcpConnectionOpenEvent [source=SimpleInterceptor:null], [factory=unknown, connectionId=localhost:50001:64609:627f6eb5-401f-44e2-88a9-4f966ee66092] **OPENED** 

TcpConnectionOpenEvent with raw TcpConnection↓
16:50:01.426 [main] DEBUG com.neriudon.example.tcp.listener.TcpConnectionEventsListener - ★OPEN★ TcpConnectionOpenEvent [source=TcpNetConnection:localhost:50002:64610:ee9b0bcd-aa9a-4fdb-9194-2e761caabed6], [factory=client2, connectionId=localhost:50002:64610:ee9b0bcd-aa9a-4fdb-9194-2e761caabed6] **OPENED** 

TcpConnection wrapped interceptor publish TcpConnectionOpenEvent whose connection factory property is "unknown". I think that this connection factory property should be "client1". Is it why? (The version of Spring Integration is 4.3.12.)

Editted from here

Other TcpConnectionEvents' connection factory property seem correct. For example, TcpConnectionCloseEvent log is below.

TcpConnectionCloseEvent with TcpConnection wrapped Interceptor↓
20:26:54.009 [main] DEBUG com.neriudon.example.tcp.listener.TcpConnectionEventsListener - ★CLOSE★ TcpConnectionCloseEvent [source=TcpNetConnection:localhost:50001:53828:ec63181f-3db1-478b-8a38-160a431a8887], [factory=client1, connectionId=localhost:50001:53828:ec63181f-3db1-478b-8a38-160a431a8887] **CLOSED** 

TcpConnectionCloseEvent with raw TcpConnection↓
20:26:54.021 [main] DEBUG com.neriudon.example.tcp.listener.TcpConnectionEventsListener - ★CLOSE★ TcpConnectionCloseEvent [source=TcpNetConnection:localhost:50002:53829:4e02e3cc-7eb8-4e5d-a41a-2e6ff99518aa], [factory=client2, connectionId=localhost:50002:53829:4e02e3cc-7eb8-4e5d-a41a-2e6ff99518aa] **CLOSED** 

Answer:

It's a bug; the connection factory name is not propagated to the interceptor.

Please open a JIRA Issue.

Question:

I have a simple TcpOutboundGateway configured via annotations with the following configuration:

@Bean
@ServiceActivator(inputChannel="toTcpChannel")
public TcpOutboundGateway outboundClient() {
    TcpOutboundGateway tcpOutboundGateway = new TcpOutboundGateway();
    tcpOutboundGateway.setConnectionFactory(clientFactory());
    tcpOutboundGateway.setRequiresReply(true);
    tcpOutboundGateway.setReplyChannel(filterChannelInput());
    tcpOutboundGateway.setRequestTimeout(tcpRequestTimeout);
    tcpOutboundGateway.setRemoteTimeout(tcpReplyTimeout);
    return tcpOutboundGateway;
}

@Bean
public AbstractClientConnectionFactory clientFactory() {

    TcpNetClientConnectionFactory factory = new TcpNetClientConnectionFactory(tcpHost, Integer.parseInt(tcpPort));          
    factory.setSoKeepAlive(true);
    factory.setSoReceiveBufferSize(tcpBufferSizeReal);
    factory.setSoSendBufferSize(tcpBufferSizeReal);
    factory.setSerializer(serializer());
    factory.setDeserializer(serializer());      
    factory.setSingleUse(false);    
    return factory;
}

Setting factory.setSingleUse(false); I have detected the following random issue in my connection:

13:02:10,851 WARN  [org.springframework.integration.ip.tcp.connection.TcpMessageMapper] (pool-6-thread-1) Null payload from connection XXXX.XXXX.XXXX.XXXX:9100:52940:22539566-1e50-4f68-a599-0b211ab3c6ef
13:02:10,851 WARN  [org.springframework.integration.ip.tcp.connection.TcpMessageMapper] (pool-6-thread-1) Null payload from connection XXXX.XXXX.XXXX.XXXX:9100:52940:22539566-1e50-4f68-a599-0b211ab3c6ef
13:02:10,851 WARN  [org.springframework.integration.ip.tcp.connection.TcpMessageMapper] (pool-6-thread-1) Null payload from connection XXXX.XXXX.XXXX.XXXX:9100:52940:22539566-1e50-4f68-a599-0b211ab3c6ef
13:02:10,851 WARN  [org.springframework.integration.ip.tcp.connection.TcpMessageMapper] (pool-6-thread-1) Null payload from connection XXXX.XXXX.XXXX.XXXX:9100:52940:22539566-1e50-4f68-a599-0b211ab3c6ef
.....
[Stackoverflow exception in JBOSS]

Ok, I changed factory.setSingleUse(true); to close the socket for each connection and obviously set the log level to ERROR but I do not understand the issue. ¿What is the reason? ¿Invalid END OF MESSAGE? ¿Serializer?

Additionally, I tested with Wireshark if the socket receives null messages but there are no messages after the last received message (correctly formatted).

¿Any suggestions?


Answer:

You need to show your serializer() bean.

It means your deserialize() method returned null which is ignored (and logged).

If the deserializer detects a socket close between messages, it should throw a SoftEndOfStreamException which is a signal to the framework that we are done with receiving messages from this socket.

Question:

I wrote a client which basically just open a socket and send content over the connection. ( the content follows the Http protocol)

The problem I'm facing regards to the question - how and when should i close the connection. The issue is that the connection sometime closes too early ("FIN" is sent to the server before the server answered).

in this case the server's answer is lost. I tried to use Thread.sleep before closing the connection but nothing seems to affect the time between the content is sent and the "FIN" message is sent. (viewed in Wireshark)

The answer sometimes arrive and sometimes not ( race condition).

How can i delay the "FIN" message so i won't miss the server's response?

i added the relevant class. The relevant function is sendContentOverSocket

public class SocketClient {

           private String hostName;
           private int portNumber;
           private Socket ConnectionSocket;

           public void init(String hostName, int portNumber){
                          this.hostName = hostName;
                          this.portNumber = portNumber;
                          this.ConnectionSocket=createSocketConnection();

           }

           private Socket createSocketConnection() {
                          Socket socket = null;
                          try {
                                         socket = new Socket(this.hostName, this.portNumber);
                                         return socket;
                          } catch (UnknownHostException e) {
                                         e.printStackTrace();
                          } catch (IOException e) {
                                         e.printStackTrace();
                          }

                          return socket;
           }

           public void sendContentOverSocket(String content) {
                          try {
                                         PrintWriter out = new PrintWriter(
                                                                       ConnectionSocket.getOutputStream(), true);
                                         BufferedReader in = new BufferedReader(new InputStreamReader(
                                                                       ConnectionSocket.getInputStream()));
                                         out.print(content);

                                         try {
                                                        Thread.sleep(2000);
                                         } catch (InterruptedException e) {
                                                        // TODO Auto-generated catch block
                                                        e.printStackTrace();
                                         }

                                         out.close();
                                         in.close();                           
                                         ConnectionSocket.close();

                          } catch (IOException e) {
                                         e.printStackTrace();
                          }
           }

}


Answer:

TCP works with a concept called a half close. When you close the socket that is an indication that you are not going to send anymore. In your explanation I see "FIN is sent to the server before the server answered", if you are the client, that would mean that you have performed a close on the socket. If you expect a result from a server within a certain time frame you need some kind of timing mechanism, possibly making use of select in combination with a timeout. If the server closes his end of the connection, you detect this by receiving bytes in receive. Usually this means that you have to close the socket too. So in conclusion there is 3 reasons for you to close the socket :

  • the server closes his end of the socket basically saying i am not going to send anymore
  • you have waited for a while and you are tired of waiting and decide to close the socket yourself.
  • any other error conditions but usually they all appear like receiving 0 bytes or a negative number.

Question:

I have 2 connections established from a JMeter instance to an Apache Server, and from the Apache server to a Java application deployed in Jonas.

When I kill the JMeter process, the connection to Apache is closed with a [RST]. Then Apache sends a [FIN, ACK] to Jonas. Jonas has not sent all data, so it keeps sending data. Jonas closes the connection later with a [FIN,ACK]. This behaviour is described in TCP RFC.

So, the problem is Apache receives all data from Jonas, even if Apache can not send it to JMeter.

My question is: Can my Java application be triggered on receipt of the FIN,ACK send from Apache ?


Answer:

Not directly, eventually java may throw a IOException from the InputStream or OutputStream but this is platform dependent.

there was talk of a "raw sockets" java implementation prior to the release of JDK 7 but somehow I don't think it ever got off the ground.

Question:

I am new to android. I tried to build an application which sends a string from android mobile to a java client on my pc. here is the server side:

public class Ser {

public static void main(String[] args) throws IOException {
    ServerSocket ss = new ServerSocket(12345);
    Socket s = ss.accept();
    InputStream is = s.getInputStream();
    InputStreamReader isr = new InputStreamReader(is);
    BufferedReader br = new BufferedReader(isr);
    System.out.println("message received from server is :");
    String ms = br.readLine();
    System.out.println("" + ms);
}

}

and here is the client side:

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Socket s= null;
    try {
    s = new Socket("192.168.0.102",12345);
    OutputStream os=s.getOutputStream();
    PrintWriter pw=new PrintWriter(os);
    pw.println("Hey!!! I am from client side ");
    pw.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

}

but this is giving the following error:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.ankitanand.udp/com.example.ankitanand.udp.MainActivity}: android.os.NetworkOnMainThreadException
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2097)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2122)
        at android.app.ActivityThread.access$600(ActivityThread.java:140)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1228)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:4895)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)
        at dalvik.system.NativeStart.main(Native Method)
 Caused by: android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1118)
        at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:84)
        at libcore.io.IoBridge.connectErrno(IoBridge.java:127)
        at libcore.io.IoBridge.connect(IoBridge.java:112)
        at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
        at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
        at java.net.Socket.startupSocket(Socket.java:566)
        at java.net.Socket.tryAllAddresses(Socket.java:127)
        at java.net.Socket.<init>(Socket.java:177)
        at java.net.Socket.<init>(Socket.java:149)
        at com.example.ankitanand.udp.MainActivity.onCreate(MainActivity.java:30)
        at android.app.Activity.performCreate(Activity.java:5163)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2061)

             The ip of my pc is 192.168.0.102 Also i have used the following permission in the manifest file

 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>

Answer:

You can't do network stuff on the Main thread. Try using an AsyncTask

Take also a look on this page about Network on Main Thread Exeption.

With that your code will work.

Question:

I implemented a simple TCP Echo server in java. It works fine if I launch it from the command line.

But it doesn't work if I launch it from ant. I tried both 'java' and 'exec' tasks. The process is started correctly but the clients cannot connect to it.

Actually, local clients can establish the connection. But remote clients cannot connect to my TCP server.

Does the ant put some restrictions (sandbox?) on applications launched from it?


Answer:

  1. Check that you are listening on the correct address. Start a shell and use netstat -ano on Windows and netstat -anp on Unix or Mac.
  2. Check that your firewall allows remote connection to the port you are listening on

Question:

I have a multithreaded TCP Server in Java which allows connections from several clients and starts a new ServerThread for each connected Client:

Server Class:

while (!Thread.currentThread().isInterrupted()) {
    try {
        // Create a new thread for each incoming connection.
        Socket clientSocket = serverSocket.accept();
        ServerThread serverThread = new ServerThread(clientSocket, this);
        serverThread.run();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

After a specific timeout, a client closes its socket. How can I interrupt the ServerThread which was connected with the client? clientsocket.isClosed() and !clientSocket.isConnected() don't work for some reason.

Finally, I got it working with the following snippets (the solution is the socket in the resource block and the endless in.readLine() == null):

Server class

public void run() {
    while (!Thread.currentThread().isInterrupted()) {
        try {
            // Create a new thread for each incoming connection.
            Socket clientSocket = serverSocket.accept();
            ServerThread serverThread = new ServerThread(clientSocket, this);
            serverThread.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ServerThread class:

public void run() {
    try (Socket socket = clientSocket; // Enable auto-close for socket...
         PrintWriter out = ...; BufferedReader in = ...;) {

        ...

        while (!clientSocket.isClosed() && !isInterrupted()) {
            if (in.readLine() == null) {
                break;
            }
        }
        System.err.println("Client with port " + clientSocket.getPort() + " closed connection to server.");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Client class: I use the same try with resource block as in the ServerThread class


Answer:

If the client closes a TCP socket uncleanly without sending an explicit FIN (for example, if the client crashes) then the server will not know about it until it next tries to send a packet to the client (at which point the client will sent an RST packet to tell the server the socket was closed).

Assuming you have control of both client and server code, the most robust way to check the connection is to implement a heartbeat mechanism between the two so they are regularly pinging a small piece of data between them to check the validity of the connection.

Question:

I am building TCP/TLS server for IoT network. I am using Java NIO with Reactor pattern to achieve non-blocking always ready to serve server. Some of the server actions can take up to several seconds so I opted to use NIO with worker threads. What is better? Keeping large number of mostly idle connections (it will be more than 10000 connections) or would it be better to force open connection for each request? What is more scalable and more perfomant? I tried to search it but I couldn't find Java comparison using NIO.


Answer:

After research and tryout on my testing env I decided to go concurrent way. I benchmarked it is less overhead using concurrent connection rather than create new connection every 5 seconds. I set up the linux similar to the MigratoryData server.

Source: My benchmark MigratoryData Solving 10M problem ( https://mrotaru.wordpress.com/2015/05/20/how-migratorydata-solved-the-c10m-problem-10-million-concurrent-connections-on-a-single-commodity-server/ )

Question:


Answer:

You declared the field in your activity, but you never initialize it. Check your AsyncTask's doInBackground method. You are creating a new local field called mTcpClient, you are not accessing the MainActivity's field. This is why you got NullPointException.

Here is the fixed code:

package f.l.tcptest;

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    TcpClient mTcpClient;
    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new ConnectTask().execute("");

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                    mTcpClient.sendMessage("testing");
            }
        });

    }

    public class ConnectTask extends AsyncTask<String, String, TcpClient> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();

        }

        @Override
        protected TcpClient doInBackground(String... message) {
            //we create a TCPClient object
            // You should use the global one, do not create the local instance if you want to use it on click event
           mTcpClient = new TcpClient(new TcpClient.OnMessageReceived() {
                @Override
                //here the messageReceived method is implemented
                public void messageReceived(String message) {
                    //this method calls the onProgressUpdate
                    publishProgress(message);
                }
            });
            mTcpClient.run();
            return null;
        }

        @Override
        protected void onProgressUpdate(String... values) {
            super.onProgressUpdate(values);
            //response received from server
            Log.d("test", "response " + values[0]);
            //process server response here....
        }
    }
}

Additional Note for Android:

But this approach is not good. You should follow best practices. Maybe you can use the intent service instead of AsyncTasks and sending message on UI thread.

Question:

I am learning about Sockets in Java and I am only missing how to receive back response from the server.

Following How to send string array object and How to send and receive serialized object in socket channel, I am trying to ask the user to pick as much as he wants out of choices:

1 - 2 - 3 - 4

And then I want to split and send them as an array to a server, where the server should send back the number of choices the user has picked.

For example if the user chose

2 3 4 1 2 3 4 1

Server should return

8

server is sending response fine, but on the client side I get error:

Exception in thread "main" java.net.ConnectException: Connection refused: connect at java.net.DualStackPlainSocketImpl.connect0(Native Method) at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source) at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source) at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source) at java.net.AbstractPlainSocketImpl.connect(Unknown Source) at java.net.PlainSocketImpl.connect(Unknown Source) at java.net.SocksSocketImpl.connect(Unknown Source) at java.net.Socket.connect(Unknown Source) at java.net.Socket.connect(Unknown Source) at java.net.Socket.(Unknown Source) at java.net.Socket.(Unknown Source) at ClientClass.main(ClientClass.java:26)

I am not sure why the issue. Any help?

My Client:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Scanner;

public class ClientClass {

    public static void main(String args[]) throws IOException, ClassNotFoundException 
    {
        // take order and convert it to array of choices
        Scanner myScanner = new Scanner(System.in); // take from user
        System.out.println("Enter all your choices seperated by space:");
        System.out.println("Choices are: 1- 2- 3- 4");
        String orderString = myScanner.next();
        orderString += myScanner.nextLine();
        String orderArray[] = orderString.split(" ");

        // send request to server
        Socket mySocket = new Socket("127.0.0.1", 4444); // create a socket
        ObjectOutputStream out = new ObjectOutputStream(mySocket.getOutputStream());
        out.writeObject(orderArray);  

       // get response from server
       InputStream is = mySocket.getInputStream();
       InputStreamReader isr = new InputStreamReader(is);
       BufferedReader br = new BufferedReader(isr);
       String message = br.readLine();
       System.out.println("Message received from the server : " +message);

    }
}

My Server:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.SocketChannel;
import java.util.Scanner;

public class ServerClass {

    public static void main(String args[]) throws IOException, ClassNotFoundException
    {
        // receive
        ServerSocket myServerSocket = new ServerSocket(4444); // create a server socket
        Socket mySimpleSocket = myServerSocket.accept(); // accept requests
        ObjectInputStream ois = new ObjectInputStream(mySimpleSocket.getInputStream());
        String[] choices = (String[]) ois.readObject();


       // send back response
       OutputStream os = mySimpleSocket.getOutputStream();
       OutputStreamWriter osw = new OutputStreamWriter(os);
       BufferedWriter bw = new BufferedWriter(osw);
       bw.write(choices.length);
       System.out.println("Message sent to the client is "+choices.length);
       bw.flush();

    }
}

Answer:

server is sending response fine

Rubbish. The server isn't even getting an incoming connection, let alone reading the request, let alone sending a response.

but on the client side I get error:

Exception in thread "main" java.net.ConnectException: Connection refused: connect at 

On this evidence the server wasn't even running. Certainly not running in the same host as the client, which is what is required by new Socket("127.0.0.1", 4444).

Question:

I'm trying to write a tcp client and server program. The server's working just fine, it's opening the socket normally, but when I run the client program, i get the following error:

Exception in thread "main" java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(Unknown Source)
    at java.net.SocketInputStream.read(Unknown Source)
    at server.Client.main(Client.java:22)

Can anyone tell me how I fix it? Thanks in advance

Here is my client code

public class Client {

private final static String serverIP = "192.168.56.1";
private final static int serverPort = 50000;
private final static String fileOutput ="D:\\Julian\\Kancolle.7z";

public static void main(String args[]) throws UnknownHostException, IOException {
    Socket sock = new Socket(serverIP, serverPort);
    byte[] byte_arr = new byte[1024];
    InputStream is = sock.getInputStream();
    FileOutputStream fos = new FileOutputStream(fileOutput);
    BufferedOutputStream bos = new BufferedOutputStream(fos);
    int bytesRead = is.read(byte_arr, 0, byte_arr.length);
    bos.write(byte_arr, 0, bytesRead);
    bos.close();
    sock.close();
  }
}

and server code

public class Server implements Runnable {

private final static int serverPort = 50000;                        // reserves port
private final static String fileInput = "D:\\Julian\\Kancolle";     // destination

public static void main(String args[]) throws IOException{

    int bytesRead; // buffer variable

    ServerSocket servsock = new ServerSocket(serverPort);
    File myFile = new File(fileInput);
    while (true) {
      Socket sock = servsock.accept();

      InputStream in = sock.getInputStream();
      OutputStream output = new FileOutputStream(myFile);
      byte[] buffer = new byte[1024]; // buffer

      while((bytesRead = in.read(buffer)) != -1)
      {
          output.write(buffer,  0,  bytesRead);;
      }
      output.close();
      servsock.close();
    }
}

public static void start(){
    Server upd = new Server();  
    Thread tupd = new Thread(upd);  
    tupd.start(); 
}

@Override
public void run() {

}
}

Answer:

This doesn't make any sense. Both sides are reading from the socket and copying to a FileOutputStream. Nobody is sending anything over the socket. So what should really be happening is a mutual-read deadlock after the first connection.

You are also incorrectly closing the ServerSocket inside the accept() loop. So your server will get an undisclosed SocketException: socket closed when trying to accept the second connection, exit, the OS will close the leaked accepted socket, and propagate a FIN or a reset to the peer, depending on the platform.

Question:

I have to send and Receive data over the WiFi within two android device. Code is working fine when I connect the android server code.

Problem is that when i send acknowledgement from server to client it gives exception at client side. I have to Send data from client to server and after that It should return the acknowledgement to Client.

   W: java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)
W:     at libcore.io.IoBridge.maybeThrowAfterRecvfrom(IoBridge.java:592)
W:     at libcore.io.IoBridge.recvfrom(IoBridge.java:556)
W:     at java.net.PlainSocketImpl.read(PlainSocketImpl.java:485)
W:     at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:37)
W:     at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:237)
W:     at java.io.InputStream.read(InputStream.java:162)
W:     at in.co.prosimerp.serverdemo.CleintActivity$MyClientTask.doInBackground(CleintActivity.java:103)
W:     at in.co.prosimerp.serverdemo.CleintActivity$MyClientTask.doInBackground(CleintActivity.java:67)
W:     at android.os.AsyncTask$2.call(AsyncTask.java:292)
W:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
W:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
W:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
W:     at java.lang.Thread.run(Thread.java:818)
W: Caused by: android.system.ErrnoException: recvfrom failed: ECONNRESET (Connection reset by peer)
W:     at libcore.io.Posix.recvfromBytes(Native Method)
W:     at libcore.io.Posix.recvfrom(Posix.java:185)
W:     at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:250)
W:     at libcore.io.IoBridge.recvfrom(IoBridge.java:553)

Client code :

    socket = new Socket(dstAddress, dstPort);
                             OutputStream os = socket.getOutputStream();
                OutputStreamWriter osw = new OutputStreamWriter(os);
                BufferedWriter bw = new BufferedWriter(osw);
               String number = "2";
               String sendMessage = number + "\n";
                bw.write(sendMessage);
                bw.flush();
                System.out.println("Message sent to the server : "+sendMessage);
                ByteArrayOutputStream byteArrayOutputStream =new ByteArrayOutputStream(1024);
                byte[] buffer = new byte[1024];
                int bytesRead;
               InputStream inputStream = socket.getInputStream();
//Exception at this point
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    byteArrayOutputStream.write(buffer, 0, bytesRead);
                    response += byteArrayOutputStream.toString("UTF-8");
                }

Sever Code :

 serverSocket = new ServerSocket(SocketServerPORT);
            while (true) {
                Socket socket = serverSocket.accept();
                count++;
                message += "A#" + count + " from " + socket.getInetAddress()
                        + ":" + socket.getPort() + "\n";                 

                OutputStream outputStream;
                String msgReply = "Hello from Android, you are #" + count;

                try {
                    outputStream = socket.getOutputStream();
                    PrintStream printStream = new PrintStream(outputStream);
                    printStream.print(msgReply);
                    printStream.close();

                    message += "replayed: " + msgReply + "\n";

                    MainActivity.this.runOnUiThread(new Runnable() {

                        @Override
                        public void run() {
                            msg.setText(message);
                        }
                    });

                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    message += "Something wrong! " + e.toString() + "\n";
                }}

Answer:

Your client is sending a message that is never read by the server. When the server closes the socket with unread pending data, it causes a connection reset instead of a normal close.

Question:


Answer:

It should be fixable from inside the PlayerService.java class you have posted. I suggest moving:

in = new Scanner(s.getInputStream());
out = new PrintWriter(s.getOutputStream());

from public void run() to your PlayerService constructor:public PlayerService(Socket aSocket) It looks like the function sendDataToClient is trying to use the out variable before it gets initialised.