Hey guys I am working on a project where I need to broadcast a UDP packet on the actual internet and also receive them on the client. Currently I am using the multicast socket for broadcasting the packet on the local lan. I had come across this project called jstunt for NAT traversal of a UDP datagram but cant find any relevant documentation on it and also no implementation. I am familiar with the concepts of Nat Traversal, UDP hole punching but am facing the same problem as above, no relevant documentation and implementation. So can anyone please help and also suggest some other techniques for achieving this.
As the other poster has mentioned, you can't really "broadcast" a packet freely to the internet. If that were possible, networks could easily be DOS'd and incredible congestion would result. Even within controlled networks, broadcasts are usually tightly controlled so that they do not get out of hand. That said, perhaps you don't really need to "broadcast" the packet.
If you need to create a UDP "tunnel" across the internet, such as how P2P software works, it can be done. The trick is usually NAT. You mentioned you were already familiar with UDP hole punching, but couldn't figure out how to make it work. Here are some Java libraries that can be used for this:
http://www.masquerade.cz/en/nat-tunel-metodou-udp-hole-punching-v-jazyce-java/
http://ulno.net/projects/jpunch/
http://samy.pl/pwnat/
Also check out UPNP: http://en.wikipedia.org/wiki/Universal_Plug_and_Play
And the STUNT library: http://nutss.gforge.cis.cornell.edu/stunt.php
It's highly unlikely that your ISP, and your clients', will support UDP broadcast, let alone what the Internet backbone may or may not allow. You need to investigate that first. It's not a programming problem yet, it's a feasibility problem.
ITS BASIC DAY TIME SERVER IMPLEMENTATION USING UDP SOCKET ITS HELP YOU
CLIENT
import java.io.*;
import java.net.*;
public class DayTime_Client_Udp
{
public static void main (String[] args) throws IOException
{
String hostname= "localhost";
int port=13;
if ((args.length == 1))
{
hostname=args[0];
}
else if ((args.length==2))
{
hostname=args[0];
port=Integer.parseInt(args[1]);
}
InetAddress host = InetAddress.getByName(hostname);
DatagramSocket socket = new DatagramSocket ();
DatagramPacket packet=new DatagramPacket (new byte[100], 0,host, port);
socket.send (packet);
packet.setLength(100);
socket.receive (packet);
socket.close ();
byte[] data = packet.getData ();
String time=new String(data); // convert byte array data into string
System.out.println(time);
}
}
SERVER
import java.io.*;
import java.net.*;
public class DayTime_Server_Udp
{
public static final int DEFAULT_PORT = 3001;
public static void main (String[] args) throws IOException
{
if (args.length > 1)
{
throw new IllegalArgumentException ("Syntax: DaytimeServer [<port>]");
}
DatagramSocket socket = new DatagramSocket(args.length == 0 ?
DEFAULT_PORT : Integer.parseInt (args[0]));
DatagramPacket packet = new DatagramPacket (new byte[1], 1);
while (true)
{
socket.receive (packet);
System.out.println("Received from: " + packet.getAddress () + ":" +
packet.getPort ());
byte[] outBuffer = new java.util.Date ().toString ().getBytes ();
packet.setData (outBuffer);
packet.setLength (outBuffer.length);
socket.send (packet);
}
}
}
IF MORE HELP REQUIRED THAN COMMENT IT I ALSO HAVE OTHER PROGRAM WITH UDP BASD SO ITS HELP UU
Related
I am learning about sockets in java, but when I was running a program that sends messages from the client side to server side it doesn't show a message. If I enter some text on the client side it doesn't show up on the server side, but if I type endProcess it stops running. Which means that the message is going through it's just not showing up.
My Client.java code is here:
import java.net.*;
import java.io.*;
public class Client{
Socket soc;
DataInputStream dis;
DataOutputStream dos;
public Client(){
try{
soc = new Socket("(Address)",5000);
System.out.println("Connection Established");
dis = new DataInputStream(System.in);
dos = new DataOutputStream(soc.getOutputStream());
System.out.println("Streams connected");
}catch(UnknownHostException u){
System.out.println(u);
}catch(IOException i){
System.out.println(i);
}
String line = "";
while(!line.equals("endConnection")){
try{
line = dis.readUTF();
dos.writeUTF(line);
}catch(IOException i){
System.out.println(i);
}
}
try {
soc.close();
dis.close();
dos.close();
} catch (Exception e) {
System.out.println(e)
}
}
public static void main(String[] args) {
new Client();
}
}
Here is my Server.java code:
import java.net.*;
import java.io.*;
public class Server {
ServerSocket serSoc;
Socket soc;
DataInputStream dis;
public Server(){
try {
serSoc = new ServerSocket(5000);
System.out.println("Server Online");
soc = serSoc.accept();
System.out.println("Client Connected");
dis = new DataInputStream(new BufferedInputStream(soc.getInputStream()));
String line = "";
System.out.println("Waiting for input...");
while(!line.equals("endConnection")){
line = dis.readUTF();
System.out.println(line);
}
System.out.println("Client disconnected");
soc.close();
dis.close();
} catch (Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
new Server();
}
}
There are many problems here.
Duplex protocol issues
line = dis.readUTF();
dos.writeUTF(line);
This isn't going to work; The dis.readUTF() line is going to block (freeze) until a line is read. The problem is, sometimes you have nothing to send in which case you want to read, and something you have nothing to read in which case you want to send. In practice you need to redesign this entirely; you need 2 threads. At which point you get into the issues of multicore, needing synchronization primitives and/or java.util.concurrent classes for all data that is shared between the 2 threads.
Alternatively, adopt a model that is strictly push or pull (where at any given time both parties already know who can send, and if the other party wants to send they simply cannot. For example, every party sends a simply 'NOTHING TO DO' message every second, trading places every time. This is quite an inefficient algorithm, of course. But could be written without involving multiple threads.
Flush and close issues
dos.writeUTF(line);
This doesn't actually send anything, or at least, isn't guaranteed to. To send any data on the internet, it gets wrapped in a packet which has lots of overhead. So, things are buffered until there's a full packet to send. Which means that line doesn't do anything. It just fills a buffer, no packets go out. You first need to close or flush. dos.flush() would help maybe. This is a big problem, because later you do:
soc.close();
dis.close();
dos.close();
You first close the socket, which, well, closes the socket. You then close the streams, which will also send anything that's still stuck in a buffer, except, that will fail, because the socket is already closed. In other words, the line you .writeUTF()-ed? It never gets there. You first shove it in a buffer, then you close the socket, then you send the buffer which won't work as the socket is already closed.
Broken error handling
} catch (Exception e) {
System.out.println(e);
}
Horrible. Don't do this. Your code reacts to any problem by printing something and just keeping right on going. That means if anything goes wrong, the client will start spamming an endless cavalcade of exception traces and locking up the system with any luck. You want the code to stop running when problems occur. Easiest way, by far, is to just stick throws IOException on your constructor and main method, which is allowed. Distant second best option is to configure your 'eh whatever' catch blocks as throw new RuntimeException("unhandled", e); instead of e.printStackTrace().
What you do (System.out.println(e);) is even worse - you are tossing away extremely useful information such as the stack trace and causal chain.
I'm a beginner in java. I have a device that sends UDP broadcast ping packets every 5s, and rarely sends an alert (a kind of alarm).
I want to have a java program that listens for the ping packets and shows how long since the last ping, and sets off an alarm of some kind either if a ping is not received for a certain amount of time, or if an actual alert from the sensor is received.
I've shamelessly copied this code from stackoverflow, but the serverSocket.receive(receivePacket) blocks, so the counter does not work.
I think that I need to spawn a thread to open the socket and wait for received data, and then communicate back to the main thread somehow without blocking so the timer can run, but I have no idea how to achieve that.
Here's the code I have so far - it works but the timer does not work to show the time since the last ping:
package com.testing;
import java.io.IOException;
import java.net.*;
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class Receiver { // from https://stackoverflow.com/a/13780614/1340782
public static void main(String[] args) {
int port = args.length == 0 ? 8266 : Integer.parseInt(args[0]);
new Receiver().run(port);
}
public void run(int port) {
try {
DatagramSocket serverSocket = new DatagramSocket(port);
byte[] receiveData = new byte[8];
String sendString = "pong";
byte[] sendData = sendString.getBytes("UTF-8");
System.out.printf("Listening on udp:%s:%d%n",
InetAddress.getLocalHost().getHostAddress(), port);
DatagramPacket receivePacket = new DatagramPacket(receiveData,
receiveData.length);
LocalTime lastPing = java.time.LocalTime.now();
String lastMessage = "";
while(true)
{
serverSocket.receive(receivePacket);
String sentence = new String( receivePacket.getData(), 0,
receivePacket.getLength() );
// System.out.println(java.time.LocalTime.now().truncatedTo(ChronoUnit.SECONDS) + " RECEIVED: " + sentence);
LocalTime now = java.time.LocalTime.now();
lastMessage = now.format(DateTimeFormatter.ofPattern("HH:mm:ss"))
+ " RECEIVED: " + sentence;
if (sentence.equals("ping")) {
lastPing = java.time.LocalTime.now();
}
lastMessage = lastMessage + " - " + Duration.between(lastPing,now).toMillis() + "ms since last ping";
System.out.print(lastMessage);
System.out.print("\r");
}
} catch (IOException e) {
System.out.println(e);
}
// should close serverSocket in finally block
}
}
Thanks everyone
You are using blocking IO in this example, so if you want something to be running at the same time while your socket is waiting for data, you will need another Thread, as you figured out already.
In this case, it looks like you don't really need to manage a Thread yourself, just use Java's repeating scheduler service instead, so that you can get a task to run repeatedly every p period of time.
Your code doing networking doesn't require any changes, just pull out the code that manages the pings into a separate method that will do something like this:
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
class Scratch
{
// AtomicReference helps exchange data between threads safely
static final AtomicReference<Instant> lastPing = new AtomicReference<>();
public static void main(String[] args) throws InterruptedException
{
// the lambda below will run every 2 seconds
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
Instant lastPingTime = lastPing.get();
if (lastPingTime == null)
{
System.out.println("No ping yet");
}
else
{
System.out.println("Last ping was " + Duration.between(lastPingTime, Instant.now()) + " ago");
}
}, 0, 2, TimeUnit.SECONDS);
// simulate a ping from the main Thread after 5 seconds
Thread.sleep(5_000L);
lastPing.set(Instant.now());
}
}
You can run this code and it should print something like this:
No ping yet
No ping yet
No ping yet
Last ping was PT0.999S ago
Last ping was PT2.997S ago
Last ping was PT4.995S ago
...
Hopefully this is enough to get you unblocked. There's much to read about multi-threading in Java, but knowing you can use AtomicReference as well as its primitive cousins (AtomicBoolean, AtomicInteger...) to safely exchange data between different Threads should already be enough for you to implement what you want now.
Learning about the Java ExecutorService (I used Executors above to create one) is also important, so you don't need to create Threads yourself directly (the service will do it for you). Notice that because the ExecutorService usually keeps a thread-pool internally, you need to make sure to call close() on it once you're done, otherwise your application will never finish running (might be ok for GUIs and servers, but not for CLIs and short-running processes).
Right now I have a device sending out UDP messages to a multicast group. I wrote a small Java program that can detect these packets by joining the group and looking to the right port. I use the MulticastSocket.receive(packet); command. I am moving on to writing a program with a GUI for this purpose. I want a user to be able to specify an amount of time, and for my program to look for packets for this amount of time. I've done a lot of research and found that the best way of doing this, cutting off the receive command when it is blocking a port, is to close the port prematurely. In order to do this, I have my program open up another thread, and use the new thread to watch for the UDP packets while my main thread sleeps for the specified time. It is detecting the packets just fine. However, I cannot seem to access it from the main thread to close the port. Here is my code:
import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;
public class MulticastClient_v2 extends Thread
{
public volatile MulticastSocket socket;
public void run()
{
try {
//Declare the port and IGMP Group IP
MulticastSocket socket2 = new MulticastSocket(5000);
InetAddress address = InetAddress.getByName("224.0.1.2");
//Display connection information
System.out.println("Joining 224.0.1.2 on port 5000");
//Join the Multicast Group
socket.joinGroup(address);
//Declaring a DatagramPacket
DatagramPacket packet;
//Starting an infinite loop
//while (true)
//{
System.out.println("Waiting on packets..");
byte[] buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length); //Declaring an internal DatagramPacket
socket.receive(packet); //Receiving a Packet
String received = new String(packet.getData(), 0, packet.getLength());
InetAddress senderAddress = packet.getAddress(); //Get the InetAddress object
String forFun = senderAddress.getHostAddress(); //Extract the IP address of sender in text format
if (received.indexOf("Product1") >= 0) //Searching the raw data for "Product1"
{
//If found, display the IP and device type
System.out.println("Product1 found at " + senderAddress);
}
if (received.indexOf("Product2") >= 0) //Searching the raw data for "Product2"
{
//If found, display the IP and device type
System.out.println("Product2 found at " + senderAddress);
}
//}
}
catch(IOException ex)
{
System.out.println (ex.toString());
}
}
public static void main(String[] args)
{
MulticastClient_v2 thread = new MulticastClient_v2();
thread.start();
try {
Thread.sleep( 3000 );
thread.socket2.close();
}
catch(InterruptedException in)
{
System.out.println("Interrupted Exception!");
}
System.out.println("Done.");
}
}
So, when I try to compile, I get the following error:
MulticastClient_v2.java:63: error: cannot find symbol
thread.socket2.close();
^
symbol: variable socket2
It seems to me, that the main method cannot see socket2 with is in another method. My question is how to I make it available to see? I experimented a bit with the
public volatile MulticastSocket socket;
and the main method can access it, but I can't connect to a certain port when I'm in the run method. The only thing I could find that may do this is bind(). But bind() requires both an IP and a port, whereas when I first declare a Multicast socket, I can declare just the port like so:
MulticastSocket socket2 = new MulticastSocket(5000);
Any help would be very much appreciated! I've been stuck on this a while now.
EDIT: I've gotten some suggestions. First, that I should declare and initialize at the class level, this is giving me the following IO error:
MulticastClient_v2.java:8: error: unreported exception IOException; must be caught
or declared to be thrown
public volatile MulticastSocket socket = new MulticastSocket(5000);
^
So next, I tried putting it in a try..catch block at the class level, and I get this:
MulticastClient_v2.java:8: error: illegal start of type
try{
^
So I guess what I really need to do is initialize the Multicast Port at the class level then put it in a try block inside a method, as JTMon suggested. But I can't figure out a way to pick just its port without doing it during initialization.
EDIT 2:
I'm having difficulty still. If I try to initialize it like so in the class level:
public volatile MulticastSocket socket;
How can I edit its port later on in the run() method?
socket2 is a local variable, so it's scope is just the try block in which it is defined. Using a MulticastClient_v2 instance you could only access fields of that class.
Isn't socket2 declared as a local variable inside the run method? It would not be accessible from anywhere outside that method. Try declaring it at the class level first and see what happens.
I will try to put some code here to explain what I meant exactly.
Declare the variable socket2 at the class level.
The MulticastClient_v2 class should have a public consturctor of the type:
public MulticastClient_v2(int portNumber){
try{
socket2 = new MulticastSocket(portNumber);
}catch(IOException e){
//Do something with exception here
}
}
If the port number does not change you can hard code it in but this way is more flexible.
In the run method you can now use the initialized socket and you can still access it from outside the class. Just for the record though I would prefer you make the access through another method on the thread, but that might be a discussion for another thread ;)
It would seem that the Client - Server application i wrote does work however it seems that not all data is processed every time.
I am testing it on a local machine in Eclipse env.
Server:
private void sendData() throws Exception
{
DatagramPacket data = new DatagramPacket(outgoingData, outgoingData.length, clientAddress, clientPort);
InputStream fis = new FileInputStream(responseData);
int a;
while((a = fis.read(outgoingData,0,512)) != -1)
{
serverSocket.send(data);
}
}
Client:
private void receiveData() throws Exception
{
DatagramPacket receiveData = new DatagramPacket(incomingData, incomingData.length);
OutputStream fos = new FileOutputStream(new File("1"+data));
while(true)
{
clientSocket.receive(receiveData);
fos.write(incomingData);
}
}
I used to have if else in the while(true) loop to check if packet length is less than 512 bytes so it knew when to break;
I was thinking there was a problem whit that but seems that was oke for now i just wait few minutes and then stop the Client.java app
The file does transfer but the original file is 852kb and so far i got 777, 800, 850,.. but never all of it.
The fundamental problem with your approach is that UDP does not guarantee delivery. If you have to use UDP (rather than, say, TCP), you have to implement a scheme that would detect and deal with packets that got lost, arrive out of order, or are delivered multiple times.
See When is it appropriate to use UDP instead of TCP?
You should probably use TCP to transfer files. You are probably losing packets because you are sending them so fast in that while loop.
int a;
while((a = fis.read(outgoingData,0,512)) != -1)
{
serverSocket.send(data);
}
since you're sending so fast I highly doubt it will have a chance to be received in the right order. some packets will probably be lost because of it too.
Also since your sending a fixed size of 512 bytes the last packet you send will probably not be exactly that size, so you will see the end of the file "look wierd."
When I tested with both client and server on localhost its works. But then I split the client and server to different machines with different IP addresses and now the packets are not being received on the client side. Can anyone spot the problem with my code:
Client:
class Csimudp {
public static DatagramSocket ds;
public static byte buffer[] = new byte[1024];
public static void Myclient() throws Exception {
while (true) {
DatagramPacket p = new DatagramPacket(buffer, buffer.length);
ds.receive(p);
System.out.println(new String(p.getData(), 0, p.getLength()));
}
}
public static void main(String args[]) throws Exception {
System.out.println("for quitting client press ctrl+c");
ds = new DatagramSocket(777);
Myclient();
}
}
Server:
class Ssimudp {
public static DatagramSocket ds;
public static byte buffer[] = new byte[1024];
public static void MyServer() throws Exception {
int pos = 0;
while (true) {
int c = System.in.read();
switch (c) {
case '~':
System.out.println("\n Quits");
return;
case '\r':
break;
case '\n':
ds.send(new DatagramPacket(buffer, pos, InetAddress
.getByName("117.201.5.150"), 777));
pos = 0;
break;
default:
buffer[pos++] = (byte) c;
}
}
}
public static void main(String args[]) throws Exception {
System.out.println("server ready....\n please type here");
ds = new DatagramSocket(888);
MyServer();
}
}
I would hazard a guess that your packets are being blocked by a firewall somewhere in their way. I'd start by opening the appropriate outgoing and incoming UDP ports in the firewalls of the client and the server respectively.
Or your server might be sitting behind a NAT gateway and you need to set up port forwarding rules for it to receive any packets. For example, most ADSL routers are actually set up as a NAT gateway.
Another potential issue is your port selection:
You are binding your client to a specific local port. There is no need for that - let the OS select a free port on its own. This would also remove the possibility of trying to use a port that is already in use.
You are using ports in the [0-1023] range. This port range is generally reserved for well-known services - as a matter of fact, on most Unix-like systems (e.g. Linux) you cannot bind a listening port in that range without root privileges. As a result, quite a few ISPs will filter that port range in their firewall, supposedly to protect their users.
Without more information on the networks that connect the client to the server, it's quite hard to provide a more concrete answer.
PS: There is no need to recreate the InetAddress object in every iteration of your loop - do it once beforehand...
PS.2: In general the computer that sends the first packet in a UDP session is considered the client, since it's also the one that can exist without a fixed address. Your assignment of the client/server roles is reversed in that respect. So when reading my points above, you will have to reverse the client/server specifications for them to apply to your code...