Image Transfer with UDP on Android - java

I want to send an image through UDP on localhost Android but I don't know how to combine the image's packets. I read a jpeg file and send it to client side. I want to create this jpeg file on server side. What should I do? This my code but I have a permission denied error:
Client Side:
InetAddress serverAddr = InetAddress.getByName(Server.SERVERIP);
FileInputStream fin = new FileInputStream("/sdcard/send.jpg");
BufferedInputStream input = new BufferedInputStream(fin);
Log.d("UDP", "C: Connecting...");
et.append("C: Connecting...\n");
/* Create new UDP-Socket */
DatagramSocket socket = new DatagramSocket();
byte[] sendData = new byte[Server.BUF_SIZE];
byte[] buf = new byte[Server.BUF_SIZE];
String sentence;
int bytesRead = 0;
while((bytesRead = input.read(buf, 0, Server.BUF_SIZE)) != -1) {
sentence = new String(buf, 0, bytesRead);
sendData = sentence.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length,
serverAddr, Server.SERVERPORT);
socket.send(sendPacket);
Server Side:
File f = new File("/sdcard/out.jpg");
f.createNewFile();
FileOutputStream fos = new FileOutputStream(f);
BufferedOutputStream out = new BufferedOutputStream(fos);
InetAddress serverAddr = InetAddress.getByName(SERVERIP);
byte[] receiveData = new byte[BUF_SIZE];
String sentence;
Log.d("UDP", "S: Connecting...");
et.append("S: Connecting...\n");
DatagramSocket socket = new DatagramSocket(SERVERPORT, serverAddr);
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
socket.receive(receivePacket);
byte[] buf = new byte[Server.BUF_SIZE];
sentence = new String(receivePacket.getData());
et.append(sentence);
buf= sentence.getBytes();
out.write( buf,0, Server.BUF_SIZE );

If you're going to use UDP, you have to implement any features UDP doesn't provide that you need. Unfortunately, in this case UDP doesn't provide a long list of features that you need. There's simply no possible way this code can work.
You need, but don't provide:
1) Transmit pacing: Your code just sends data as fast as it can with no consideration for the capabilities of the network between the devices.
2) Packet ordering: Your code does not identify the packets with any kind of sequence number. If they are received out of order, the data cannot be recovered.
3) Retransmissions: If a packet is lost in transit, the data is just lost. There is no way the receiver can detect this and request a retransmission.
4) Connections: Your receiver has no way to know when the transmitter is going to start sending, when it should start receiving, when it is done receiving, and so on.
5) MTU detection: Unless you really don't care at all about performance, you want to detect the path MTU. Send datagrams that are larger than the path MTU and packet loss goes up exponentially. Send datagrams that are smaller than the path MTU and efficiency goes down.
6) Link sharing: Unless you have a link all to yourself, you need to work out a backoff and run up algorithm. Back off too much and your throughput will drop drastically when other connections use the same link. Ramp up too aggressively and you'll cause packet loss and traffic jams when you have to share a link with other traffic.
If you want to, you can implement all of these things in your own code. But TCP already has them all, and TCP has been designed, implemented, and refined by the finest minds on the planet. So it's very unlikely you would do a better job.

Related

Transferring Large Data with UDP protocol

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".

Send long over UDP multicast

I'm trying to send a long over a multicast.
The connection should work, because it's possible to send a String.
This is my serverside code:
currentServerStatusId = Server.getServerStatusVersionId();
buf = ByteBuffer.allocate(8).putLong(currentServerStatusId).array(); //long should be 8 bytes in Java
InetAddress group = InetAddress.getByName(multicastAddress);
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, port);
socket.send(packet);
and this is on the client side (the receiver):
byte[] buf = new byte[256];
serverIpPacket = new DatagramPacket(buf, buf.length);
System.out.println("waiting to receive");
multicastSocket.receive(serverIpPacket);
receivedIp = serverIpPacket.getAddress().getHostAddress();
currentServerStatusId = ByteBuffer.allocate(8).put(serverIpPacket.getData()).getLong();
//new String(serverIpPacket.getData(), 0, serverIpPacket.getLength());
System.out.println("received current ServerStatusId: " + currentServerStatusId);
This gives me a BufferUnderflowException.
Apparently it does work when I double the size from 8 to 16 in the allocate method on the receiver/client side.
But then it returns 0 instead of my testing value (something like 68763)
Okay, sorry, for the trouble but I just found the answer myself:
I have to put this in the client side:
ByteBuffer buffer = ByteBuffer.wrap(serverIpPacket.getData());
currentServerStatusId = buffer.getLong();
that's all

Broadcast server discovery

I'm creating a game in Java that simulates the classic 5 cards Poker with 2 to 4 players.
Most of the data will be processed by a server, but since I can't use an online server, my idea is to allow a user to host a game by creating a local one.
Now, I don't want to force the use of IPs to connect to a game, so I created a "discovery" interface within the user can see all avaible games. This is done using the UDP protocol and a broadcast research on a common group:
(code is simplified to show only the actions that are executed, may not work as it is showed here)
Client
MulticastSocket socket = new MulticastSocket(6020);
InetAddress group = InetAddress.getByName("226.0.0.1");
socket.joinGroup(group);
DatagramPacket packet = new DatagramPacket(new byte[] {(byte) 0xF0}, 1, group, 6020);
socket.send(packet);
while(true) {
buf = new byte[1];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
if(packet.getData()[0] == 15) {
Socket client = new Socket(packet.getAddress(), 6020);
}
}
Server
MulticastSocket socket = new MulticastSocket(6020);
InetAddress group = InetAddress.getByName("226.0.0.1");
socket.joinGroup(group);
// new thread listening on port 6020 TCP
ServerSocket server = new ServerSocket(6020);
new Thread(new Runnable() {
public void run() {
while(true) {
// new thread communicating with client and back listening on port 6020
new ServerThread(server.accept());
}
}
}).start();
// listening on port 6020 UDP
byte[] buf;
DatagramPacket packet;
while(true) {
buf = new byte[1];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
if(packet.getData()[0] == -16) {
DatagramPacket packet = new DatagramPacket(new byte[] {(byte) 0x0F}, 1, packet.getSocketAddress());
socket.send(packet);
}
}
The client sends an UDP broadcast packet on the port 6020. When a server receive this packet if it's composed by a byte 0xF0, he sends back a byte 0x0F to the client. Every client is also listening on the port 6020 and when receive a packet composed by a byte 0x0F it starts a new connection TCP to the server on the port 6020.
My question: is there a better way to achieve this "discovery" system?
I know this is going to work only in local networks, is it possible to extend the discovery "outside" using a local server?
Unless you want to set up some sort of known broker that can connect players with servers (or give them a listing of servers), you may be out of luck. As you discovered, multicast and broadcast is generally not sent to the WAN by most switches (and definitely cannot traverse the Internet).
If your issue with setting up a known server/broker is that you have a home connection and so a dynamic ip, I would recommend looking into dynamic DNS. There are a number of providers out there that will allow you to set up a sub-domain on their system that is automatically changed to point to your IP as your IP changes.

Problems with UDP Received and Sent UDP Packages?

I am trying to write a simple program about UDP Connections to learn about them. I have implemented some basic things but when I try to send and get back what I sent but I face some problems like,
When I do this ;
send a string
"asd" to server I get back asdxxxxxxxxxx
and when I try to print What I get in the server I get [B#5f186fab
How can I solve this problem ?
To be more clear I am sending you a few lines of code ,
In client;
Scanner in = new Scanner(System.in);
String result = in.nextLine();
// send request
byte[] buf = new byte[1000];
String read = result;
InetAddress address = InetAddress.getByName("localhost");
DatagramPacket packet = new DatagramPacket(result.getBytes(), result.getBytes().length, address, 4445);
socket.send(packet);
// get response
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
// display response
String received = new String(packet.getData(), 0, packet.getLength());
System.out.println("Quote of the Moment: " + received);
In server ;
byte[] buf = new byte[1000];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
byte[] received = packet.getData();
System.out.println(received.toString());
// figure out response
// send the response to the client at "address" and "port"
InetAddress address = packet.getAddress();
int port = packet.getPort();
packet = new DatagramPacket(received, received.length, address, port);
socket.send(packet);
Thank you all
EDIT 1 I think I have problems with my buffer but I dont know how to solve .
You can use
System.out.println(Arrays.toString(received));
but what you probably want is
System.out.println(new String(received, o, lengthRead, "UTF-8"));
Have you fixed this?
Otherwise, what I've found is that if you declare a receiving byte[] buf with a capacity that's greater than the length string you're actually receiving, you'll end up with the rest of the buffer full of unwanted bytes.
Eg. if you declare byte[] received = new byte[1000]; but only receive a string of 4 bytes, you'll end up with 996 unwanted bytes.
One quick way around this is to do something like
byte[] received = packet.getData();
System.out.println(received.toString().trim());
trim() did the trick for me. Hope that helps you!

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