I built an application which has a service and it contains sockets to receive messages in LAN.It work fine when WiFi is ON, but when I start the application with WiFi OFF state it gives an error of socket bind failed and it don't work even if I turn the WiFi ON.
Is there any way to get notified in the app when the WiFi is turned on so that I can start that particular service again, or any other method to bind the socket so that it may bind correctly with the WiFi OFF state.
My current code is:
socket = new DatagramSocket(port, broadcastIP);
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
socket.receive(packet);
If WiFi is OFF you are probably getting a SocketException when creating the DatagramSocket instance because the socket cannot be bound to the IP address passed. Moreover, if the network interface is down it doesn't have any IP address.
Maybe you should ask first for the network interfaces in your device and then check the status of each interface. If the interface is up then you get the IP address and then you can create a socket bound to it.
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface netIf : Collections.list(nets))
{
System.out.println("Display name: " + netIf.getDisplayName());
System.out.println("Name: " + netIf.getName());
if (netIf.isUp()) //Is the interface up
{
Enumeration<InetAddress> inetAddresses = netIf.getInetAddresses();
for (InetAddress inetAddress : Collections.list(inetAddresses))
{
System.out.println("InetAddress: " + inetAddress);
}
}
}
Look here:
http://docs.oracle.com/javase/tutorial/networking/nifs/retrieving.html
and here:
http://docs.oracle.com/javase/6/docs/api/java/net/NetworkInterface.html
Related
I have a java application that pulls information from network interface and I'm using NetworkInterface class to iterate through the gazillion of interfaces I have in my computer. "I have installed virtualbox" and this create many virtual interface. But I need to get info from my wireless or ethernet interface as those are the only option to connect to the network. The problem is that I want to be able to sort through all these interfaces and get only the relevant. What approach you guys suggest? doing a search through the NetworkInteface collection looking for eth0 or wlan1. any ideas appreciated. Here's the code that deals with network interface in my application.
//displaying all network interface
Enumeration<NetworkInterface> nets = null;
try {
nets = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e3) {
e3.printStackTrace();
}
for (NetworkInterface netint : Collections.list(nets)) {
displayInterfaceInformation(netint);
}
static void displayInterfaceInformation(NetworkInterface netint) throws SocketException {
Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
System.out.printf(count + " Display name: %s\n", netint.getDisplayName());
System.out.printf("Name: %s\n", netint.getName());
for (InetAddress inetAddress : Collections.list(inetAddresses)) {
System.out.printf("InetAddress: %s\n", inetAddress);
}
System.out.println("\n");
}
There could be a more straightforward way, but if you're just looking for the interface that connects to the internet, there's a simple trick you can use that doesn't involve reading routing tables - just create a socket, connect it to an address that exists on the internet, then get that socket's local address. It's better to use a UDP socket since its connect doesn't do any actual IO:
DatagramSocket s = new DatagramSocket();
s.connect(InetAddress.getByName("1.1.1.1"), 53);
System.out.println(s.getLocalAddress());
The operating system will bind the socket to an appropriate interface for the outbound connection using the routing table. Once you have the IP address, you can find the interface with that IP address.
I am developing a web application which acts as a server. In this application I have implimented ServerSocket for two way communication between server application and wi-fi device which acts as client. I am not connecting to my server directly, I am connecting to my router which port forwards to my system and two way communication is successful. All I want now is to find the MAC address of Wi-fi device which is connected.I have done some research and tried to get the MAC address but failed.Can anyone help me on this.Below is the part of my code.
public class ScheduleJob extends ServletApp implements Job{
private int port = 1717;
public static String number;
String ReceivedData = "";
public void execute(JobExecutionContext context)throws JobExecutionException {
System.out.println("Starting ... ");
ServerSocket Sersocket = null;
System.out.println("Starting the socket server at port:" +port);
boolean listeningSocket = true;
try {
Sersocket = new ServerSocket(port);
System.out.println("Waiting for clients...");
} catch (IOException e) {
System.err.println("Could not listen on port: 1717");
}
try {
while (listeningSocket) {
Socket scokt = Sersocket.accept();
InetAddress MachineAdd = scokt.getInetAddress();
System.out.println("Response-----:" +MachineAdd);
InetAddress ip = InetAddress.getLocalHost();
System.out.println("current ip : "+ip);
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
byte[] mac = network.getHardwareAddress();
System.out.print("Current MAC address : ");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mac.length; i++) {
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));
}
System.out.println(sb.toString());
MAC address is piece of information which belongs to layer 2 of OSI model.
In other words it's not preserved whenever you are communicating using L3 protocol (until you are communicating directly via cross cable or via L2 switch).
I would recommend you to send MAC address as a part of your application communication from client to your server, so it will not be lost when your router will do port forwarding.
Some of already asked questions on this topic:
Why can't the server get the client MAC address, like the client IP?
How can I get the MAC and the IP address of a connected client in PHP?
how to get a client's MAC address from HttpServlet?
I want that my client application is able to connect to a Server application.
The problem is that my Client doesn't know the Server ip (in LAN).
So I tried to use java object MulticastSocket. Luckily Oracle have a page with an example of Broadcasting.
Here I have rearranged it for my use.
Server code:
long FIVE_SECONDS = 5000;
int port = 4445;
DatagramSocket socket = new DatagramSocket(port);
while (true) {
System.out.println("Server running...");
try {
// message for client
String dString = "Hello Client";
byte[] buf = dString.getBytes();
// send
InetAddress group = InetAddress.getByName("230.0.0.1");
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, port);
socket.send(packet);
// sleep for a while
try {
Thread.sleep((long)(Math.random() * FIVE_SECONDS));
}
catch (InterruptedException e) {
System.err.println("Interrupted Exception");
}
} catch (IOException e) {
System.err.println("IOException");
}
}
Client code:
MulticastSocket socket = new MulticastSocket(4445);
InetAddress address = InetAddress.getByName("230.0.0.1");
socket.joinGroup(address);
// receive the message
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String received = new String(packet.getData(), 0, packet.getLength());
System.out.println("Received: " + received);
socket.leaveGroup(address);
socket.close();
When I run Srver: no problem, but when I try running client it throw java.net.BindException: Address already in use cause both client and server are listening/sending information on port 4445.
But isn't it right? To connect each other they must have the same port number, or they'll never 'meet'.
Can I solve this problem? How?
Are the port number correct?
Is this a right resolution to the problem about the unknown server ip?
Thanks!
As Warren mentioned in his answer, your client and server can't bind to the same port on the same machine. The Oracle example is not doing that.
The client should bind to port 4446 and the server should bind to port 4445. When the server create a DatagramPacket it should do so with the client's port which is 4446.
If you do this and the client still can't receive, you may need to set the outgoing interface for multicast on the server. You can do this with either the setInterface or setNetworkInterface methods.
For example, suppose your serverhas IP addresses 192.168.1.1 and 192.168.2.1. If you want your sender to send from 192.168.1.1, you would call:
multicastSocket.setInterface(InetAddress.getByName("192.168.1.1"));
You are getting this exception because you are trying to run your server application and your client application on the same machine. When you start your client, your server has already bound to port 4445, so it is already in use - and thus unavailable - when your client tries to bind to it.
Running your server and your client on different machines would get around that particular error. However, you could also get around it by choosing different ports for your server and your client.
For example if you ran your server on port 4445, and your client on port 4446, you could do the following. On the server, you would add a variable for the client port, and use the client port as the destination port when sending your DatagramPacket:
int clientPort = 4446;
...
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, clientPort);
instead of
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, port);
On the client, you would simply bind to the client port instead of the server port:
MulticastSocket socket = new MulticastSocket(4446);
instead of
MulticastSocket socket = new MulticastSocket(4445);
Using different port numbers for the server and for the client would allow you to run both the server application and the client application on the same machine and get you past this particular issue.
I'm not familiar with java, and I'm trying to do two Android application that communicates with each other (Client application, and Server application). On Client application, I want to display the Server IP, but it doesn't work with this:
for(i=1;i<=254;i++)
{ s1=partialip+String.valueOf(i);
//partialip has the form: "a.b.c."
//in s1 there are all possible Server's IPs : "192.168.1.1" or "192.168.1.2"...
InetAddress serv = InetAddress.getByName(s1);
Socket socket = new Socket(serv, 5000);
if(socket.isConnected()==true)
{
String server_ip = new String(s1);
text2.setText("Server IP: " + server_ip);
break;
}
}
I will appreciate it if somebody will help me.
To find a server on a local network, you'd better use UDP broadcast (DatagramSocket).
I am trying to implement a method that sends an UDP packet to multiple receivers. I thought that this should be doable setting setReuseAddress(true) on the receiving DatagramSocket instances.
My problem is that in certain conditions I need to limit the communication to the local computer - hence the localhost interface (useLocalhost=true in the demo code below). In such a case suddenly only the first receiver socket gets the incoming packet, the two other don't see anything.
I tested this on Windows (oracle 64bit) and Linux (OpenJDK 64bit), therefore I only see three possibilities:
This is an intended and known behavior (and I don't understand the whole mechanism - aka "bug in my brain")
There is a bug in the Java JRE
There is a bug in my code.
Does somebody have any experience on that topic and can me help to identify where the problem is located?
See below a minimal working example that demonstrates this. Note that I am using the broadcast address for simulating network packets that come from a real external host.
If everything goes right you should see three lines at the end (in this or a different order):
Thread-0 - packet received
Thread-1 - packet received
Thread-2 - packet received
public static void main(String[] args) throws Exception {
boolean useLocalhost = true;
InetSocketAddress addr;
String sendPacketTo = "192.168.1.255"; // we use broadcast so that packet comes from an real external address
if (useLocalhost)
sendPacketTo = "localhost"; // does not work (only listener 1 received packet)
addr = new InetSocketAddress(15002);
new MyThread(addr).start(); // Datagram socket listener 1
new MyThread(addr).start(); // Datagram socket listener 2
new MyThread(addr).start(); // Datagram socket listener 3
DatagramSocket so = new DatagramSocket();
so.setBroadcast(true); // does not change anything
so.connect(new InetSocketAddress(sendPacketTo, 15002));
so.send(new DatagramPacket("test".getBytes(), 4));
Thread.sleep(1000);
System.exit(0);
}
public static class MyThread extends Thread {
DatagramSocket socket;
public MyThread(InetSocketAddress addr) throws SocketException {
super();
setDaemon(true);
socket = new DatagramSocket(null);
socket.setReuseAddress(true);
socket.setBroadcast(true); // does not change anything
socket.bind(addr);
System.out.println("Listener started: " + socket.getLocalAddress());
}
public void run() {
byte[] buf = new byte[10];
DatagramPacket p = new DatagramPacket(buf, buf.length);
try {
socket.receive(p);
System.out.println(Thread.currentThread().getName() + " - packet received");
} catch (IOException e) {
e.printStackTrace();
}
}
}
192.168.1.255 is a broadcast address, so the datagram is broadcast, under the rules for UDP broadcast. 127.0.0.1 is a unicast address, so the packet is unicast. So you get different behaviour.
As #DavidSchwartz commented, your code is a mixture. Connecting to a broadcast address for example doesn't have a lot of meaning, and neither does binding to it. I think what you are looking for is multicast.
You can use multicast on localhost
However, there are several things you need to be careful of to make it work.
example:
lo0 (127.0.0.1)
en0 (192.168.0.111)
en1 (10.1.0.111)
for each interface 2 separate sockets, one for receiving, one for
sending. In the above example this means creating a total of 6
sockets.
Never bind() a socket that will send multicast UDP packets.
Always bind() a socket that will receive multicast UDP packets.
Never try to setsockopt() or reconfigure multicast sockets after you call bind()
Instead, when machine's interfaces change due to cables being unplugged/plugged,
destroy all send/receive multicast sockets and recreate them.
sample code:
iMulticastSocketInterfaceIPAddress would be one of the three interfaces
/* use setsockopt() to request that the kernel join a multicast group */
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr=inet_addr( "239.192.0.133" );
myAddress.sin_addr.s_addr = mreq.imr_multiaddr.s_addr;
mreq.imr_interface.s_addr=( htonl(iMulticastSocketInterfaceIPAddress) );
theErr = setsockopt( CFSocketGetNative( mSocketBroadcast ) ,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));