Transferring Large Data with UDP protocol - java

I know TCP is better to send file but I have a homework about sending file via udp protocol . Is there any code example in C# or Java about sending file?
I have server-client example to send and recieve message. I tried to send the file using the same way but could not succeed. I may need an algorithm to divide the file small parts and send them via datagram, and I have an idea to put "md5" of the part as header of the array to check if the packet is lost or not.
Here is my try , my server side in java;
// 1. creating a server socket, parameter is local port number
sock = new DatagramSocket(7777);
// buffer to receive incoming data
byte[] buffer = new byte[65536];
DatagramPacket incoming = new DatagramPacket(buffer, buffer.length);
byte []bigByteArray=new byte[1024*1024*1024*1024];
// 2. Wait for an incoming data
echo("Server socket created. Waiting for incoming data...");
ByteBuffer target = ByteBuffer.wrap(bigByteArray);
// communication loop
while(true)
{
try
{
sock.receive(incoming);
String s = new String(incoming.getData());
if(s=="finish") break;
target.put(incoming.getData());
}
catch(Exception e)
{
}
}
fos.write(bigByteArray);
fos.close();echo("RECIEVED");
and my client side;
String s;
Path path=Paths.get("C:\\Users\\Toshiba\\Desktop\\aa.txt");
byte[] data = Files.readAllBytes(path);
try
{
sock = new DatagramSocket();
InetAddress host = InetAddress.getByName("localhost");
//take input and send the packet
byte [] part;
for (int i = -1; i < data.length; i=i+100)
{
if(sock.isConnected())
{
part=Arrays.copyOfRange(data,i+1,i+100 );
}
else i=i-100;
}
byte [] f="finish".getBytes();
DatagramPacket finalpac = new DatagramPacket(f ,f.length , host , port);
sock.send(finalpac);
}
Thank you in advance.

Several issues:
The following isn't correct:
sock.receive(incoming);
String s = new String(incoming.getData());
The final line should be
String s = new String(incoming.getData(), incoming.getOffset(), incoming.getLength());
and if you aren't receiving text you shouldn't be converting the data to a String at all.
Remove the sock.isConnected() test. DatagramSockets are not usually connected, and you certainly haven't connected this one.
The loop in which this is embedded does nothing useful. You are only sending the word "finish".

Related

UDP client does not receive bytes

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
The Reason
MTU!
You are sending packets with long buffe 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/switchs/hosts...), and even smaller sometimes. Though some nods may do sigmentation for ip packets, but you should not count on it when you are using UDP.
Suggestions
Use TCP instead in this application, as for:
You are sending data which expected to be complete (otherwise it would be useless).
You do not care about congestion control algorithms.
So just go with TCP.
Edit Based on The Update of The Question
So, as this is an excercise, 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. Which means network should be connected both physically and virtually, and 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 apckets come out of order, the receiver should be able to know.
Sender should be able to cache and resend the packets which are not confirmed by the receiver yet.
Make sure your have a good network connection. Split the image buffer into buffer array with each buffer item length less than 1000bytes(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
...
Sequence should be mono-increasing. e.g. 1, 2, 3, 4.... (Not necessory to start from 1 but OK)
It works like 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 necessory
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.

Java Socket receives Keep Alive on communication with RCON game server

I am currently implementing a game server manager for the RCON server protocol. I'm opening a connection to the server via a socket:
this.socket = new Socket();
this.socket.connect(new InetSocketAddress(this.getAddress(), this.getPort()), 3000);
The connection works fine, I can communicate with the server and receive the responses. No problem there. My problem is that when I am debugging the communication process and i take to long getting from the request to the read on the input stream, I am getting a message "Keep Alive". This is the code for request and response:
send:
Rcon rcon = new Rcon();
byte[] data = rcon.constructPackage(this.getPort(), pRequestType, pPayload);
OutputStream out = this.socket.getOutputStream();
out.write(data);
out.flush();
receive:
InputStream in = this.socket.getInputStream();
byte[] header = new byte[3*4];
in.read(header);
ByteBuffer buffer = ByteBuffer.wrap(header);
buffer.order(ByteOrder.LITTLE_ENDIAN);
int length = buffer.getInt();
int id = buffer.getInt();
int type = buffer.getInt();
int payloadLength = length - (2*4) - 2;
byte[] payload = new byte[payloadLength];
DataInputStream dis = new DataInputStream(in);
dis.readFully(payload);
dis.read(new byte[2]);
payloadString = new String(payload);
I have searched for this as Java and RCON related but I did not find a single clue where this is coming from. I'm guessing this is an RCON related effect, since I have to interpret the package which is received from the RCON server and split its contents to get to the actual payload. After this is done, the payload string contains "Keep Alive".

android studio byte[] for UDP is redudant

I just want to send data to another device (PC) using UDP by clicking on a button. So I made a method for it in which I put the UDP code and made a relation when button is clicked. But according to the IDE, the byte which contains the String data I want to send is not well created.
Here's the code:
String argv = "WhatISend";
int port = 9268;
byte[] buffer= new byte[argv.lenght()];
try {
InetAddress server = InetAddress.getByName("172.16.19.14");
buffer = argv.getBytes();
DatagramSocket socket = new DatagramSocket();
DatagramPacket udp_emission = new DatagramPacket(buffer, buffer.length, server, port);
socket.send(udp_emission);
socket.close();
} catch (Exception e) {
System.out.println("Fail socket");
}
the problem is on "byte[] buffer= new byte[size];"
Based on the wording of your question, it sounds like you want buffer to contain the characters of the original string. However, the byte array actually does not contain the string data. The code you have shown us just creates a byte array that has the same length as the input string. You have not assigned the individual characters over to the buffer.
What you probably want is this:
buffer = argv.getBytes();
For more information, see String.getBytes().

Socket giving incorrect response [duplicate]

I want to connect Android Device to external device via Socket. Socket Connect to external device successfully.
Now if any data require from external device then send request of byte packet data to socket below order. if external device receive data correct then send byte data in response.
Parameters : methodname(1 byte), payloadlength(2 byte), payload(2 byte).
Now My Code is...
Socket socket = new Socket("local exteranl device ip", 5000);
if(socket.isConnected()) {
int methodname = 5;
int payload = 2151;
int payloadLength = 2;
ByteBuffer buffer = ByteBuffer.allocate(3 + payloadLength); // 3 = for method name + length
buffer.order(ByteOrder.BIG_ENDIAN); // Just to be explicit
buffer.put((byte) methodname);
buffer.putShort((short) payloadLength);
buffer.putShort((short) payload);
buffer.rewind();
byte[] result = new byte[buffer.capacity()]; // Could also use result = buffer.array();
buffer.get(result);
DataOutputStream classOUTstream = new DataOutputStream(socket.getOutputStream());
// socket is already connected
classOUTstream.write(result);
classOUTstream.flush();
InputStream stream = socket.getInputStream();
byte[] data = new byte[100];
int count = stream.read(data);
}
Above Code is Android, i knowing only basic concept of java. i am getting -1 result in count.
can any one please suggest me or tell me my mistake?
You're doing this the hard way. Get rid of the ByteBuffer altogether and use all the methods of DataOutputStream. They are all big-endian. I can't see any mistake but clearly you must be sending something the peer didn't understand so he is closing the connection instead of sending a reply.
Note: Socket.isConnected() cannot possibly be false at the point you're testing it.

Use datagrams in java to send video/audio from client to server?

Hey everyone, I'm having a bit of a problem with UDP and Datagrams. I'm supposed to make a server that will get a request from the client to send a file in the same directory. The UDP Server will then get this file (a video), put it into a datagram and send it. I think I know how to do it, but I can't put the file in the datagram. I'm putting it in Binary form, so keep that in mind.
Here's my code so far:
edit: This is the server by the way, and I keep having trouble with BufferedInputReader and OutputReader, so keep that in mind :)
Scanner inFromUser = new Scanner(System.in);
int port = 12345;
DatagramSocket server = new DatagramSocket(port);
// Read name of file supplied by client (must be a line of text):
Scanner in = new Scanner(new DataInputStream(server.getInputStream()));
String filename = in.nextLine();
DatagramSocket request = server.accept();
// Create buffer, then we're ready to go:
// Puts file into binary form
BufferedInputStream inbinary =
new BufferedInputStream(new FileInputStream("poop.txt"));
// Outputs the binary form
BufferedOutputStream outbinary =
new BufferedOutputStream(request.getOutputStream());
int numbytes;
int countblocks = 0;
int countbytes = 0;
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length, port);
server.receive(packet);
while ((numbytes = inbinary.read(buf,0,1024)) >= 0)
{
// receive packet from client, telling it to send the video file
server.receive(packet);
InetAddress address = packet.getAddress();
packet = new DatagramPacket(buf, buf.length, address, port);
server.send(packet);
countblocks++; // keep statistics on file size
countbytes += numbytes;
outbinary.write(buf,0,numbytes); // write buffer to socket
}
outbinary.flush(); // FLUSH THE BUFFER
server.close(); // done with the socket
System.out.println(countblocks + " were read; " + countbytes + " bytes");
}
}
I haven't done datagrams in a while, but I'm pretty sure the accept() call is wrong. That's for TCP servers.
I'd recommend cribbing from Sun's excellent tutorial: http://java.sun.com/docs/books/tutorial/networking/datagrams/clientServer.html

Categories

Resources