#java #udp #datagram
Вопрос:
Я создал два разных класса java, для клиента и для сервера, с методами отправки и получения в каждом. В соответствии с задачей я должен был установить соединение сервер-клиент через DatagramPacket
и соединение клиент-сервер через DatagramChannel
. Последний отлично работает, но у меня проблемы с датаграммами-они отправляются с сервера и никогда не поступают на клиент. Что случилось?
public class TransferClient implements Serializable{
private static final long serialVersionUID = 26L;
public TransferClient() {
}
public void send(Command com) throws IOException {
SocketAddress socketAddressChannel = new InetSocketAddress("localhost", 1);
DatagramChannel datagramChannel=DatagramChannel.open();
ByteBuffer bb;
datagramChannel.connect(socketAddressChannel);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(com);
oos.flush();
bb=ByteBuffer.wrap(baos.toByteArray(),0, baos.size());
datagramChannel.send(bb,socketAddressChannel);
baos.close();
oos.close();
}
public Command receive() throws IOException, ClassNotFoundException {
SocketAddress address = new InetSocketAddress(2029);
DatagramSocket s = new DatagramSocket();
DatagramPacket inputPacket = new DatagramPacket(new byte[1024],1024, address);
s.receive(inputPacket);
ByteArrayInputStream bais = new ByteArrayInputStream(inputPacket.getData());
ObjectInputStream ois = new ObjectInputStream(bais);
return (Command) ois.readObject();
}
}
public class TransferServer {
public TransferServer(){
}
public void send(Command com) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
byte[] buffer;
oos.writeObject(com);
oos.flush();
buffer=baos.toByteArray();
SocketAddress address = new InetSocketAddress("localhost",2029);
DatagramSocket s = new DatagramSocket();
DatagramPacket outputPacket = new DatagramPacket(buffer,buffer.length,address);
s.send(outputPacket);
}
public Command receive() throws IOException, ClassNotFoundException {
SocketAddress socketAddressChannel = new InetSocketAddress("localhost", 1);
DatagramChannel datagramChannel = DatagramChannel.open();
datagramChannel.bind(socketAddressChannel);
ByteBuffer bb = ByteBuffer.allocate(1024);
datagramChannel.receive(bb);
ByteArrayInputStream bais = new ByteArrayInputStream(bb.array());
ObjectInputStream ois = new ObjectInputStream(bais);
Command command;
System.out.println(ois.available());
command =(Command) ois.readObject();
datagramChannel.close();
ois.close();
bais.close();
return command;
}
}
Комментарии:
1. Порты ниже 1024 защищены. Похоже, вы используете очень низкие цифры.
2. О боже, я поменял порты, но это не помогло. Тем не менее, спасибо!
Ответ №1:
Вам необходимо указать порт, к которому вы будете привязаны DatagramSocket
, чтобы получать свои данные. В противном случае он будет привязан к первому доступному порту, найденному на вашем компьютере.
И вам не нужно SocketAddress
здесь, но вам нужно учитывать фактическую длину полученного пакета.
См.Документацию java.net. DatagramSocket
В receive()
методе вашего TransferClient
класса:
public Command receive() throws IOException, ClassNotFoundException {
DatagramSocket s = new DatagramSocket(2029); //Add your port Here
DatagramPacket inputPacket = new DatagramPacket(new byte[1024],1024);
s.receive(inputPacket);
ByteArrayInputStream bais = new ByteArrayInputStream(inputPacket.getData(), 0, packet.getLength());
ObjectInputStream ois = new ObjectInputStream(bais);
return (Command) ois.readObject();
}
Комментарии:
1. Но затем он выдает исключение BindException: Адрес уже используется: привязка. Чтобы прояснить ситуацию: сначала я отправляю данные с клиента на сервер, а затем-с сервера на клиента.
2. Обязательно не устанавливайте порт DatagramSocket в
send()
методе вашего сервера, это может быть причиной исключения.3. Я не устанавливаю его в методе отправки() сервера.
4. На самом деле я установил его в посылке. Может ли это исключение быть вызвано этим?
5. Это происходит потому, что вы открываете сокет каждый раз, когда вводите этот метод, и никогда не закрываете его. Вы должны создать сокет перед вводом метода один раз и закрыть его, когда вы полностью закончите с ним.