0

So, i'm experimenting a little bit with the Kryonet library, and to start i've decided to develop a simple chat program that would allow to communicate from the client (the remote computer) to the server (local machine).

Everything seems to work, i'm able to receive messages from the client to my server.

But there's a big annoying issue : if the client doesn't send any packet (here the packets are text messages) for a certain time, he gets disconnected by the server saying that he timed out.

I'm struggling with this and I don't know how to fix this ...

Here are the sources of my programs ( except commented out //all my imports so as to avoid having tons of lines of import ... ) :

ChattyServer.java

package com.azsde.Chatty;

//all my imports

public class ChattyServer {

    //Mes objets
    private Server server;
    private ArrayList <Clients> clientsList;

    //Mes méthodes

    //Constructeur
    public ChattyServer() throws IOException
    {
        clientsList = new ArrayList <Clients>();
        server = new Server();
        registerPackets();
        server.addListener(new NetworkListener(clientsList));
        server.bind(101);
        server.start();

        // Open a window to provide an easy way to stop the server.
        JFrame frame = new JFrame("Chatty Server");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.addWindowListener(new WindowAdapter()
        {
            public void windowClosed (WindowEvent evt)
            {
                server.stop();
            }
        });

        frame.getContentPane().add(new JLabel("Close to stop the server."));

        JPanel panel = new JPanel();
        frame.getContentPane().add(panel, BorderLayout.SOUTH);

        JButton btnNewButton = new JButton("New button");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                //Packet3Order order = new Packet3Order();
                //order.start = true;
                //server.getConnections()[0].sendTCP(order);                
                listClients();              
            }
        });
        panel.add(btnNewButton);
        frame.setSize(320, 200);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

    }

    private void registerPackets()
    {
        Kryo kryo = server.getKryo();
        kryo.register(Packet0ConnectionRequest.class);
        kryo.register(Packet1RequestResponse.class);
        kryo.register(Packet2Message.class);
        kryo.register(Packet3Order.class);
    }

    private void listClients()
    {
        for (int i = 0 ; i < clientsList.size() ; i ++)
        {
            if (!clientsList.isEmpty())
            {               
                System.out.println(clientsList.get(i).getUsername());
                System.out.println(clientsList.get(i).getIpAdress());               
            }
        }
    }

    public static void main (String[] args) {
        try {
            new ChattyServer();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Log.set(Log.LEVEL_DEBUG);
}   
}

NetworkListener.java (server side)

package com.azsde.Chatty;

//All my imports

public class ChattyServer {

//Mes objets
private Server server;
private ArrayList <Clients> clientsList;

//Mes méthodes

//Constructeur
public ChattyServer() throws IOException
{
    clientsList = new ArrayList <Clients>();
    server = new Server();
    registerPackets();
    server.addListener(new NetworkListener(clientsList));
    server.bind(101);
    server.start();

    // Open a window to provide an easy way to stop the server.
    JFrame frame = new JFrame("Chatty Server");
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.addWindowListener(new WindowAdapter()
    {
        public void windowClosed (WindowEvent evt)
        {
            server.stop();
        }
    });

    frame.getContentPane().add(new JLabel("Close to stop the server."));

    JPanel panel = new JPanel();
    frame.getContentPane().add(panel, BorderLayout.SOUTH);

    JButton btnNewButton = new JButton("New button");
    btnNewButton.addActionListener(new ActionListener()
    {
        public void actionPerformed(ActionEvent arg0) 
        {               
            listClients();              
        }
    });
    panel.add(btnNewButton);
    frame.setSize(320, 200);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);

}

private void registerPackets()
{
    Kryo kryo = server.getKryo();
    kryo.register(Packet0ConnectionRequest.class);
    kryo.register(Packet1RequestResponse.class);
    kryo.register(Packet2Message.class);
    kryo.register(Packet3Order.class);
}

private void listClients()
{
    for (int i = 0 ; i < clientsList.size() ; i ++)
    {
        if (!clientsList.isEmpty())
        {               
            System.out.println(clientsList.get(i).getUsername());
            System.out.println(clientsList.get(i).getIpAdress());               
        }
    }
}

public static void main (String[] args) 
{
    try {
        new ChattyServer();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    Log.set(Log.LEVEL_DEBUG);
}   
}

Packet.java (common to server and client)

package com.azsde.Chatty;

public class Packet {

        public static class Packet0ConnectionRequest {String username;}
        public static class Packet1RequestResponse {Boolean accepted = false;}
        public static class Packet2Message {String message;}
        public static class Packet3Order {Boolean start = false;}

}

ChattyClient.java

package com.azsde.Chatty;

//My imports

public class ChattyClient {


    public Client client;
    public static Scanner scanner;

    public ChattyClient()
    {
            scanner = new Scanner(System.in);
            client = new Client();
            register();
            NetworkListener nl = new NetworkListener();
            nl.init(client);
            client.addListener(nl);
            client.start();
            client.setKeepAliveTCP(50);
            try 
            {
                client.connect(50000, "127.0.0.1", 101);
            } 
            catch (IOException e) 
            {    
                e.printStackTrace();
                client.close();
            }
    }

    private void register()
    {
        Kryo kryo = client.getKryo();
        kryo.register(Packet0ConnectionRequest.class);
        kryo.register(Packet1RequestResponse.class);
        kryo.register(Packet2Message.class);
        kryo.register(Packet3Order.class);
    }

    public static void main (String[] args)
    {
            new ChattyClient();
            Log.set(Log.LEVEL_DEBUG);
    }
}

NetworkListener.java (client side)

package com.azsde.Chatty;

//My imports

public class NetworkListener extends Listener

{
private Client client;

public void init(Client client) 
{
    this.client = client;
}

public void connected(Connection arg0) 
{
    Packet0ConnectionRequest conRequest = new Packet0ConnectionRequest();
    conRequest.username = System.getProperty("user.name");
    Log.info("[CLIENT] You have connected");
    client.sendTCP(conRequest);
}

public void disconnected(Connection arg0)
{
    Log.info("[CLIENT] You have disconnected.");
}

public void received(Connection c, Object o)
{
    if ( o instanceof Packet1RequestResponse)
    {
        Log.info("I got a response");
        if (((Packet1RequestResponse) o).accepted)
        {
            Log.info("[CLIENT] You have connected.");
            while(true)
            {
                if (ChattyClient.scanner.hasNext())
                {
                    Log.info("Enter your message : ");
                    Packet2Message mpacket = new Packet2Message();
                    mpacket.message = ChattyClient.scanner.nextLine();
                    client.sendTCP(mpacket);

                }
            }
        }

        else
        {
            Log.info("[CLIENT] Connection failed.");
            c.close();
        }

    }

    if ( o instanceof Packet3Order)
    {
        Log.info("I got an order");
        if (((Packet3Order) o).start) Log.info("Start");
        else Log.info("Stop");
    }
}
}

Can someone tell me what i'm doing wrong ? I'd like to keep the connection between the client and the server alive even if the client has been idle for a long time.

Thank you in advance !

user3666197
  • 1
  • 6
  • 50
  • 92
Azsde
  • 11
  • 4
  • You might want to know, that Stackoverflow Netiquette discourages from using a URL-link derrogated posts. Rather include the merit her, in your post, once the referred page(s) need not be persistent forever so as to still provide your intended content. You might want to re-read the StackOverflow Do-s and Don't-s and re-edit your post to both show your will to comply with the Community Netiquette and also to avoid any adverse step from any Moderator who may feel necessary to enforce the said rules. Enjoy the great Community of contributing members you have just stepped in to belong to. – user3666197 Sep 28 '14 at 22:13

2 Answers2

0

Messaging systems either setup/dispose connections once per a need arises, or setup/maintain connectivity and feed the channels with flow-control objects also known as KeepAlive messages ( which may also contain telemetry details about connection or client/server side state etc ).

So, based on your task definition ( keep connections ) and ( avoid T/O on idle state(s) ) the simplest solution is:

  1. equip your messaging strategy with aKeepAliveMsgINJECTOR on each sender side to asynchronously fire "still-here" messages over the connection (yes, on you application level, thus independent of the underlying transport keep-alive(s) )
  2. implement anIncomingMessageFILTER on each receiver side to split a useful chat-content from [[[aKeepAliveMSG]]] Signalling/Control payload(s)

Having done so, you may add more logic into such trivial Signalling/Control layer per your wish or as your messaging architecture needs grow.

halfer
  • 19,824
  • 17
  • 99
  • 186
user3666197
  • 1
  • 6
  • 50
  • 92
  • Isn't that what client.setKeepAliveTCP(50); is supposed to do? – Azsde Oct 01 '14 at 07:14
  • As per your own observations, that setup did not manage to avoid time-outs and failed to operate, didn't it? Rather inject your own message flow, under your explicit control, to move forward from the square 1. You may add UUID(s), telemetry details, round-trip latency logging and many other things to diagnose the operating environment that also help you to isolate the root cause of the issues. – user3666197 Oct 01 '14 at 12:12
0

I did something very stupid.

Having this : mpacket.message = ChattyClient.scanner.nextLine(); makes my program wait for a input, thus, during this period, no keepAlive packet were sent to the server.

Azsde
  • 11
  • 4