Making a Multicast Socket accessible from another Thread - java

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 ;)

Related

Client side is not sending message to server Java Socket

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.

What type of array do I send to constructor?

I am creating a server-chat-client application and have borrowed code. I know how most of the things work except one.
In my Class Server I wait for a socket to be accepted.
public static ArrayList<String> clientUsernameList = new ArrayList<>();
/**
* #param args the command line arguments
* #throws java.io.IOException
*/
public static void main(String[] args) throws IOException {
int port = 8900; //Port number the ServerSocket is going to use
ServerSocket myServerSocket = null; //Serversocket for sockets to connect
Socket clientSocket = null; //Listerner for accepted clients
ClientThread[] clientsConnected = new ClientThread[20]; //Max clients in this server
try {
myServerSocket = new ServerSocket(port);
System.out.println("Server waiting for clients on port:" + port);
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
while (true) {
try { //Freezes while-loop untill a socket have been accepted or if some failure occur
clientSocket = myServerSocket.accept();
System.out.println("Client have connected from:" + clientSocket.getLocalAddress().getHostName());
} catch (Exception e) {
//Print out exception
System.out.println(e);
}
//For-loop that counts every element in Array-clientsConnected
for (int i = 0; i < clientsConnected.length; i++) {
//If-statement checks if current element is null
if(clientsConnected[i] == null){
//If current element in the Array is null then create a new object from ClientThread class
//With a socket and the object of itself as parameter.
(clientsConnected[i] = new ClientThread(clientSocket, clientsConnected)).start();
//Must have a break otherwise it will create 20 objects (Exit for-loop)
break;
} //Exit if-statement
} //Exit for-loop
} //Exit while-loop
}
}
So if a socket gets accepted I create a thread class called Class ClientThread
To create a object of this class I need a socket and a array.
This is how my ClientThread class looks like
public class ClientThread extends Thread {
private ClientThread[] clientsConnected;
private Socket SOCKET = null;
private DataInputStream IN = null;
private DataOutputStream OUT = null;
private String userName,zone;
//-------------------------------------------------------
//Constructor
public ClientThread(Socket socket, ClientThread[] clientThread) {
this.SOCKET = socket;
this.clientsConnected = clientThread;
}
//Some more code
Now this is where I am lost. Do I send in my whole array? and if I do shouldn't user1 only get an array with 1 user and when user2 connects shouldn't he get an array with 2 users? I am lost. If someone could point me to something that explains this I would be grateful.
Your code will serve only 20 requests. For each one it adds new value to clientsContected, once the whole table is full it will just go back to the start of the loop (without closing the accepted connection).
Probably the idea of passing the clientsConnected to the thread, was so it can set the value to null once it stopped working (so that your main code in the loop can assigne a new client to it). GUessin as no code is included). But for that an index inside the array would be useful (so 3 parameters instead of 2) so the ClientThread doesn't have to search the whole array to find object matching this.
I would rather recommend using BlockingQueue (with limited capacity for example 5) to which you will pass accepted connections. Once it is full your main will be forced to wait on it till it has same space to insert new connection so you will stop accepting new sockets. Create the 20 threads, that in a inifinite loop tries to get a socket from that queue and serve it. Once they finish they go back an wait for new request.
So yes you passs the whole array.
Still it doesn't solve the problem of what happens if all are busy, as you keep accepting new clients instead of waiting for free Thread.

Java: Using variables from try blocks

So I've got a thing like this:
try{ServerSocket acceptor = new ServerSocket(4782);}
catch(IOException e){System.err.println("ERROR: Couldn't listen on port 4782!");}
while (true)
{
Socket clientSock = acceptor.accept();
}
But when trying to assign clientSock, it says it can't find acceptor. When moving the acceptor out of the try block, it explodes with an unhandled exception.
Should I be putting a thing like Socket clientSock; before the try block?
Thanks.
An alternative to what the other folks here have suggested: you could move more code into the try block:
try{
ServerSocket acceptor = new ServerSocket(4782);
while (true) {
Socket clientSock = acceptor.accept();
}
} catch(IOException e){
System.err.println("ERROR: Network problem:" + e.getMessage());
}
The advantage of doing things this way -- when you can get away with it -- is that the "happy path" reads more clearly; it's easier to follow what the code is supposed to do. The dark side of this approach is that it leads to lumping various error conditions together, so you can't react as specifically to individual problems. Sometimes, though, even that is an advantage rather than a problem.
You can keep the instantiation in the try-catch but move the variable declaration out.
ServerSocket acceptor = null;
try{acceptor = new ServerSocket(4782);}
catch(IOException e){System.err.println("ERROR: Couldn't listen on port 4782!");}
while (true)
{
Socket clientSock = acceptor.accept();
}
No you should put the declarion of acceptor before the try block, like this:
ServerSocket acceptor = null;
try {
acceptor = new ServerSocket(4782);
} catch (IOException e) {
System.err.println("ERROR: Couldn't listen on port 4782!");
}
while (true) {
Socket clientSock = acceptor.accept();
}
For this code, acceptor can be null inside the while-loop, either check for it there or do something flow-alterning inside the catch-block.
You might also want to handle the IOException that Socket clientSock = acceptor.accept();
might throw, since such Exception would break the while-loop - which might not be according to plans.
The general explaination is that java scopes variable declarations "as limiting as possible" acceptor was declared inside the try-block in your code, hence not available/undeclared outside of it.

Monte carlo server program

package montecarlo;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
/**
*
* #author hafiz
*/
public class PICalcDistributedMaster {
ObjectOutputStream ostream;
ObjectInputStream istream;
Socket s;
String numThrows;
public void go(){
Scanner input = new Scanner(System.in);
System.out.println("Please enter number of throws: ");
numThrows = input.next();
int num = Integer.parseInt(numThrows);
try{
ServerSocket sock = new ServerSocket(100);
s = new Socket("127.0.0.1",100);
System.out.println("Waiting for connection");
System.out.println("Connection received from " + s.getInetAddress());
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
pw.println("Sending Number");
pw.println(num);
ostream = new ObjectOutputStream(s.getOutputStream());
ostream.flush();
istream = new ObjectInputStream(s.getInputStream());
System.out.println("IO streams found");
istream.read(); //reads the input stream
}
catch (IOException ie){
ie.printStackTrace();
}
}
public static void main(String [] args){
PICalcDistributedMaster pim = new PICalcDistributedMaster();
pim.go();
}
}
i have adjusted the code to what you told me.I am still getting an error after running it more than once and i think it has to do with the garbage collector problem.My error is
java.net.SocketException: Unrecognized Windows Sockets error: 0: JVM_Bind
at java.net.PlainSocketImpl.socketBind(Native Method)
at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:365)
at java.net.ServerSocket.bind(ServerSocket.java:319)
at java.net.ServerSocket.<init>(ServerSocket.java:185)
at java.net.ServerSocket.<init>(ServerSocket.java:97)
at montecarlo.PICalcDistributedMaster.go(PICalcDistributedMaster.java:31)
at montecarlo.PICalcDistributedMaster.main(PICalcDistributedMaster.java:56)
I assume the problem is with the socket it is binding to.I have tried different kinds but i cant still proceed
I'd like to suggest programming in smaller chunks. You've got a lot of code here and I don't think most of it ever runs:
ServerSocket sock = new ServerSocket(5000);
s = new Socket("127.0.0.1",5000);
s = sock.accept();
This code creates a server socket, binds it to a port.
Then you create a new socket s to connect to the server socket. (Which isn't yet listening.)
You destroy your new socket s with the sock.accept() result -- when you lose the last reference, the socket is free for garbage collection, and you only ever had one reference to it -- s.
The sock.accept() call probably ought to block until a new connection arrives. If it doesn't block, that means you triggered an exception even before all this code.
Incidentally, there's another instance of overwriting content nearly immediately after creating it:
String message = "connection successful";
message = (String) istream.readObject();
You'll never see connection successful from your program because you've overwritten the only reference you have to the string.
Probably the most egregious error in the entire program -- the one that is keeping you from making any real forward progress -- is that you throw away all the exception information:
try{
go(null);
}
catch(Exception e){
System.err.print("Connection terminated");
}
The catch(Exception e) { /* print message */ } means that you don't get any diagnostic information about what errors actually happened in your program. (Since you never use the parameter of go(), you should remove it completely and the needless null here, as well.)
One of these catch-all catch statements might be useful once you're confident that your product catches everything more specific, is nearly bullet-proof, and your customers demand an always-on reliable product. But it has no place in development -- you need to be alerted to faults in your programs with as much detail as possible so you can find and fix all your bugs.
Remove this. Get rid of your process() method completely -- it is only harmful.

Need help with udp socket programming in java

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

Categories