I'm writing a Network Framework prototype in Java using UDP to deal with moments where a device using it might not have a permanent and/or reliable connection and how it should deal with it. It is required that I have to be able to use it with "normal" IPv4 and IPv6 addresses as well as IPv6 LinkLocal Addresses.
Due to the concept there's moments where the device loses connectivity and i have to close all DatagramSockets binded to a specific IP/Port pair so i can free resources and, once the device gets a new connection, i need to "rebind" the sockets to the given Addresses.
There's no problems with the code when I'm testing with "normal" IPv4 and IPv6 addresses but once i start using IPv6 LinkLocal addresses I get this exception when I try to rebind a DatagramSocket to any LinkLocal address:
java.net.BindException: Cannot assign requested address (Bind failed)
at java.base/java.net.PlainDatagramSocketImpl.bind0(Native Method)
at java.base/java.net.AbstractPlainDatagramSocketImpl.bind(AbstractPlainDatagramSocketImpl.java:131)
at java.base/java.net.DatagramSocket.bind(DatagramSocket.java:394)
Since this code works for non LinkLocal Addresses i assumed it would work for LinkLocal addresses too.
Here's the code i use to bind a DatagramSocket to a IP/Port pair:
private void bindDatagramSocket() {
try {
this.ds = new DatagramSocket(null);
InetSocketAddress isa = new InetSocketAddress(this.ip, this.port);
this.ds.bind(isa);
this.hasConnection = true;
}
catch (SocketException e) {
e.printStackTrace();
}
Where this.ip and this.port are updated by another Thread that detects a change in the available Addresses and connection status (with/without connection).
When a connection loss is detected I use this code to close the DatagramSocket in use (this.ds)
public void updateConnectionStatus(boolean value){
this.connectionLock.lock();
this.hasConnection = value;
this.connectionLock.unlock();
if(value && !this.isRunning){
new Thread(this).start();
}
else{
if(!value) {
this.ds.close();
this.ds = null;
}
}
Any suggestions are appreciated
TL;DR: Using DatagramSockets to bind to an IP/Port pair corresponding to a IPv6 LinkLocal Address, closing that DatagramSocket and rebinding it to the same IPv6 LinkLocal Address results in Exception even though the same code works for any other case I can test with "normal" IPv4 and IPv6 Addresses
Related
I'm trying to create a local server with Wi-Fi P2P between an Android phone and a Raspberry Pi, with the Android as the host. I have been able to successfully establish a P2P connection using wpa_cli on the Pi, but now I am trying to use a C client socket to connect to the phone and transfer data. However, the line Log.d("Socket waiting", serverSocket.getLocalSocketAddress().toString()); spits out D/Socket waiting: ::/:::8888. It doesn't seem to have an address at all, so how am I supposed to connect to it?
As indicated by my comment, my research told me that the correct IP should be 192.168.49.1. If the IP were any different, that would be okay, because I can just send a BLE packet to the phone, telling it the IP. My issue is that the IP is entirely blank.
My code is as follows, for a thread that waits on a connection:
public static class DataTransfer extends Thread {
#Override
public void run() {
Log.d("DataTransfer", "Start");
ServerSocket serverSocket = null;
try {
/**
* Create a server socket and wait for client connections. This
* call blocks until a connection is accepted from a client
*/
// Expects a connection at 192.168.49.1:8888
serverSocket = new ServerSocket(8888);
//serverSocket.setReuseAddress(true);
//serverSocket.toString()
Log.d("Socket waiting", serverSocket.getLocalSocketAddress().toString());
Socket client = serverSocket.accept();
InputStream inputstream = client.getInputStream();
Log.d("InputStream Available", String.valueOf(inputstream.available()));
serverSocket.close();
}
catch (IOException e) {
Log.e("Receive Error", e.getMessage());
if(serverSocket != null) {
try {
serverSocket.close();
} catch (IOException ex) {
Log.e("Failed to close socket", ex.getMessage());
}
}
return;
}
}
}
And here is the output of ip a on the Pi, once it is connected via Wi-Fi P2P
11: p2p-wlan0-8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether b2:0e:07:e6:e6:55 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.23/24 brd 192.168.1.255 scope global noprefixroute p2p-wlan0-8
valid_lft forever preferred_lft forever
inet6 fe80::e79c:33f3:6e49:b6ed/64 scope link
valid_lft forever preferred_lft forever
Final edit:
My problem was seemingly unrelated. As both comments below indicate, the IP shown off is fine, it just means it accepts connections from anything. My actual issue was that I had a static IP set up on my Pi without specifying which interface the static IP was for. The client needed to be on a 192.168.49.# address, and the static IP was preventing it.
You can specify the interface the server socket is listening on by passing an address to the constructor:
serverSocket = new ServerSocket(8888, 10, InetAddress.getByName("192.168.49.1"));
Seeing :: means your server was listening for IPv6 connections on all interfaces. That is represented by the IPv6 address of all zeros which can be written as ::. But you are trying to connect to an IPv4 address, not IPv6. Most systems I've worked with are configured so that IPv4 connections can be accepted by an IPv6 server, but I guess yours isn't. The answer to this question suggests you may be able to change your system's behavior with sysctl:
sysctl net.ipv6.bindv6only=0
:: is the IPv6 default route. It indicates that you are serving requests from all interfaces.
This is the expected behavior. Is there a problem with that?
Hy guys, my code here to create a simple server works fine with the local host address(127.0.0.1). Here is my code.
import java.io.*;
import java.net.*;
public class Main {
public static void main(String[] args)
{
Zig z = new Zig();
z.start();
}
}
class Zig
{
ServerSocket ss = null;
InetAddress ia = null;
Socket s = null;
private static final int prt = 56540;
Zig()
{
try
{
byte[] addr = {127,0,0,1};
ia = InetAddress.getByAddress(addr);
SocketAddress sa = new InetSocketAddress(ia,prt);
ss = new ServerSocket();
ss.bind(sa);
s = ss.accept();
}
catch (IOException e)
{
e.printStackTrace();
}
}
Zig start()
{
try
{
InputStream i = s.getInputStream();
InputStreamReader isr = new InputStreamReader(i);
BufferedReader br = new BufferedReader(isr);
String str = null;
while (str != "stp")
{
str = br.readLine();
System.out.println(str);
}
br.close();
isr.close();
i.close();
s.close();
ss.close();
}
catch (IOException e)
{
e.printStackTrace();
}
return this;
}
}
My question is, how can I use the router's IP - 192.168.8.1 instead of 127.0.0.1? I also tried the IP address from http://whatsmyip.org but still got this exception:
java.net.BindException: Cannot assign requested address: JVM_Bind
at java.net.DualStackPlainSocketImpl.bind0(Native Method)
at java.net.DualStackPlainSocketImpl.socketBind(DualStackPlainSocketImpl.java:106)
at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:387)
at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:190)
at java.net.ServerSocket.bind(ServerSocket.java:375)
at java.net.ServerSocket.bind(ServerSocket.java:329)
at Zig.<init>(Main.java:26)
at Main.main(Main.java:8)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Exception in thread "main" java.lang.NullPointerException
at Zig.start(Main.java:38)
at Main.main(Main.java:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
I wanted to create a simple server with that i can access remotely with another computer both having internet connection.
Or is there a way I can make communication between two computers over internet?
Regards.
how can I use the router's IP - 192.168.8.1
You cannot use the router's IP. You should use the IP thats available in the system.
Note this error :
> java.net.BindException: Cannot assign requested address: JVM_Bind
The bind is failing because the address isn't that of the system.
If you want your 2 devices to communicate via LAN (local network) you can use the addresses your router assigned to these devices (that's the 192.168.8.X address you mentioned. EDIT: As Prabhu mentioned, use the devices IP Address, not the routers IP-Address! You can usually find the IPs your router assigned to connected devices in your routers admin-interface). Remember that your router might assign a different adress to the same devices in the future. Most routers come with a function that always assigns the same IP to a specific device. Also, some routers block communication between local devices (i.e. between wired and WiFi devives) for security reasons. Check your router's configuration for more information and configuration options!
If you want your devices to connect via internet you have to use your routers global IP-address (thats probably the one you found out using whatsmyip).
Additionally, your router usually just blocks incoming requests from the internet for security reasons. Again, your Router probably has a function called Port forwarding, which allows you to redirect requests to a specific device (and a specific port at that device) in your local network. Use this with care, as this opens (a part) of your routers built-in security mechanisms.
Finally, depending on your provider, you may have a IPv4 address (see Wikipedia) that you share with other customers (So called DS-Lite (Wiki). In this case, you're network is not reachable from the IPv4-internet at all and your only chance is to use the IPv6 Protocol (if available).
Hope that helps.
I'm trying to make a basic datagram client/server program with Java.
I've made the server cling to port 9321 on my local computer.
I've made the client on port 9320 on my local computer,
then send the data over wireless router network (192.168.1.100) at port 9321
the program works!
then i try to send the packet over (via router)internet IP 139.195.12.183(my ip) at port 9321
but it didnt work!
there is this exception:
java.net.SocketException: Interrupted function call: Datagram send failed
i've set the router to forward any request for port 9321 to my computer
and then i've set exception for the firewall on my computer on that port
this is the source
String SERVER = "139.195.12.183";
sendString(SERVER, 9321, "Greetings"); <<
private void sendString(String IP, int port, String toSend) {
byte[] buf = toSend.getBytes();
DatagramPacket packet = null;
try {
packet = new DatagramPacket(buf, buf.length, InetAddress.getByName(SERVER), port);
ds.send(packet);<<
}catch(UnknownHostException e) {
System.out.println("unknownhostception");
}catch(IOException e) {
System.err.println("ioception "+e.getMessage());
}
}
i've had another answers from another forum it said:
"The way routers work, you can't see your external (WAN) internet address from your
internal network (LAN). If that's what you are trying to do, there's nothing wrong, it
just won't work.
Ian."
any explanation?
Some steps that you can take:
Check that the code works across two machines on your LAN.
Check that ping <target-ip> works on your machine.
If it does, check your local and LAN firewall settings for blocking on the port/protocol.
If the ports are unblocked change the port to something else. Some ISPs will block certain ports.
Some more reasons why this error could come up:
UDP (I Assume?) datagram too large.
Client side error that doesn't affect reception (Have seen similar things with some network stacks where the error was spurious.)
Post a link to your code from patsebin or something if you want more info.
I need to change the IP address of a host from a client.
I use UDP commands and a MulticastSocket to obtain the IP address of this host (currentIp) and use this IP address to successfully establish a TCP connection.
The command to change this host IP address requires a DatagramSocket since I need to first get the host device MAC address to include in the change IP address command. Once the TCP connection is made I close the MulticastSocket UDP socket so I can open the DatagramSocket but get the following error:
java.net.BindException: Cannot assign requested address: Cannot bind
Is there something I need to do besides close the MulticastSocket socket before trying to get a DatagramSocket socket with the same port number, or is am I missing something else?
DatagramSocket socket;
private boolean ChangeIpAddress(String newIp) {
DatagramSocket socket;
try {
socket = new DatagramSocket(30718, InetAddress.getByName(currentIp));
} catch (SocketException ex) {
...
It appears you are using a hostname with an incorrect IP address. You need to find you etc/hosts or where ever its defines.
In my case, I have changed the listening address to 127.0.0.1 (localhost) and the problem is fixed
What I'd like to achieve
bind a server to an ephemeral port for unit testing purposes.
My issue :
Using the 1.5.0_22 JDK I try to bind an InetSocketAddress on an ephemeral port using port 0 as per the javadoc but I can't find a way from the address object to know which port it has binded to, so I cannot have my clients configured accordingly:
InetSocketAddress address = new InetSocketAddress(0);
assertThat(address.isUnresolved(), is(false));
assertThat(address.getPort(), is(0));
I might not understand the javadoc sentence correctly :
A valid port value is between 0 and 65535. A port number of zero will
let the system pick up an ephemeral port in a bind operation.
But checking the port even after having my server listening to the socket (I'm assuming the binding had happened then) does not returns anything else but 0 (the following uses the http://simpleweb.sourceforge.net/ library) :
Container httpServer = new Container() {
public void handle(Request req, Response resp) {
}
};
SocketConnection connection = new SocketConnection(httpServer);
InetSocketAddress address = new InetSocketAddress(0);
connection.connect(address);
assertThat(address.isUnresolved(), is(false));
assertThat(address.getPort(), is(0));
Using nmap I don't even see a binded port so I'm assuming my understanding is incorrect. Any help?
The InetSocketAddress that initially contains port 0 is not updated by connect() to represent the actual port that was bound to. Call connection.getLocalPort() or ((InetSocketAddress)connection.getLocalSocketAddress()).getPort() instead to get the bound port.