i have made a video conferencing application in java. It is based on UDP as it should be. It works well on LAN. Now I am switching it to WAN. After a lot of reading about problems in UDP transmission behind NAT (as there will be users behind different routers). I tried to implement hole punching as read. But its not working. I am using a client-server-client architecture. More precisely, every client sends its images(or frames) to server, which then forwards them to other clients. For this i am using the client's IP and port assigned to them by the router. The server then sends the packets to clients. But the packets are still blocked by the router. Can anyone tell me what should be a reliable solution to this? Or there is any library to achieve hole punching efficiently?
==================================================================================
client code:
//some code
final Socket client = new Socket(IPaddr, port); // tcp connection
...
// code for some gui components...
...
String message2="video";
clientSocketReceiver = new DatagramSocket();
String ip = "x.x.x.x";
InetAddress IPAddress = InetAddress.getByName(ip);
ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
baos1.write(message2.getBytes());
baos1.write('\n');
baos1.flush();
byte[] message2InByte = baos1.toByteArray();
baos1.close();
clientSocketReceiver.send(new DatagramPacket(message2InByte, message2InByte.length, IPAddress, 8876));
...
//some code....
...
//thread for receiving images..
while (true) {
byte[] receiveData = new byte[50000];
DatagramPacket receivePacket = new DatagramPacket(receiveData,receiveData.length);
clientSocketReceiver.receive(receivePacket);
InputStream in = new ByteArrayInputStream(receivePacket.getData());
buffImage = ImageIO.read(in);
...
//code for displaying images on GUI
...
}
//==========================================================================
=========================================================================== =
server code:
//code for storing client's ip and port. runs only when a new client is accepted by tcp socket....
serverSocket=new DatagramSocket(8876); //declared at starting of code
while (checked==false ) {
DatagramPacket receivePacket = new DatagramPacket(receiveData,receiveData.length);
serverSocket.receive(receivePacket);
String data = new String(receivePacket.getData());
data = data.trim();
if (data.equals("video")) {
vx.add(receivePacket.getAddress().getHostAddress()); // storing ip
String tmp = "" + receivePacket.getPort();
vv.add(tmp); //storing port. vv and vx r vectors
checked=true;
}
}
======================================
//thread for receiving/sending images from/to clients
DatagramSocket serverSocket2 = new DatagramSocket(9876);
byte[] receiveData = new byte[50000];
while (true) {
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket2.receive(receivePacket);
InputStream in = new ByteArrayInputStream(receivePacket.getData());
bImage = ImageIO.read(in);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bImaget, "jpg", baos);
baos.flush();
byte[] imageInByte = baos.toByteArray();
baos.close();
for (int i = 0; i < vx.size() && i < vv.size(); i++) {
serverSocket2.send(new DatagramPacket(imageInByte, imageInByte.length, InetAddress.getByName(vx.elementAt(i).toString()), Integer.parseInt(vv.elementAt(i).toString())));
}
}
=============================================
Related
I need to send and receive in multicast.
This is my Sender:
public static void main(String[] args) {
MulticastSocket socket = null;
try {
socket = new MulticastSocket(3575);
int n = 1;
while (n <= 100) {
byte[] buf = new byte[256];
// non aspetta la richiesta
String dString = new Date().toString();
buf = dString.getBytes();
// invia il messaggio in broadcast
InetAddress group = InetAddress.getByName("230.0.0.1");
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, 3575);
socket.send(packet);
System.out.println ("Broadcasting: "+dString);
Thread.sleep(1000);
n++;
}
socket.close();
}catch(Exception e) { e.printStackTrace(); socket.close();}
}//main
This is my Receiver:
public static void main(String[] args) throws IOException {
MulticastSocket socket = new MulticastSocket(3575);
InetAddress group = InetAddress.getByName("230.0.0.1");
socket.joinGroup(group);
DatagramPacket packet;
for (int i = 0; i < 100; i++) {
byte[] buf = new byte[256];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String received = new String(packet.getData()).trim();
System.out.println("Time: " + received);
}
socket.leaveGroup(group);
socket.close();
}//main
When I run them, the Receiver does not receive anything.
I tried on two different PC ( both with Windows) with AntiVirus and firewall disabled. I also tried with different LAN: my router, my phone hotspot.
It does not work neither on local machine.
How can I solve the problem?
Thanks
I compiled and ran your code on my laptop, with the sender and receiver on the same machine. It works. (Fedora 26 Linux, Java 1.8.0_171)
It seems that the problem is something to do with your networking, not the application code. So, since this not a programming problem, I think you would be better off asking this Question on the ServerFault site ... where they specialize in networking, etcetera.
Im trying to Send out a DatagramPacket on a MulticastSocket. This bit is working but when i try and get the info out of the header its not working.
while(true){
byte[] packet = new byte[1500];
DatagramPacket packetR = new DatagramPacket(packet, packet.length);
socketM.receive(packetR);
ByteBuffer data = ByteBuffer.wrap(packetR.getData());
byte[] senderAddress = new byte[100];
byte[] senderCommand =new byte[100];
data.get(senderAddress,0,4);
InetAddress senderIP = InetAddress.getByAddress(senderAddress);
data.position(4);
data.get(senderCommand,0,1);
String command = (char)senderCommand[0]+"";
System.out.print(senderIP+": "+ command+"\n");
}
This works but i just get all of it printed out
while(true){
byte[] packet = new byte[100];
DatagramPacket packetR = new DatagramPacket(packet, packet.length);
socketM.receive(packetR);
InetAddress ip = packetR.getAddress();
String meg = new String(packetR.getData());
System.out.print(ip+": "+ meg+"\n");
}
Can anyone see why this would not work thanks.
The fourth byte of data is given by packet.getData()[3].
If that doesn't answer as clarified in your comments you will have to clarify further.
I am trying to send DatagramPackets (UDP) in my Android application:
//create a byte to receive data
mClientSocket = new DatagramSocket();
byte[] receiveData = new byte[MAX_RECEIVE_DATA_SIZE_BYTES];
DatagramPacket receivePacket = new DatagramPacket(receiveData,
receiveData.length);
// Set a receive timeout
mClientSocket.setSoTimeout(timeout);
// receive the packet
mClientSocket.receive(receivePacket);
return new String(receivePacket.getData(), 0,
receivePacket.getLength());
I get the following error:
Try again
Am I missing something here?
Well to send the UDP you'd need something similar to:
Server:
String messageStr="Hello Android!";
int server_port = 12345;
DatagramSocket s = new DatagramSocket ();
InetAddress local = InetAddress .getByName("192.168.1.102");
int msg_length=messageStr.length();
byte[] message = messageStr.getBytes();
DatagramPacket p = new DatagramPacket (message, msg_length,local,server_port);
s.send(p);
Client:
String text;
int server_port = 12345;
byte[] message = new byte[1500];
DatagramPacket p = new DatagramPacket (message, message.length);
DatagramSocket s = new DatagramSocket (server_port);
s.receive(p);
text = new String (message, 0, p.getLength());
Log.d("Udp tutorial","message:" + text);
s.close();
References:
Simple UDP communication example
I am creating a simple Android app which can communicate with my PC. On my computer I have a very simple UDP server in Java.
public void run(){
try{
DatagramSocket serverSocket = new DatagramSocket(port);
byte[] receiveData = new byte[8];
byte[] sendData = new byte[8];
while(true)
{
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String sentence = new String( receivePacket.getData());
System.out.println("RECEIVED: " + sentence);
InetAddress IPAddress = receivePacket.getAddress();
String sendString = "polo";
sendData = sendString.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port);
serverSocket.send(sendPacket);
}
}catch (Exception e){
}
}
and I have another simple piece of code inside my android app which sends a UDP packet to the server and awaits the response.
public void checkServerOnline(View v) {
try {
int port = 46001;
DatagramSocket clientSocket = new DatagramSocket();
clientSocket.setSoTimeout(1800);
InetAddress IPAddress = InetAddress.getByName(host);
byte[] sendData = new byte[8];
byte[] receiveData = new byte[8];
String sentence = "marco";
sendData = sentence.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port);
clientSocket.send(sendPacket);
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
clientSocket.receive(receivePacket);
clientSocket.close();
} catch (Exception e) {
}
The problem I am having is that my Client is timing out waiting for a response. The server is definitely receiving the string "marco" and is presumably sending the response "polo", but the client is not receiving it. I've tried removing the timeout on the client, but it just freezes up until I force close the application.
Can anyone see an error in my code? I can't understand why it won't work. I've managed to successfully setup a TCP Server and client with the same setup, but cannot seem to do UDP.
The server is sending to the wrong port. It should send to the port in the received datagram, not its own port. It is simplest to reuse the request datagram and just change the data to the response data: the return address is already there.
I am trying to send a serialized object from a server process to a client process in Java using UDP. The problem is that the client is being blocked on the receive method. Can someone help?!
here is the server code for sending the object:
ClientModel C1= new ClientModel(100,"Noor","Noor",38,38,"asd");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(C1);
oos.flush();
byte[] Buf= baos.toByteArray();
packet = new DatagramPacket(Buf, Buf.length, client, port);
socket.send(packet);
and here is the client code for receiving the object:
byte[] buffer = new byte[100000];
packet = new DatagramPacket(buffer, buffer.length );
socket.receive(packet);
System.out.println("packet received");
I just want to receive the object to be able to reconstruct but I cannot receive the packet itself.
I dont know what you want to accomplish in the end, but working with UDP is not so easy... the main reason is in the Description of the DatagramPacket Object:
Datagram packets are used to implement
a connectionless packet delivery
service. Each message is routed from
one machine to another based solely
on information contained within that
packet. Multiple packets sent from
one machine to another might be routed
differently, and might arrive in any
order. Packet delivery is not
guaranteed.
A good tutorial when working with udp is http://download.oracle.com/javase/tutorial/networking/datagrams/clientServer.html
About your blocking:
Receives a datagram packet from this
socket. When this method returns, the
DatagramPacket's buffer is filled with
the data received. The datagram packet
also contains the sender's IP address,
and the port number on the sender's
machine.
This method blocks until a datagram is
received. The length field of the
datagram packet object contains the
length of the received message. If the
message is longer than the packet's
length, the message is truncated.
I didnt really test it, but I am pretty sure - based on the description - that the datagramsocket.reseive function will block until the packet is filled (in your case until 100000 bytes are received).
I would suggest you start with a datagrampacket with a fixed known length, where you transmit the size of the actual payload. Something like:
public static void main(String[] args) {
ClientModel c1 = new ClientModel ();
c1.data = 123;
c1.name = "test";
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(c1);
oos.flush();
// get the byte array of the object
byte[] Buf= baos.toByteArray();
int number = Buf.length;;
byte[] data = new byte[4];
// int -> byte[]
for (int i = 0; i < 4; ++i) {
int shift = i << 3; // i * 8
data[3-i] = (byte)((number & (0xff << shift)) >>> shift);
}
DatagramSocket socket = new DatagramSocket(1233);
InetAddress client = InetAddress.getByName("localhost");
DatagramPacket packet = new DatagramPacket(data, 4, client, 1234);
socket.send(packet);
// now send the payload
packet = new DatagramPacket(Buf, Buf.length, client, 1234);
socket.send(packet);
System.out.println("DONE SENDING");
} catch(Exception e) {
e.printStackTrace();
}
}
On the other side you now KNOW your sizes:
public static void main(String[] args) {
try {
DatagramSocket socket = new DatagramSocket(1234);
byte[] data = new byte[4];
DatagramPacket packet = new DatagramPacket(data, data.length );
socket.receive(packet);
int len = 0;
// byte[] -> int
for (int i = 0; i < 4; ++i) {
len |= (data[3-i] & 0xff) << (i << 3);
}
// now we know the length of the payload
byte[] buffer = new byte[len];
packet = new DatagramPacket(buffer, buffer.length );
socket.receive(packet);
ByteArrayInputStream baos = new ByteArrayInputStream(buffer);
ObjectInputStream oos = new ObjectInputStream(baos);
ClientModel c1 = (ClientModel)oos.readObject();
c1.print();
} catch(Exception e) {
e.printStackTrace();
}
}
The CientModel clas sI used:
public class ClientModel implements Serializable{
private static final long serialVersionUID = -4507489610617393544L;
String name = "";
int data = 1;
void print() {
System.out.println(data +": " + name);
}
}
I tested this code and it works just fine. Hope that helps (I got the byte-To-int and around from http://www.tutorials.de/java/228129-konvertierung-von-integer-byte-array.html)
Edit: As stated in the comments, it is often a very bad idea to use UDP, mainly, because you do not know if your packets are received in the correct order, or even at all. UDP does NOT guarantee that. I didn't do too much udp programming, but the only part you can rely on (if I understood correctly) is, that if you get a packet and it fits within the datagram (65,527 bytes - see https://en.wikipedia.org/wiki/User_Datagram_Protocol) it will contain the whole thing. So if you do not care about the order in which the message come and your object fits in the datagram, you should be fine.
Edit2: As for the code: do not use it as is. it is only an example, ind UDP you should only have one type of packet, and this with a known size. that way you do not need to send the "size". If you use the code as shown above, and one packet is dropped, the next packet will be the wrong size (i.e. the first packet is dropped, suddenly you are checking the first bytes of the payload to get the size).
I didnt really test it, but I am pretty sure - based on the
description - that the datagramsocket.reseive function will block
until the packet is filled (in your case until 100000 bytes are
received).
This is wrong. The receive function will block until a datagram is received, which can be smaller than the buffer size (and usually will be). The method packet.getLength() will tell you how big it was.