简体   繁体   English

如何在UDP Java中检查客户端是否连接到服务器

[英]How to check if client is connected to server in UDP Java

I am doing a UDP program in Java language.我正在用 Java 语言做一个 UDP 程序。 I wish to send a message from the server to the client.我希望从服务器向客户端发送消息。 However, as I am using UDP protocol.但是,因为我使用的是 UDP 协议。

How do I ensure that the client is connected before the datagram packet is sent?如何在发送数据报包之前确保客户端已连接?

buf = stringMessage.getBytes();
serversocket.send(new DatagramPacket(buf, stringMessage.length(), ia, cport));
// how to ensure that client is connected before sending?

UDP protocol doesn't have state, so there is no "connection". UDP 协议没有状态,所以没有“连接”。

You either use TCP or have to make your server respond to confirm that message is received.您要么使用 TCP,要么必须让您的服务器响应以确认收到消息。

there is no such 'connected' state in UDP protocol, however, you can create your own function to kinda have a list of connected clients. UDP 协议中没有这种“已连接”状态,但是,您可以创建自己的函数来获得已连接客户端的列表。

Below I will present you some code I created to retrieve UDP clients and maintain them in a connected list of clients,下面我将向您展示我创建的一些代码,用于检索 UDP 客户端并将它们维护在连接的客户端列表中,

When you create the server you can wait for incoming connections, ( UDP clients sending "connect" messages ), then when the server receive those request check on the client list if that client is already there, if not, it creates a new client, it assigns an ID and send a response to the client with the ID assigned and message connected something like: "1001#connected", after client send the request is waiting for the response, when the response arrives then ID is retrieved and set to the ID property of the client, and execute socket.connect( ip, port ) in order to only allow request/response from/to server创建服务器时,您可以等待传入连接,(UDP 客户端发送“连接”消息),然后当服务器收到这些请求时,检查客户端列表中的客户端是否已经存在,如果没有,则创建一个新客户端,它分配一个 ID 并向客户端发送响应,其中分配了 ID 并连接了消息,例如:“1001#connected”,客户端发送请求后正在等待响应,当响应到达时,将检索 ID 并将其设置为客户端的 ID 属性,并执行 socket.connect( ip, port ) 以只允许来自/到服务器的请求/响应

/**@TODO consider add variable to specify number of clients
 * this class contains main server connection with all clients
 * connected to a game, this connection is using UDP and it is really
 * simple, if you need to use other kind of connection you are free
 * to create your own
 * @author PavulZavala
 */
public class Server 
        implements Conectable
{

    protected DatagramSocket serverSocket;

    protected boolean isAccepting;

    protected List<Client> clientList;

    protected String ip;

    protected int port;

    private Thread connectThread;


    /**
     * 
     * @param port
     * @throws IOException 
     */
    public Server( int port ) throws IOException
    {
        serverSocket = new DatagramSocket( port );

        this.port = port;
        this.isAccepting = true;
        clientList = new ArrayList<>();
    }//


    /**
     * Accept UDP connections and store in clientList
     * ----------------------------------------------
     * this method is used to receive packages from UDP clients, 
     * and store their IP and ADDRESS in the client list, 
     * - you can change isAccepting to false to no receive more
     * client connections or simple, call stopIsAcception to finish
     * the Tread.
     * @TODO it can be changed to accept like server socket
     */
    @Override
    public void connect()
    {
       connectThread = new Thread( ()->
        {

            while( isAccepting )
            {
                try {
                    //datagram packet to receive incoming request from client
                    DatagramPacket request = 
                            new DatagramPacket( new byte[ Config.UDP_BUFFER_SIZE ], Config.UDP_BUFFER_SIZE );

                    serverSocket.receive( request );

                    //get Port and Address from client
                    //and check if exists in clientList
                    Client c = clientList
                            .stream()
                            .filter( client ->
                            {
                                return client.getIp().equals( request.getAddress().getHostAddress() );
                            }).findFirst().orElse( null );

                    //if no exists add it and send response
                    if( null == c )
                    {
                        Client client = new Client();
                        client.setIp( request.getAddress().getHostAddress() );
                        client.setPort( request.getPort() );
                        client.setId( generateId() );

                        //adding new client to the list
                        clientList.add( client );

                        byte[] bufResp = (client.getId() + "#connected").getBytes( "UTF-8" );
                       DatagramPacket resp = 
                               new DatagramPacket(bufResp, bufResp.length, 
                                       InetAddress.getByName( client.getIp() ), 
                                       client.getPort());

                       System.err.println( client.getId()+ " Connected, response Sent" );
                       serverSocket.send( resp );

                    }//

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

            }
        });//.start();
        connectThread.start();
    }//


    /**
     * this stops thread to accepts client socket connections
     * @throws java.lang.InterruptedException
     */
    public void stopAccepting() throws InterruptedException
    {
        connectThread.join();
    }

    /**
     * this closes the DatagramSocket that is acting
     * as server
     */
    public void closeServer()
    {
        serverSocket.close();
    }

    /**
     * used to receive UDP packets from clients
     * this method creates its own Thread so it can
     * receive packages without blocking the game
     * @param r
     */
    public void receive( Requestable r)
    {
        new Thread(()->
        {
            while( true )
            {
            r.receiveData();
            }
        }).start();   
    }//

    /**
     * used to generate id for connected clients
     * @return 
     */
    private int generateId()
    {
        return ++Config.SOCKET_ID_COUNTER;
    }

    /**
     * used to send UDP packets to clients
     * @param r
     */
    public void send( Responsable r )
    {
        r.sendData();
    }

    public DatagramSocket getServerSocket() {
        return serverSocket;
    }

    public void setServerSocket(DatagramSocket serverSocket) {
        this.serverSocket = serverSocket;
    }

    public boolean isIsAccepting() {
        return isAccepting;
    }

    public void setIsAccepting(boolean isAccepting) {
        this.isAccepting = isAccepting;
    }

    public List<Client> getClientList() {
        return clientList;
    }

    public void setClientList(List<Client> clientList) {
        this.clientList = clientList;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }






}//

Client class:客户端类:

how do you now client was connected with the server, simple id property must be different than cero, in my implementation all ID are numeric starting on 1001, and that ID is only created by server, the only gap i have right now is how the server now if the client is still active, i am thinking to create another Thread where i can send messages periodically from client to server in order to ensure we are still communication, if the server does not receive for example a request from a client in 5 minutes, servers disconnects the client or it can ignore send broadcast messages to the client until it receives a new message ( i am currently working on this )现在客户端如何与服务器连接,简单的 id 属性必须与 cero 不同,在我的实现中,所有 ID 都是从 1001 开始的数字,并且该 ID 仅由服务器创建,我现在唯一的差距是服务器现在如果客户端仍然处于活动状态,我正在考虑创建另一个线程,我可以在其中定期从客户端向服务器发送消息以确保我们仍在通信,如果服务器没有收到例如来自客户端的请求 5分钟,服务器断开客户端连接,或者它可以忽略向客户端发送广播消息,直到它收到新消息(我目前正在处理这个)

public class Client 
        implements Conectable
{

    protected DatagramSocket socket;
    protected String ip;
    protected int port;
    protected int id;
    private Thread connectThread;

    /**
     * constructor without arguments to use with getters and setters
     * @throws java.net.SocketException
     */
    public Client() throws SocketException
    {
        this.socket = new DatagramSocket();
        id = 0;
        //id set after increasement
        //id = ++Config.SOCKET_ID_COUNTER; 
    }

    /**
     * this constructor creates a client indicating the ip and port
     * where the server
     * @param ip
     * @param port
     * @throws SocketException 
     */
    public Client( String ip, int port ) throws SocketException
    {
    this();
    this.setIp( ip );
    this.setPort(port);
    }

    public DatagramSocket getSocket() {
        return socket;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }



    /**
     * this method send a request to the server to connect
     */
    @Override
    public void connect()
    {
        try 
        {
            //send connect request to server
            send( "connect" );
        }
        catch (IOException ex) 
        {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }


        connectThread = 
            new Thread( ()->
        {
            while( id == 0 )
            {
                 DatagramPacket response =
                            new DatagramPacket(new byte[ Config.UDP_BUFFER_SIZE], Config.UDP_BUFFER_SIZE );

                try 
                {

                    socket.receive( response );

                    String resp = new String( response.getData(), "UTF-8" );
                    resp = resp.trim();
                    System.err.println("getting DATA: "+resp);


                    if( resp.trim().contains( "connected" ) )
                    {   
                    id = Integer.parseInt( resp.trim().split( "#" )[0] ) ;
                    socket.connect( InetAddress.getByName( ip ), port );
                    stopConnecting();
                    }


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

            }

        });

        connectThread.start();

    }

    /**
     * method used to receive responses from server,
     * every time this method is called a new Thread is created
     * be careful not to call many times this
     * @param r 
     */
    public void receive( Requestable r )
    {
        new Thread(()->
        {
            while( true )
            {
            r.receiveData();
            }

        }).start();

    }

    /**
     * this method is used to send requests to server
     * @param r 
     */
    public void send( Responsable r )
    {
    r.sendData();
    }


    /**
     * this method will send a request to the server to
     * the specific IP and port set by this class
     * @param data request data
     * @throws UnknownHostException 
     */
    public void send( String data ) throws UnknownHostException, IOException
    {
        byte[] dataBuf = data.getBytes();
        DatagramPacket request = 
                new DatagramPacket(dataBuf, 
                        dataBuf.length, InetAddress.getByName( ip ), port );

        socket.send( request );
    }

    /**
     * this method kills Thread used that is created
     * when we attempt to connect to the server
     * @throws InterruptedException 
     */
    public void stopConnecting() throws InterruptedException
    {
    connectThread.join();
    }
}//

Server implementation, this can be done in the main of the app that will be the client服务器实现,这可以在将成为客户端的应用程序的主体中完成

try 
        {
            System.err.println("starting server");
           Server s = new Server( 24586 );

            //accept incoming conenctions
            s.connect();

        } 
        catch (IOException ex) 
        {
            Logger.getLogger(DemoLevel.class.getName()).log(Level.SEVERE, "::: error con algo", ex);
        }

Client implementation:客户端实现:

try 
        {
            client = new Client( "127.0.0.1" , 24586 );


            System.err.println("waiting to connect to the server");
            client.connect();

        } 
        catch ( SocketException ex ) 
        {
            Logger.getLogger(DemoLevel.class.getName()).log(Level.SEVERE, "::: error with server connection", ex);
        }

i hope this can be usefull for you.我希望这对你有用。

Console Messages from server:来自服务器的控制台消息:

> Task :run
starting server
1001 Connected, response Sent

Console Messages from client:来自客户端的控制台消息:

> Task :run
waiting to connect to the server
getting DATA: 1001#connected

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM