отправка и получение дейтаграммы сокета

#java #sockets #datagram

#java #сокеты #дейтаграмма

Вопрос:

Я делаю дейтаграмму сокета сервера и клиента.

Клиент подключается к серверу, и вам нужно записать в клиенте строку, содержащую Hello или hello.

Когда сервер обнаруживает строку с hello или Hello, он отправляет клиенту другую строку.

Проблема в том, что клиент не читает строку, которую отправляет сервер.

Вот мой код.

 
Client
public class Client {

    public static void main(String[] args) {
        try {
            System.out.println("Creando socket datagram");
            DatagramSocket datagramSocket = new DatagramSocket();

            Scanner myObj = new Scanner(System.in);  // Create a Scanner object
            System.out.println("Say Hello");
            String saludo = myObj.nextLine();

            System.out.println("Sending message");
            InetAddress addr = InetAddress.getByName("localhost");
            DatagramPacket datagrama = new DatagramPacket(saludo.getBytes(), saludo.getBytes().length, addr, 5555);
            datagramSocket.send(datagrama);
            System.out.println("Message sent");

            System.out.println("Reading message");
            byte[] mensaje = new byte[25];
            DatagramPacket datagrama1 = new DatagramPacket(mensaje, 25);
            datagramSocket.receive(datagrama1);

            System.out.println("Message recieved: "   new String(mensaje));

            System.out.println("Closing");

            datagramSocket.close();
            System.out.println("FInished");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 

Сервер

 public class Server {

    public static void main(String[] args) throws InterruptedException {
        try {

            for (;;) {
                System.out.println("Creating socket datagram");
                InetSocketAddress addr = new InetSocketAddress("localhost", 5555);
                DatagramSocket datagramSocket = new DatagramSocket(addr);

                System.out.println("RReading message");
                byte[] mensaje = new byte[25];
                DatagramPacket datagrama1 = new DatagramPacket(mensaje, 25);
                datagramSocket.receive(datagrama1);

                System.out.println("Message recieved: "   new String(mensaje));

                if (new String(mensaje).contains("hello") || new String(mensaje).contains("Hello")) {

                    String quetal = "¿Hello, how are you doing?";
                    System.out.println("Sending message");

                    TimeUnit.SECONDS.sleep(2);

                    DatagramPacket datagrama2 = new DatagramPacket(quetal.getBytes(), quetal.getBytes().length, addr.getAddress(),
                             5555);
                    datagramSocket.send(datagrama2);
                    System.out.println("Message Sent");

                }

                datagramSocket.close();

            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 

Я попытался перевести сервер в режим ожидания на случай, если сервер отправит строку до того, как клиент попытается прочитать.

Большое спасибо за помощь, как всегда.

Ответ №1:

Клиент использует DatagramSocket() конструктор без параметров для привязки к случайному порту, с помощью которого можно отправлять и получать на:

Создает сокет дейтаграммы и привязывает его к любому доступному порту на локальном хост-компьютере. Сокет будет привязан к подстановочному адресу, IP-адресу, выбранному ядром.

Однако, когда сервер получает дейтаграмму, вы игнорируете IP и порт, с которого фактически была отправлена дейтаграмма:

DatagramSocket.receive(DatagramPacket)

Получает пакет дейтаграммы из этого сокета. Когда этот метод возвращается, DatagramPacket буфер заполняется полученными данными. Пакет дейтаграммы также содержит IP-адрес отправителя и номер порта на компьютере отправителя.

Когда сервер отправляет ответ, вы отправляете его обратно на сам сервер localhost:5555 , а не клиенту вообще.

На стороне сервера вам необходимо изменить это:

 DatagramPacket datagrama2 = new DatagramPacket(..., addr.getAddress(), 5555);
 

Либо для этого:

 DatagramPacket datagrama2 = new DatagramPacket(..., datagrama1.getAddress(), datagrama1.getPort());
 

Или к этому:

 DatagramPacket datagrama2 = new DatagramPacket(..., datagrama1.getSocketAddress());
 

Кроме того, ваш сервер также игнорирует фактическую длину данных, отправляемых клиентом. Сервер получает данные, используя 25-байтовый массив, но клиент может фактически не отправлять 25 байт. Если клиент отправляет менее 25 байт, вы получите a String , который содержит случайный мусор в конце. И если клиент отправляет более 25 байт, `receive() усечет данные.

Вместо этого попробуйте что-то более похожее:

 System.out.println("Reading message");

byte[] buffer = new byte[65535];
DatagramPacket datagrama1 = new DatagramPacket(buffer, buffer.length);
datagramSocket.receive(datagrama1);

String mensaje = new String(datagrama1.getData(), datagrama1.getLength());

System.out.println("Message recieved: "   mensaje);

if (mensaje.contains("hello") || mensaje.contains("Hello")) {
    ...
}
 

Ответ №2:

Это было весело 🙂

Пожалуйста, имейте в виду, что способ кодирования может быть не самым лучшим, однако он работает так, как вы хотите.

Клиент отправляет привет, сервер получает привет и отправляет (привет вам).

Затем оба завершаются. Он не продолжает повторять эти 2 сообщения вечно, но я показал вам идею.

Сервер также должен действовать как клиент, чтобы отправлять сообщения.

 import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class DReceiver{

    
    public static void replyToTheClientListening() throws IOException {
        
        DatagramSocket ds = new DatagramSocket();

        String str = "hello back at you";
        
        InetAddress ia = InetAddress.getByName("127.0.0.1");
        
        DatagramPacket dp = new DatagramPacket(str.getBytes(), str.length(), ia, 3001);
        
        ds.send(dp);
        ds.close();
    }
    
    public static void listenToMessagesFromTheClient() throws IOException {
        
        DatagramSocket ds = new DatagramSocket(3000);
        ds.setSoTimeout(60000); //Wait 60 SECONDS for messages
        
        byte[] buf = new byte[1024];
        
        DatagramPacket dp = new DatagramPacket(buf, 1024);
        ds.receive(dp);
        
        String strRecv = new String(dp.getData(), 0, dp.getLength());

        if("hello".equalsIgnoreCase(strRecv)) { //hello in any case
            
            System.out.println("Received a MSG from the Client "   strRecv);
            
            replyToTheClientListening();
        }
        ds.close();
    }
    
    public static void main(String[] args) throws Exception {
   
        listenToMessagesFromTheClient();

  }
}
 

DSender является клиентом, но также должен действовать как сервер (для прослушивания сообщений, поступающих с другого сервера)

 import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class DSender{
  
    
    public static void actAsAServerAndListenToMessages() throws IOException {
        
        //Listen to Port 3001 --The Server will send to that port
        DatagramSocket dsReceive = new DatagramSocket(3001);
        
        dsReceive.setSoTimeout(60000); //Make it wait 60 SECONDS
        
        byte[] buf = new byte[1024];
        
        DatagramPacket dpReceive = new DatagramPacket(buf, 1024);
        dsReceive.receive(dpReceive);
        
        String strRecv = new String(dpReceive.getData(), 0, dpReceive.getLength());
        
        System.out.println("Client -- Received a Msg back from Server --"   strRecv);
        
        dsReceive.close();
        
    }
    
    public static void sendAMessageAsAClientToTheServer() throws IOException {
        
        // Client will send a message to Port 3000 which the Server listens to.
        DatagramSocket ds = new DatagramSocket();
        
        String str = "hello";
        
        InetAddress ia = InetAddress.getByName("127.0.0.1");
        
        DatagramPacket dp = new DatagramPacket(str.getBytes(), str.length(), ia, 3000);
        
        ds.send(dp);
        
        ds.close();
        
    }
    public static void main(String[] args) throws Exception {

        sendAMessageAsAClientToTheServer();
    
        actAsAServerAndListenToMessages();
    
  }
}
 

Ссылка :
https://www.javatpoint.com/DatagramSocket-and-DatagramPacket

Я запускаю сервер, затем клиент.

введите описание изображения здесь

Комментарии:

1. Большое спасибо за ваш ответ! Я протестировал его, и он отлично работает! Я добавил сканер, чтобы пользователь мог вводить строку. Большое спасибо!

2. Рад, что помог 🙂