0

This question has been asked a lot, but so far, none of the solutions that I applied from previous answers have helped me.

Main goal

I am trying to learn UDP conexions and this is my attempt. I want to have a client ask for a picture at a server via UDP and the server will send it. Then the client will create a file with that information given.

Explanation

My main idea is to ask the server for an image using a "GET" command (not the HTTP, just GET) followed by the name of the image(extension included). Then the client awaits an answer which is the image requested.

Problems

The client waits and answer which does no come

Research

  • From another similar question it was a problem that I was using the same PORT for both receive and connect, so I added two ports, receivingPORT and sendingPORT, no results from the Client.

  • From other similar questions, It was a Firewall problem. So, on a Win10 machine, I created a new rule for UDP in the Firewall for the ports that I am using for this application, and nothing was received by the Client...

I have checked that the image is loaded into byte[] and the image is sent. But on the Client, nothing is received and stays there waiting for a connection to come through

CODE from Server

public class UDPserver { static DatagramSocket serverUDP; static DatagramPacket packet; static InetAddress address; static byte[] buffer = new byte[65507];//65507 final static int receivingPORT = 6668; final static int sendingPORT = 6669; public static void main(String[] args) throws SocketException, IOException, InterruptedException{ boolean serverActive = true; String order = ""; String file = ""; //Instantiate server serverUDP = new DatagramSocket(receivingPORT); while(serverActive){ //Kind of packet we want to receive packet = new DatagramPacket(buffer, buffer.length); System.out.println("Server awaiting connection..."); //Receive it serverUDP.receive(packet); System.out.println("Received packet from: " + packet.getAddress() + "/" + packet.getPort()); //What does the packet contain? String msg = new String(packet.getData()); address = packet.getAddress(); System.out.println("Order from: " + address + "/" + receivingPORT + " says: " + msg); try{ order = msg.split(" ")[0].trim(); file = msg.split(" ")[1].trim(); } catch (Exception e){ } switch(order){ case("GET"):{ System.out.println("Sending back an image..."); buffer = loadImageFromServer(file); packet = new DatagramPacket(buffer, buffer.length, address, sendingPORT); Thread.sleep(5000); serverUDP.send(packet); System.out.println("Client served"); break; } case("DISCONNECT"):{ buffer = "Server is disconnecting...".getBytes(); packet = new DatagramPacket(buffer, buffer.length, address, sendingPORT); serverUDP.send(packet); serverActive = false; serverUDP.close(); break; } } } } static byte[] loadImageFromServer(String path) { try { System.out.println("Loading path: " + path); //Instantiate a buffer from the image for it BufferedImage img = ImageIO.read(UDPserver.class.getResource(path)); //Create a byte[] stream object to handle the data ByteArrayOutputStream baos = new ByteArrayOutputStream(); //Write the image data into those above with jpg format ImageIO.write(img, "png", baos); //Flush the information baos.flush(); byte[] buffer = baos.toByteArray(); //Write it out on a byte string and return it return buffer; } catch (IOException ex) { Logger.getLogger(UDPserver.class.getName()).log(Level.SEVERE, null, ex.fillInStackTrace()); System.exit(-1); } return null; } } 

CODE client

public class Client { static DatagramSocket clientUDP; static InetAddress address; static DatagramPacket packetSend; static DatagramPacket packetReceive; static int SIZE = 65507; final static int receivingPORT = 6669; final static int sendingPORT = 6668; static byte[] buffer = new byte[SIZE]; static Scanner scan = new Scanner(System.in); public static void main(String[] args) throws SocketException, UnknownHostException, IOException{ boolean clientLoop = true; //Get address address = InetAddress.getByName("localhost"); //Instantiate Client -> UDP clientUDP = new DatagramSocket(); while(clientLoop){ System.out.print("Enter any key and press enter"); scan.next(); //Just to stop the loop //Load the buffer buffer = "GET imagenServidor.png".getBytes(); //buffer = "DISCONNECT".getBytes(); System.out.println("Buffer is ready"); //Arm the packet packetSend = new DatagramPacket(buffer, buffer.length, address, sendingPORT); System.out.println("Packet is armed!"); //Send the packet to the server clientUDP.send(packetSend); System.out.println("Order sent to server"); System.out.println("Waiting an answer"); packetReceive = new DatagramPacket(buffer, buffer.length, address, receivingPORT); clientUDP.receive(packetReceive); System.out.println("Server answered!"); ByteArrayInputStream bais = new ByteArrayInputStream(packetReceive.getData()); BufferedImage image = ImageIO.read(bais); System.out.println(image); } clientUDP.close(); } } 

NOTES

  • This is a UDP exercise
4
  • 1
    1. There is no such thing as a UDP connection. 2. There is no problem using the same port for send and receive, and you should not waste ports in this way. 3. You need ew ByteArrayInputStream(packetReceive.getData(), 0, packetReceive.getLength()); 4. Most importantly, you are probably failing to send the datagram of 65507 bytes. You can't send a datagram larger than your socket send buffer, for a start, and in any case this is in practice far too large for UDP, and also too small for most images. Basically you can't do this. Use TCP. Commented May 21, 2020 at 0:13
  • I know TCP would solve my issues perfectly, but it's homework I must understand. I am going to try apply your points. Thank you Commented May 21, 2020 at 6:55
  • 3
    Because you must use UDP for your exercise, you need to create an application-layer protocol that will handle converting a stream into individual messages that are much smaller than the data stream. UDP works best if you use data sizes of around 576 bytes. Real-time protocols, e.g. VoIP, use much smaller (20 bytes or so) for the data size on UDP because UDP is connectionless and packets will be lost. You need to take that into account and your protocol must re-request data lost in transit. Commented May 21, 2020 at 13:21
  • Good comment @RonMaupin. This would be a nice addition to polish the assigment, although for now I am just learning the basics. I've got a solution which I am going to post afterwards one I handle a problem with Netbeans path to files... Commented May 21, 2020 at 14:09

2 Answers 2

1

The Reason

MTU!

You send packets with long buffers through UDP directly, which may not work in most network circumstances.

A packet sent through UDP should not be longer than the network MTU. Otherwise, it would be dropped. The network MTU may not be more than 1500 on most net nods(routers/switches/hosts...) and even smaller sometimes. Though some nodes may do segmentation for IP packets, you should not count on it when you are using UDP.

Suggestions

Use TCP instead in this application as for:

  • You are sending data expected to be complete (otherwise, it would be useless).

  • You do not care about congestion control algorithms.

So go with TCP.

Edit Based on The Update of The Question

So, as this is an exercise, in which you have to use UDP only.

As a file might be useless unless it is complete, you have to make sure:

  • All packets are possible to pass the path. This means the network should be physically and virtually connected, and the packet size should always be smaller than the MTU.
  • If any packets are lost, both the receiver and the sender should be able to know.
  • If any packets come out of order, the receiver should be able to know.
  • The sender should be able to cache and resend the packets not yet confirmed by the receiver.

Make sure you have a good network connection. Split the image buffer into a buffer array with each buffer item length less than 1000 bytes (should be safe).

Then let's design an amature but simple protocol for this:

 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | type | sequence number | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | payload ... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

For types, we may need:

  • hello: 0x01
  • bye: 0x02
  • ack: 0x03
  • nack: 0x04
  • data: 0x05
  • feedback: 0x06
  • ...

The sequence should be mono-increasing. e.g. 1, 2, 3, 4.... (It is not necessary to start from 1, but OK.)

It works like the following:

Sender->Receiver: hello(seq=i) Receiver->Sender: ack(seq=i) # Sender->Receiver: hello(seq=i) # if timeout and got no ack for seq=i Sender->Receiver: data(seq=i+1) Receiver->Sender: ack(seq=i+1) # Sender->Receiver: hello(seq=i+1) # if timeout and got no ack for seq=i+1 Sender->Receiver: data(seq=i+2) Sender->Receiver: data(seq=i+3) Receiver->Sender: ack(seq=i+2) Receiver->Sender: ack(seq=i+3) # Sender->Receiver: hello(seq=i+2) # if timeout and got no ack for seq=i+2 or got nack for seq=i+2 Sender->Receiver: bye(seq=n) Receiver->Sender: ack(seq=n) # bye is not necessary 
Sign up to request clarification or add additional context in comments.

2 Comments

This is a UDP exercise. I know TCP is the correct way. I will add a note about it. Thanks
@WhiteGlove Updated for the UDP solution
1

Firstly, I think you need to learn how to use wirshark or tcmpdump to analysis network streams when debugging, that will help you find out the problem and solve it.

As for your program, there are several problems the user207421 has mensioned. I think it's better to use TCP, but if you want to learn UDP by this way, the thing you need is to do a slim reliable UDP by yourself.

For example, you may need the following models

  • Build a send buffer and recive buffer, check every time if the buffer is empty, if not, send/receive and process it.(Cause UDP has MTU)

  • Add some extra format of information in the head of each datagram, which includes the size of the whole message, the sequence of the datagram, the left size, etc.(Cause you need to cut your message into many parts)

  • Build a controller, which need to have some function like retransmission, rebuild the message, etc.(Cause UDP is unreliable, you need to check the completeness of all parts)

Hope that can help you.

3 Comments

I will work that head info today. The assigment just wants the basics but I like to give the teacher a good application. Thanks a lot for pointing out
Hope you can do a good job! And I suggest you learn some basic knowledge first, like the udp socket patterns, and the basic TCP design thought like the GBN and FEC is also really good but not used in TCP. For a long term learning, you may find QUIC, libutp, KCP or some other open source projects really helpful.
And what's more, the suggestions I give you are how to realise the example you write correctly, you need to do these if you really want to use UDP..

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.