Как проверить, подключен ли клиент к серверу в UDP Java - PullRequest
0 голосов
/ 23 апреля 2019

Я делаю программу UDP на языке Java. Я хочу отправить сообщение с сервера клиенту. Однако, поскольку я использую протокол UDP.

Как мне убедиться, что клиент подключен до отправки пакета дейтаграммы?

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

Ответы [ 2 ]

2 голосов
/ 23 апреля 2019

Протокол UDP не имеет состояния, поэтому нет «соединения».

Вы либо используете TCP, либо должны заставить свой сервер ответить, чтобы подтвердить получение сообщения.

0 голосов
/ 20 июля 2019

в протоколе UDP нет такого состояния «соединения», однако вы можете создать свою собственную функцию, чтобы иметь список подключенных клиентов. ниже я представлю вам некоторый код, который я создал для извлечения клиентов UDP и поддержания их в списке подключенных клиентов,

Когда вы создаете сервер, вы можете ждать входящих соединений (UDP-клиенты, отправляющие сообщения «connect»), затем, когда сервер получает эти запросы, проверяют список клиентов, если этот клиент уже существует, если нет, он создает новый клиент, он назначает идентификатор и отправляет ответ клиенту с назначенным идентификатором и сообщением, что-то вроде: «1001 # подключен», после того как клиент отправляет запрос, ожидает ответа, когда ответ приходит, тогда ID извлекается и устанавливается в свойство идентификатора клиента, и выполняется socket.connect (ip, port), чтобы разрешить только запрос / ответ от / к серверу

/ ** @ TODO рассмотрим добавление переменной для указания количества клиентов * этот класс содержит соединение с главным сервером со всеми клиентами * подключено к игре, это соединение использует UDP, и оно действительно * просто, если вам нужно использовать другой вид соединения, вы свободны * создать свой собственный * @author PavulZavala * / Сервер публичного класса реализует 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 incomming 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;
}

} //

Класс клиента: как вы теперь клиент был подключен к серверу, свойство простого идентификатора должно отличаться от cero, в моей реализации все идентификаторы являются числовыми, начиная с 1001, и этот идентификатор создается только сервером, единственный пробел, который у меня сейчас есть, как сервер сейчас, если клиент все еще активен, я думаю создать другой поток, где я мог бы периодически отправлять сообщения от клиента к серверу, чтобы гарантировать, что мы все еще общаемся, если сервер не получает, например, запрос от клиента в 5 минут, сервер отключает клиента или он может игнорировать отправку широковещательных сообщений клиенту, пока он не получит новое сообщение (я сейчас работаю над этим)

Клиент публичного класса реализует 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();
}

} //

Реализация сервера, это можно сделать в основном приложении, которое будет клиентом

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

Реализация клиента:

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

Я надеюсь, что это может быть полезно для вас.

Консольные сообщения от сервера:

> Task :run
starting server
1001 Connected, response Sent

Консольные сообщения от клиента:

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