#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. Рад, что помог 🙂