0

所以,我正在对 Kryonet 库进行一些试验,并开始我决定开发一个简单的聊天程序,允许从客户端(远程计算机)到服务器(本地计算机)进行通信。

一切似乎都正常,我能够从客户端接收消息到我的服务器。

但是有一个很烦人的问题:如果客户端在一段时间内没有发送任何数据包(这里的数据包是文本消息),他会被服务器断开连接,说他超时了。

我正在努力解决这个问题,我不知道如何解决这个问题......

以下是我的程序的来源(除了注释掉//all my imports以避免有大量的导入行......):

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(服务器端)

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(服务器和客户端通用)

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(客户端)

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");
    }
}
}

有人可以告诉我我做错了什么吗?即使客户端长时间空闲,我也想保持客户端和服务器之间的连接。

先感谢您 !

4

2 回答 2

0

消息传递系统可以根据需要设置/处理连接,或者设置/维护连接并为通道提供流量控制对象,也称为 KeepAlive 消息(其中还可能包含有关连接或客户端/服务器端状态等的遥测详细信息)。

因此,根据您的任务定义(保持连接)和(避免空闲状态的 T/O),最简单的解决方案是:

  1. 在每个发送方配备您的消息传递策略,以aKeepAliveMsgINJECTOR通过连接异步触发“仍然在这里”消息(是的,在您的应用程序级别,因此独立于底层传输 keep-alive(s) )
  2. 在每个接收方实施 anIncomingMessageFILTER以从 [[[aKeepAliveMSG]]] 信令/控制有效负载中拆分有用的聊天内容

完成此操作后,您可以根据自己的意愿或随着消息传递架构需求的增长,将更多逻辑添加到此类琐碎的信号/控制层中。

于 2014-09-29T12:06:16.107 回答
0

我做了一件非常愚蠢的事情。

有这个:mpacket.message = ChattyClient.scanner.nextLine();让我的程序等待输入,因此,在此期间,没有 keepAlive 数据包被发送到服务器。

于 2014-10-05T20:42:23.903 回答