I tried setting the Multicast host as 230.0.0.1 using the port 5500. Then, on the other side I said to join group 230.0.0.1 at port 5500. It joined and it received packets for a few seconds. Then it stops all of a sudden. If I use 255.255.255.255 it receives packets normally. Why is this happening? The code for the Multicast sender is below:
private class StatusBroadcasterThread extends Thread
{
private static final boolean DEBUG = App.DEBUG;
private static final String TAG = "StatusBroadcasterThread";
private DatagramSocket broadcastSocket;
public StatusBroadcasterThread(int port) throws SocketException {
broadcastSocket = new DatagramSocket(port);
this.start();
}
#Override
public void run() {
while (!this.isInterrupted()) {
try {
byte[] buffer = status.toString().getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName(App.Config.multicastAddress),
App.Config.multicastPort);
broadcastSocket.send(packet);
if (DEBUG)
Log.d(TAG, "Sent: " + new String(packet.getData()));
} catch (IOException e) {
Log.e(TAG, "Error: " + e.getMessage());
}
try {
sleep(App.Config.broadcastInterval);
} catch (InterruptedException ex) {
}
}
}
}
Receiver thread:
private class ReceiverThread extends Thread
{
private static final String TAG = ComMessageReceiver.TAG + "Thread";
private WifiManager wifiManager;
private MulticastSocket multicastSocket;
private InetSocketAddress groupInetSocketAddress;
private boolean joinedGroup = false;
public ReceiverThread(String group, int port, int timeout) throws IOException {
super();
wifiManager = (WifiManager) App.context.getSystemService(Context.WIFI_SERVICE);
groupInetSocketAddress = new InetSocketAddress(InetAddress.getByName(group), port);
multicastSocket = new MulticastSocket(port);
multicastSocket.setSoTimeout(timeout);
}
public ReceiverThread() throws IOException {
this(Config.multicastAddress, Config.multicastPort, DEFAULT_TIMEOUT);
}
#Override
public void run() {
Log.d(TAG, "started");
while (!this.isInterrupted()) {
if (wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {
if (!joinedGroup) {
try {
multicastSocket.joinGroup(groupInetSocketAddress,
NetworkInterface.getByInetAddress(getWifiInetAddress()));
wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG);
wifiManager.createMulticastLock(TAG).acquire();
joinedGroup = true;
} catch (IOException ex) {
Log.e(TAG, "Failed to join Multicast group: " + ex.getMessage());
}
}
try {
byte[] buffer = new byte[256];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
multicastSocket.receive(packet);
Message message = new Message(packet);
Log.d(TAG, "message from " + message.getIp() + " " + message.getMsg());
for (MessageListener listener : listenerList)
listener.onMessageReceived(message);
} catch (SocketTimeoutException ex) {
Log.e(TAG, "Timed out: " + ex.getMessage());
} catch (IOException ex) {
Log.e(TAG, ex.getMessage());
}
} else
joinedGroup = false;
}
}
InetAddress getWifiInetAddress() throws UnknownHostException {
ByteBuffer wifiRawAddress = ByteBuffer.allocate(4);
wifiRawAddress.order(ByteOrder.LITTLE_ENDIAN).putInt(wifiManager.getConnectionInfo().getIpAddress());
return InetAddress.getByAddress(wifiRawAddress.array());
}
}
1. 255.255.255.255 is NOT a multicast address but BroadCast address.
2. Please check that you are properly closing the sockets when the communication is completed.
See below the list of all the multicast address..........
224.0.0.0 Base address (reserved)
224.0.0.1 The All Hosts multicast group addresses all hosts on the same network segment.
224.0.0.2 The All Routers multicast group addresses all routers on the same network segment.
224.0.0.4 This address is used in the Distance Vector Multicast Routing Protocol (DVMRP) to address multicast routers.
224.0.0.5 The Open Shortest Path First (OSPF) All OSPF Routers address is used to send Hello packets to all OSPF routers on a network segment.
224.0.0.6 The OSPF All D Routers address is used to send OSPF routing information to designated routers on a network segment.
224.0.0.9 The Routing Information Protocol (RIP) version 2 group address is used to send routing information to all RIP2-aware routers on a network segment.
224.0.0.10 The Enhanced Interior Gateway Routing Protocol (EIGRP) group address is used to send routing information to all EIGRP routers on a network segment.
224.0.0.13 Protocol Independent Multicast (PIM) Version 2
224.0.0.18 Virtual Router Redundancy Protocol (VRRP)
224.0.0.19 - 21 IS-IS over IP
224.0.0.22 Internet Group Management Protocol (IGMP) Version 3
224.0.0.102 Hot Standby Router Protocol version 2 (HSRPv2) / Gateway Load Balancing Protocol (GLBP)
224.0.0.107 Precision Time Protocol version 2 peer delay measurement messaging
224.0.0.251 Multicast DNS (mDNS) address
224.0.0.252 Link-local Multicast Name Resolution (LLMNR) address
224.0.1.1 Network Time Protocol clients listen on this address for protocol messages when operating in multicast mode.
224.0.1.39 The Cisco multicast router AUTO-RP-ANNOUNCE address is used by RP mapping agents to listen for candidate announcements.
224.0.1.40 The Cisco multicast router AUTO-RP-DISCOVERY address is the destination address for messages from the RP mapping agent to discover candidates.
224.0.1.41 H.323 Gatekeeper discovery address
224.0.1.129 - 132 Precision Time Protocol version 1 time announcements
224.0.1.129 Precision Time Protocol version 2 time announcements
Related
I am currently developing a client and a server for a small game.
The client which connects to the server establishes the connection with this method:
// This method is called, passing on an ipv6 address and port number 6666
public void startConnection(String ip, int port) throws IOException {
try {
clientSocket = new Socket(ip, port);
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
//some other code handling responses
} catch (IOException e) {
LOG.debug("Error when initializing connection", e);
throw new IOException();
}
}
The Server I built accepts connections using this method:
public void start(int port) {
try {
serverSocket = new ServerSocket(port); //port = 6666
//This part is used to handle multiple connections at once
while (b){
try {
map.add(new EchoClientHandler(serverSocket.accept())); //EchoClientHandler is a class used to send and receive data instructions
x = map.size() - 1;
System.out.println("Establishing connection from port " + port);
map.get(x).start();
System.out.println("Connection established");
} catch (SocketTimeoutException e) {
}
}
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Both methods work fine and establish a stable connection between the client and the server, but when i try and establish a connection from different routers or general internet connections (like via cellular data) it doesn't work.
Is there a way to establish connections without both the client and the server having to connect from the same router?
Edit:
Here is the error i get from the client, the server doesn't show anything:
18:03:24.288 [AWT-EventQueue-0] DEBUG dorusblanken.werwolfclient.Client - Error when initializing connection
java.net.SocketException: Network is unreachable: connect
"Network is unreachable" means there is no way to get to the destination network from the current network.
You mentioned that you are trying to establish a connection via the Internet. For that to work, the destination host (your server) must be connected to the Internet, it must have a public IP address, and the clients need to use the public IP address when connecting.
That is the simplest configuration. Most companies don't actually put their servers directly on the Internet. Instead, the public IP frequently belongs to a CDN or DDoS mitigation layer, which forwards connections to a load balancer, and the load balancer forwards connections to servers.
I am running a NanoHTTPD web server on an Android host device which is broadcasting a Wifi hotspot with no internet connectivity. My host application is advertising a TCP service through NsdManager that a client app connected to the Wifi hotspot will look for.
So far logging on the host device indicates that the server is starting and NSD service is registered properly. However, my phone app is not sending any requests to my web server that handles the service (the app doesn't find an available service). Logging shows that my host server's socket does not have an IP address. However, when my phone connects to the Wifi hotspot it obtains an IP address. Is there something special I am missing in order for the host itself to obtain an IP address on the hotspot network?
Here are my NanoHTTPD server startup functions:
#Override
public void start(final int timeout, boolean daemon) throws IOException {
super.start(timeout, daemon);
ServerSocket socket = getMyServerSocket();
if (!socket.isBound()) {
final InetAddress ip = InetAddress.getLocalHost();
final int port = getListeningPort();
socket.bind(new InetSocketAddress(ip, port));
if (DEBUG) {
Log.d(TAG, "Socket bound manually.");
}
}
if (DEBUG) {
final InetAddress ip = socket.getInetAddress();
final int port = socket.getLocalPort();
Log.d(TAG, String.format("Bound socket to %s:%d", ip.getHostAddress(), port));
}
initRegistrationListener();
registerService();
}
private void initRegistrationListener() {
mRegistrationListener = new NsdManager.RegistrationListener() {
#Override
public void onServiceRegistered(NsdServiceInfo aInfo) {
mServiceName = aInfo.getServiceName();
Log.d(TAG, "Nsd service registered: " + mServiceName);
}
#Override
public void onRegistrationFailed(NsdServiceInfo aInfo, int aErrorCode) {
Log.e(TAG, "Nsd service registration failed.");
}
#Override
public void onServiceUnregistered(NsdServiceInfo aInfo) {
Log.d(TAG, "Nsd service unregistered.");
}
#Override
public void onUnregistrationFailed(NsdServiceInfo aInfo, int aErrorCode) {
Log.e(TAG, "Nsd service unregister failed.");
}
};
}
private void registerService() {
final int port = getMyServerSocket().getLocalPort();
final InetAddress addr = getMyServerSocket().getInetAddress();
NsdServiceInfo serviceInfo = new NsdServiceInfo();
serviceInfo.setServiceName("MyTcpService");
serviceInfo.setServiceType("_my-service._tcp");
serviceInfo.setPort(port);
serviceInfo.setHost(addr);
mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
if (DEBUG) {
Log.d(TAG, String.format("Registered service at %s:%d.", addr.getHostAddress(), port));
}
}
Logcat output from running these functions:
11-06 10:56:31.814 2869 2869 D JsonServer: Socket is bound to :::48376
11-06 10:56:31.816 2869 2869 D JsonServer: Registered service at :::48376.
11-06 10:56:34.199 2869 3733 D JsonServer: Nsd service registered: MyTcpService
11-06 10:57:14.160 2869 3733 D JsonServer: Nsd service unregistered.
Any ideas why my bound ServerSocket has no IP address?
Android especially.
I will try to establish a connection between two devices (android - android) where one will create a server socket, connect the other device to the client, close the socket, and the connection between the two devices remains. So simple.
Server
#Override
public void onResume() {
super.onResume();
//// !!! only for test !!!
(new Thread(new Runnable() {
#Override
public void run() {
try {
int port = 33000;
SocketAddress allInterfaces = new InetSocketAddress("0.0.0.0", port);
ServerSocketChannel channel = MuxServerSocketChannelFactory
.openAndBindServerSocketChannel(null, allInterfaces, 3);
ServerSocket server = channel.socket();
Socket socket = server.accept();
Log.i("test", "host was connected!!!: " + socket.getInetAddress().getHostAddress());
callback.onConnected(socket);
server.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
})).start();
if (true) return;
//// !!! end test on real device !!!
}
Client
int privateServerPort = 33000;
int publicServerPort = 25000;
InetAddress privateServerIpAddr = InetAddress.getByName("172.23.9.120");
InetAddress publicServerIpAddr = InetAddress.getByName("xx.xx.xx.xx"); // correct IP address
Socket socket = new Socket(publicServerIpAddr, publicServerPort,
privateServerIpAddr, privateServerPort);
// never connected
The problem arises when these devices are not in one LAN or in one, but via a VPN. It is not possible to create this connection at this time.
I've been looking for a long time here (Stackoverflow), but it does not work for me. Some of the Libraries I tried:
Portmapper
// Discover port forwarding devices and take the first one found
List<PortMapper> mappers = PortMapperFactory.discover(networkBus, processBus);
PortMapper mapper = mappers.get(0);
// mappers always return null
Cling
final PortMapping desMapp = new PortMapping(
33000,
Tool.getLocalHost(false).getHostAddress(),
PortMapping.Protocol.TCP
);
UpnpService service = new UpnpServiceImpl(new AndroidUpnpServiceConfiguration());
RegistryListener registryListener = new PortMappingListener(desMapp) {
#Override
public synchronized void deviceAdded(Registry registry, Device device) {
super.deviceAdded(registry, device);
// this callback is never call
}
};
service.getRegistry().addListener(registryListener);
Collection<Device> all = service.getControlPoint().getRegistry().getDevices();
// the value all has 0 size
service.getControlPoint().search();
Thread.sleep(5000); // anything value
all = service.getControlPoint().getRegistry().getDevices();
// again the size is 0
Is there a really simple example of How the server and client should look?
All IP addresses and ports i know. I'm testing it on Huawei P9 Lite, Elephone P9000.
I do not work with UPnP, NAT and so on.
Thank you very much for your help.
It appears to me that newer Android devices run behind a NAT, where the local address is an internal carrier or LAN address and the public address is the router or carrier assigned external address.
Nevertheless, newer phones don't return the same address using the NetworkInterface as when accessing an IP detection service.
Therefore, connecting via direct P2P SocketChannels inherently fails.
Are there any common workarounds to this problem designed for the Android platform? Can anyone clarify what is causing this NAT-like security issue?
Any links to Java NAT traversal tutorials or examples (NOT essays or theses) would also be appreciated as being helpful (as I'm not quite sure how to implement it in Java).
I will of course also accept any other solutions anyone has to offer!
Almost every phone or PC you will ever touch won't have a static public IP address, and therefore will require NAT traversal. It's not because of the device; the carrier or ISP put routers between your device and the public internet. Depending on your application, usually there are NAT-traversal libraries you can use, such as ice4j or STUNT.
I do that in my own project and have found this issue is not that complicated.
Here's a very simple UDP echo server in node.js
var dgram = require('dgram');
var socket =
dgram.createSocket('udp4');
socket
.on('listening', function()
{
var address = socket.address();
console.log('socket listening ' +
address.address + ':' + address.port);
})
.on('error', function(err)
{
console.log('socket error:\n' + err.stack);
socket.close();
})
.on('message', function(message, rinfo)
{
console.log('message: ' + message + ' from ' +
rinfo.address + ':' + rinfo.port);
var msg = new Buffer(rinfo.address + ':' + rinfo.port);
socket
.send(msg, 0, msg.length,
rinfo.port, rinfo.address,
function(err, bytes)
{
//socket.close();
});
})
.bind(15000);
An android client simply send a msg to this node server
System.out.println("UDP hole punching=======================");
class IOth extends Thread {
#Override
public void run() {
String sendMsg = "UDP hole punching";
byte[] buf = sendMsg.getBytes();
DatagramPacket packet;
System.out.println(HPremoteHost); // node server IP
System.out.println(HPremotePort); // 15000
try {
packet = new DatagramPacket(buf, buf.length, InetAddress.getByName(HPremoteHost), HPremotePort);
ds.send(packet);
} catch (Exception e) {
System.out.println("error================");
System.out.println(e);
}
}
}
IOth io00 = new IOth();
io00.start();
Android Client UDP listener to obtain general msg and your own Global ip&port via UDPholepunching
class IOLoop extends Thread {
#Override
public void run() {
try {
String msg = "Native.UDPserver.open";
SocketAddress sockAddress;
String address;
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
while (true) {
try {
ds.receive(packet);
sockAddress = packet.getSocketAddress();
address = sockAddress.toString();
msg = new String(buf, 0, packet.getLength());
System.out.println(msg + " received !!! by " + address);
// this case is UDP HolePunching reaction
if (address.equals(HPaddress1)) {
System.out.println(msg + "hole punched");
// So you can obtain own Global ip& port here.
// exchange this information
// `remoteHost` `remotePort` to another client
// with some method (signaling server)
}
} catch (IOException e) {
}
}
} catch (Exception e) {
}
}
}
IOLoop io00 = new IOLoop();
io00.start();
Android Client UDP sender using other client's IP remoteHost remotePort
class IOth extends Thread {
#Override
public void run() {
String sendMsg = "This is a test message";
byte[] buf = sendMsg.getBytes();
DatagramPacket packet;
try {
packet = new DatagramPacket(buf, buf.length, InetAddress.getByName(remoteHost), remotePort);
ds.send(packet);
} catch (Exception e) {
}
}
}
IOth io00 = new IOth();
io00.start();
Look at http://sourceforge.net/projects/jnat-pmplib/
It is an implementation of NAT-PMP in java.
I've managed to establish sockets just by forwarding the sockets you're using during the connection in your router. It worked for me.
UPDATE
Find out your IP address through cmd.exe if your using Windows (ipconfig) or through a terminal session if your on Linux (ifconfig). Then connect to it through the browser and there should be a security section. Go to port forwarding and open up the ports your using when establishing you're ServerSocket and Socket. Use TCP as the protocol.
Please note that this only applies if you're trying to connect from outside your wlan.
I'm currently using a Java implementation of the Reliable UDP protocol, found here. The project has absolutely no tutorials so I have found it really hard to identify problems.
I have set up a client and server. The server runs on localhost:1234 and the client runs on localhost:1235. The server is first established, and loops listening for connections -
try {
ReliableSocket clientSocket = server.socket.accept();
InetSocketAddress clientAddress = (InetSocketAddress) clientSocket.getRemoteSocketAddress();
Logger.getLogger("ServerConnectionListener").info("New Connection from "+
clientAddress.getHostName()+":"+clientAddress.getPort()+" Processing...");
LessurConnectedClient client = new LessurConnectedClient(clientSocket);
ClientCommunicationSocketListener listener = new ClientCommunicationSocketListener(this, client);
clientSocket.addListener(listener);
} catch (Exception e) {
e.printStackTrace();
}
When a connection is established, it creates a listener for events on that socket -
class ClientCommunicationSocketListener implements ReliableSocketListener {
ServerConnectionListener connectionListener;
LessurConnectedClient client;
public ClientCommunicationSocketListener(ServerConnectionListener connectionListener, LessurConnectedClient client){
this.connectionListener = connectionListener;
this.client = client;
}
#Override
public void packetReceivedInOrder() {
connectionListener.server.handlePacket(client);
}
#Override
public void packetReceivedOutOfOrder() {
connectionListener.server.handlePacket(client);
}
}
When a packet is received, it passes it to server.handlePacket, which performs a debug routine of printing "Packet Received!".
My client connects to the server as so -
LessurClient client = new LessurClient();
InetSocketAddress a = (InetSocketAddress) server.getSocket().getLocalSocketAddress();
Logger.getLogger("client-connector").info("Trying to connect to server "+
a.getAddress().toString()+":"+
a.getPort());
client.connect(a.getAddress(), a.getPort());
// LessurClient.connect
public void connect(InetAddress address, int port){
try {
socket = new ReliableSocket(address, port, InetAddress.getLocalHost(), 1235);
isConnected = true;
Logger.getLogger("LessurClient").info("Connected to server "+address.getHostAddress()+":"+port);
} catch (IOException e) {
e.printStackTrace();
}
}
I have linked my code so when I press the key 'Z', it will send a packet to the server as so -
public void sendPacket(GamePacket packet){
if(!isConnected){
Logger.getLogger("LessurClient").severe("Can't send packet. Client is not connected to any server.");
return;
}
try {
OutputStream o = socket.getOutputStream();
o.write(packet.getData());
o.flush();
Logger.getLogger("LessurClient").info("Sending Packet with data \""+packet.getData()+"\" to server "+socket.getInetAddress().toString()+":"+socket.getPort());
} catch (IOException e) {
e.printStackTrace();
}
}
My problem is, after sending 32 packets, the server no longer receives packets, and after sending 64 packets, it crashes. I have investigated into the code, and it appears that its something associated with packets not being removed from the receive queue, as when I changed the _recvQueueSize variable in ReliableSocket.java:1815 from 32 to 40, I could now send 40 packets without something going wrong.
Could someone help me identify this issue? I've been looking at the code all day.
I managed to fix the problem.
You see, since this is an implementation of RUDP, it extends most of the Socket classes. Specifically, ReliableSocket.getInputStream(), was custom coded to a managed input stream. My problem was, I was receiving the packets, but not reading from the buffer.
When you receive a packet you're supposed to read from the buffer, otherwise the packet will not be dropped from the queue.
So all I had to do, was everytime I received a packet, read the size of the packet, and continue.