I'm developing an Android app that at some points, sends a multicast message. I'm running this on an emulator device so far.
On the same machine, I have a server (not Android, a plain Java app) that is expecting the multicast message, but it never gets it. When I start the server, since it is on my local machine, I start it the loopback interface (127.0.0.1). I must say that I've done this with regular Java apps and it works perfectly.
Here's the code for the Android App:
try {
InetAddress group = InetAddress.getByName(MULTICAST_HOST);
byte[] data = DISCOVER_MESSAGE.getBytes();
DatagramSocket ds = new DatagramSocket();
ds.setSoTimeout(60000);
DatagramPacket dp = new DatagramPacket(data, data.length, group, TcpipSIBDiscoverer.PORT);
ds.send(dp);
byte[] buf = new byte[1024];
dp = new DatagramPacket(buf, buf.length);
ds.receive(dp);
if (dp.getLength() > 0) {
byte[] tmp = new byte[dp.getLength()];
System.arraycopy(dp.getData(), 0, tmp, 0, tmp.length);
String received = new String(tmp);
Logger.debug(this, "Received from SIB: " + received);
SIBDescriptor sibDescriptor = createSIBDescriptor(received);
this.discoveryListener.connectorSIBDiscovered(sibDescriptor);
}
} catch (SocketTimeoutException e) {
Logger.error("Socket time excedeed while waiting a response when discovering SIBs. Trying again");
} catch (IOException e) {
Logger.error("There was some kind of IO error while waiting for a response when discovering SIBs. Trying again");
}
As you can see, I'm using a regular DatagramSocket instead of MulticastSocket. This works in plain Java apps, since the listening server address is 235.0.0.1:5555.
Not really sure if the code is not working or I have to do something in the emulator device so it can truly reach my loopback interface... Any ideas?
Thanks!
Alex
127.0.0.1 on android refers to the device's localhost (or the emulators).
To reach localhost of your 'local machine' you should use 10.0.2.2.
This is discussed in a lot of topics.
Related
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 am using the below code to send text message between two android devices but i could not receive the packet at the receiver side
the sender:
String messageStr="Hello Android!";
Log.d("note","message prepaered");
int server_port = 12345;
try{
Log.d("note","socket prepaered");
DatagramSocket s = new DatagramSocket();
Log.d("note","socket defined");
InetAddress local = InetAddress.getByName(ip.getText().toString());
int msg_length=messageStr.length();
byte[] message = messageStr.getBytes();
Log.d("note","converting message to bytes");
DatagramPacket p = new DatagramPacket(message, msg_length,local,server_port);
s.send(p);
Log.d("note","sending msg");}
catch (SocketException e){
Log.d("error",e.getMessage());
}
catch(IOException v1){
Log.d("error", v1.getMessage());
}
the receiver :
String text;
int server_port = 12345;
byte[] message = new byte[1500];
try{
DatagramPacket p = new DatagramPacket(message, message.length);
Log.d("note","putting msg in packet");
DatagramSocket s = new DatagramSocket(server_port);
Log.d("note","defining socket");
s.receive(p);
Log.d("note","recieving packet");
text = new String(message, 0, p.getLength());
msg.setText(text);
s.close();
}
catch (SocketException e){
Log.d("error",e.getMessage());
}
catch(IOException v1){
Log.d("error", v1.getMessage());
}
thanks in advance for help
Ok. There are a lot of undefined variables in your story.
First of all, you should try this at a local machine, where you can be sure that this is not a network problem.
Second, try to wrap the receiving code in a endless loop, it will make the debugging easier.
If by now, you found out that your code is actually working on a localhost,
you should check your network configuration on your devices, make sure you are using the right addresses, and both devices are in the same network.
If you have trouble making your code work on a localhost, try to test your server and client independently on a working software, like http://sourceforge.net/projects/sockettest/ for example, it will allow you to make sure that your client and server code is working
Also don't forget about the timing, start your receiver first.
P.S. Please format your code properly.
I wrote a java program that is able to send/receive messages via a multicast address.
My code for multicast sender:
public boolean multicastSender(DataTransferObject message) {
try {
InetAddress group = InetAddress.getByName(ip);
MulticastSocket s = new MulticastSocket(port);
s.joinGroup(group);
String msg = jsh.dtoToJsonString(message);
DatagramPacket data = new DatagramPacket(
msg.getBytes(), msg.length(), group, port);
s.send(data);
s.leaveGroup(group);
return true;
} catch (IOException e) {
System.out.println(e.toString());
e.printStackTrace();
return false;
}
}
My code for multicast receiver:
public DataTransferObject multicastReceiver() {
try {
InetAddress group = InetAddress.getByName(ip);
MulticastSocket s = new MulticastSocket(port);
s.joinGroup(group);
byte[] buffer = new byte[1000 * 1024];
DatagramPacket data = new DatagramPacket(buffer, buffer.length);
String jsonData;
DataTransferObject dto;
while (true) {
s.receive(data);
jsonData = new String(buffer, 0, data.getLength());
dto = jsh.dtoFromJson(jsonData);
if (dto == null) {
continue;
} else {
return dto;
}
}
} catch (IOException e) {
System.out.println(e.toString());
e.printStackTrace();
return null;
}
}
My program has 4 parallel threads that listen and receive messages from four different multicast addresses (224.0.0.[1->4]) and ports [66601->66604]. In the test, I run two programs at the same time to test the communication between them. Yet I discovered that sometimes, program A sends a message to a multicast address, in a correct case, A will also receive it and so will B. But sometimes, I see that A announced that it sent the message but after that, neither A or B receive it again. I run the test on my local machine (Mac OS 10.9 with core 2 duo) . Should this problem because of my computer or something else?
Thank you very much.
I've seen this happen in a Windows environment. I understand that it's because the network layer is separate from the JVM.
What this means is one JVM may read and process/discard this message, yet other JVM's won't read the same message as the network layer has already delivered the UDP message to the first consumer, no matter how many JVM's have subscribed to the same group. This may or may not be a bug in the operating system - it's very subjective. Personally I think the OS should track registrants in order to replicate the delivery, as that's the intention of clients - it's a bit misleading to think otherwise given that an application is joining a group to receive multicasts. The operating system should take this into consideration.
I have come to this conclusion through empirical evidence, and may not be true for other platforms.
UDP, which I guess underlies your multicast implementation, does not guarantee delivery. The receiver or network will drop packets when overloaded. You'll need a higher-level protocol to ensure delivery (google reliable multicast).
I'm making a system for reading smart-cards. The reader devices send out udp packets. Wireshark can see the packets but it says that they have an incorrect frame check sequence. This is on Windows 7, while on Debian it works flawlessly. I tried adding rules, for the specific ports used, to the firewall... even disabled it altogether... no joy :/
I wrote this bare bones code that should verify that the packets are reaching the java app :
try {
DatagramSocket s = new DatagramSocket(null);
InetSocketAddress address = new InetSocketAddress("192.168.1.100",8888);
s.bind(address);
byte buffer[] = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while(true)
{
System.out.println("Waiting...");
s.receive(packet);
System.out.println("Received!");
}
} catch (Exception e) {
e.printStackTrace();
}
It seems that they aren't ... any ideas?
I am trying to send data from a C#.NET (Windows Application) program to a Java (Android App) program and vice versa, via TCP connection through Wifi. Till now I am success to send data from Java to C#, but unable to do so from C# to Java.
Following is the Java code, I used to create a connection and receive data:
ServerSocket serverSocket = null;
DataInputStream socketInputStream;
while (true) {
try {
String localIPAddr = getLocalIPAddress();
InetSocketAddress ipEndPoint = new InetSocketAddress(
InetAddress.getByName(localIPAddr), 8222);
serverSocket = new ServerSocket();
serverSocket.bind(ipEndPoint, 4);
workerSocket = serverSocket.accept();
socketInputStream = new DataInputStream(
workerSocket.getInputStream());
inputText.setText(socketInputStream.readUTF());
} catch (Exception ex) {
throw ex;
}
}
Here getLocalIPAddress() method returns the IP Address of the Android Device.
Following is the C# code in Windows Application to connect to the Android's IP Address (192.168.1.6) and send data to it:
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
void button1_Click(object sender, EventArgs e)
{
try
{
if (!clientSocket.Connected)
clientSocket.Connect(IPAddress.Parse("192.168.1.6"), 8222);
clientSocket.Send(Encoding.UTF8.GetBytes(txtInput.Text));
}
catch (Exception ex)
{
throw ex;
}
}
Well, client (C#) is failing to connect to the server (Java) That means data is not leaving from client. But it will, if it get connected. Please tell me what am I missing and where am I mistaken. :)
After you have launched your android app and it is connected to the wifi, did you try to do a ping to the ip where the application is launched.
ping 192.168.1.6
If the IP is accessible from the workstation where C# app is running, try to perform a telnet on the IP and Port of the android ip, to see whether it works or not.
telnet 192.168.1.6 8222
If either of the two steps fail then could be a problem in the wifi network. As i have noticed many times the firewall of the routers filters out all the ports except 8080 and 80. So you would need to open the ports on the router.
Did you try to do this?
Runnable showmessage = new Runnable() {
public void run() {
myTextView.setText(membervariabletext);
}
};
and from your thread, after the readUTF(), call
runOnUiThread(showmessage);
Found this here
Well, I have solved this myself, but of course Dilberted has helped me a little bit. I thank him for what he has provided. :)
Check out the solved Java code below:
ServerSocket serverSocket = null;
Socket workerSocket;
DataInputStream socketInputStream;
try {
if (serverSocket == null) {
// No need to get local IP address and to bind InetSocketAddress.
// Following single line make it very simple.
serverSocket = new ServerSocket(8222, 4);
workerSocket = serverSocket.accept();
}
// When data are accepted socketInputStream will be invoked.
socketInputStream = new DataInputStream(
workerSocket.getInputStream());
/* Since data are accepted as byte, all of them will be collected in the
following byte array which initialised with accepted data length. */
byte[] rvdMsgByte = new byte[socketInputStream.available()];
// Collecting data into byte array
for (int i = 0; i < rvdMsgByte.length; i++)
rvdMsgByte[i] = socketInputStream.readByte();
// Converting collected data in byte array into String.
String rvdMsgTxt = new String(rvdMsgByte);
// Setting String to the text view.
receivedMsg.setText(rvdMsgTxt);
} catch (Exception ex) {
throw ex;
}
Note that a separate thread is to be used to run this code in background.