A persistent and persistent socket connection in java

I created a client-server connection, something like a chat system. I used to use a while

client side loop and it waited to read a message from the console every time (of course the server has a loop while

, and also to serve forever). But right now I am trying to first create a connection at the start of the session and then sometimes send a message during the session in order to maintain a persistent and persistent connection.

Currently, without the loop, the while

client is closing the connection and I have no idea how to find a workaround.

Here is the client code:

import java.net.*;
import java.io.*;
public class ControlClientTest {
    private Socket socket = null;
//  private BufferedReader console = null;  
    private DataOutputStream streamOut = null;

    public static void main(String args[]) throws InterruptedException {
        ControlClientTest client = null;

        String IP="127.0.0.1";
        client = new ControlClientTest(IP, 5555);
    }

    public ControlClientTest(String serverName, int serverPort) throws InterruptedException {
        System.out.println("Establishing connection. Please wait ...");
        try {
            socket = new Socket(serverName, serverPort);
            System.out.println("Connected: " + socket);
            start();
        } catch (UnknownHostException uhe) {
            System.out.println("Host unknown: " + uhe.getMessage());
        } catch (IOException ioe) {
            System.out.println("Unexpected exception: " + ioe.getMessage());
        }

        String line = "";
//      while (!line.equals(".bye")) {
            try {
                Thread.sleep(1000);
                //TODO get data from input
//              line = console.readLine();
                line="1";
                if(line.equals("1"))
                    line="1,123";
                streamOut.writeUTF(line);
                streamOut.flush();
            } catch (IOException ioe) {
                System.out.println("Sending error: " + ioe.getMessage());
            }
//      }
    }

    public void start() throws IOException {
//      console = new BufferedReader(new InputStreamReader(System.in));
        streamOut = new DataOutputStream(socket.getOutputStream());
    }

}

      

And here is the server code:

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

public class ControlServer {
    private Socket socket = null;
    private ServerSocket server = null;
    private DataInputStream streamIn = null;

    public static void main(String args[]) {

        ControlServer server = null;
        server = new ControlServer(5555);
    }

    public ControlServer(int port) {
        try {
            System.out
            .println("Binding to port " + port + ", please wait  ...");
            server = new ServerSocket(port);
            System.out.println("Server started: " + server);
            System.out.println("Waiting for a client ...");
            socket = server.accept();
            System.out.println("Client accepted: " + socket);
            open();
            boolean done = false;
            while (!done) {
                try {
                    String line = streamIn.readUTF();
                    // TODO get the data and do something
                    System.out.println(line);

                    done = line.equals(".bye");
                } catch (IOException ioe) {
                    done = true;
                }
            }
            close();
        } catch (IOException ioe) {
            System.out.println(ioe);
        }

    }


    public void open() throws IOException {
        streamIn = new DataInputStream(new BufferedInputStream(
                socket.getInputStream()));
    }
public void close() throws IOException {
    if (socket != null)
        socket.close();
    if (streamIn != null)
        streamIn.close();
}

}

      

+3


source to share


3 answers


I would like to summarize some good practices regarding the stability of TCP / IP connections that I use on a daily basis.

Good Practice 1: Built-in Keep-Alive

socket.setKeepAlive(true);

      

It will automatically send a signal after a period of inactivity and check the response. The storage interval varies by operating system, but has some disadvantages. Overall, it can improve the stability of your connection.

Good Practice 2: SoTimeout

When you do read

(or readUTF

in your case) your thread will actually block forever. In my experience, this is bad practice for the following reasons: It is difficult to close the application. It's just a socket.close()

messy challenge .

A clean solution is a simple read timeout (eg 200ms). You can do it with the method setSoTimeout

. When the method timed out read()

will be called SocketTimeoutException

. (which is a subclass IOException

).

socket.setSoTimeout(timeoutInterval);

      

Here is an example of loop implementation. Pay attention to the condition shutdown

. Just set it to true and your thread will die peacefully.

while (!shutdown)
{
  try
  {
    // some method that calls your read and parses the message.
    code = readData();
    if (code == null) continue; 
  }
  catch (SocketTimeoutException ste)
  {
    // A SocketTimeoutExc. is a simple read timeout, just ignore it.
    // other IOExceptions will not be stopped here.
  }
}

      



Good Practice 3: Tcp No-Delay

Use the following setting when you often interact with small teams that need to be processed quickly.

try
{
  socket.setTcpNoDelay(true);
}
catch (SocketException e)
{
}

      

Good Practice 4: Heartbeat

In fact, there are many side scenarios that are not yet covered.

One of these is, for example, server-side applications, which are designed to only communicate with one client at a time. They sometimes accept connections and even receive messages, but never answer them.

One more: sometimes when you lose your connection, it can actually take a long time before your OS notices it. Possibly due to the disadvantages described in good practice 3, but also in more complex network situations (eg using RS232-to-Ethernet converters, VMware servers, etc.) This happens frequently.

The solution here is to create a thread that sends a message every x seconds and then waits for a response. (for example, every 15 seconds). To do this, you need to create a second thread that simply sends a message every 15 seconds. Second, you need to extend the good practice code a bit.

  try
  {
    code = readData();

    if (code == null) continue; 
    lastRead = System.currentTimeMillis();

    // whenever you receive the heart beat reply, just ignore it.
    if (MSG_HEARTBEAT.equals(code)) continue;

    // todo: handle other messages
  }
  catch (SocketTimeoutException ste)
  {
    // in a typical situation the soTimeout is about 200ms
    // the heartbeat interval is usually a couple of seconds.
    // and the heartbeat timeout interval a couple of seconds more.
    if ((heartbeatTimeoutInterval > 0) &&
        ((System.currentTimeMillis() - lastRead) > heartbeatTimeoutInterval))
    {
      // no reply to heartbeat received.
      // end the loop and perform a reconnect.
      break;
    }
  }

      

You need to decide if your client or server should send the message. This decision is not that important. But, for example, if your client is sending a message, then your client will need an additional thread to send the message. Your server should send a response when it receives a message. When your client receives a response, it should be simple continue

(i.e. see code above). And both sides have to check, "How long has it been?" in a very similar way.

+8


source


Wrap the client socket connection around a stream. Use a queue lock to wait for messages . There should only be one sender queue in your application, so use the singleton pattern.

eg.

QueueSingleton queue = QueueSingleton.getSenderQueue();
Message message = queue.take() // blocks thread
send(message); //send message to server

      

When you need to send a message to the server, you can use the block queue to send the message.



QueueSingleton queue = QueueSingleton.getSenderQueue();
queue.put(message)

      

The client thread will wake up and process the message.

Use a timer task to maintain the connection . It is a special type of thread that invokes a repeating execution method at specific times. You can use this to post a message, ping message, as often.

To process a received message, you might have another thread waiting for messages on a different blocking queue (recipient queue). The client thread puts the received message into this queue.

+1


source


You can wrap a thread around the connection and send a status periodically so that the line opens, say every 30 seconds or whatever. Then when in fact it has data to send, it will reset the save for 30 seconds after the last transfer. The status can be useful to see if the client is alive anyway, so at least it can be a useful ping.

Also, you have to change the server code, you seem to only be handling one connection at the moment. You have to loop and when the socket connection comes in, create a thread to handle the client request and go back to listening. I probably read a lot about what your test code might be.

0


source







All Articles