I'm going to set a simple socket connection between two android devices using internet.
There are two devices and two android app's , one of them is client app and another is server app.
When the apps run on a device it's all OK, but when the apps run on two devices the client application doesn't connect to server application.
Client app:
btnSend.setOnClickListener(view -> {
String msg = etMessage.getText().toString();
AsyncTask.execute(() -> {
try {
DatagramSocket socket = new DatagramSocket();
InetAddress ip = InetAddress.getByName("100.66.20.245");
int port = 1020;
DatagramPacket packet = new DatagramPacket(
msg.getBytes(), msg.length(), ip, port
);
socket.send(packet);
runOnUiThread(() -> {
Toast.makeText(this, "Message sent", Toast.LENGTH_SHORT).show();
});
} catch (Exception e) {
Log.w(TAG, e.toString());
}
});
});
Server app:
Runnable runnable = () -> {
try {
int port = 1020;
DatagramSocket socket = new DatagramSocket(port);
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer,1024);
runOnUiThread(() -> {
Toast.makeText(this,"Waiting for client",Toast.LENGTH_SHORT).show();
});
socket.receive(packet);
String msg = new String(packet.getData(),0,packet.getLength());
runOnUiThread(() -> {
Toast.makeText(this, "Client msg : " + msg, Toast.LENGTH_SHORT).show();
});
} catch (Exception e) {
Log.w(TAG, e.toString());
}
};
new Thread(runnable).start();
Are both devices connected to a network? And is the IP address of client application equal to the IP address of the server?
The best solution was the port forwarding with a router.
When you are using a router you can set an ip address to forwarding ports to that ip address.
However if you have a better solution, please post a comment :)
Related
hope your having a nice day . im building a Video Call application using XMPP and Jingle and direct ByteStream from phone to phone . in order to do so i noticed i need a stun server to get public ip and port of android devices and send them to the other party , im getting the public ip like this
InetAddress address = Inet4Address.getByName("stun.l.google.com");
MessageHeader sendMH = new
MessageHeader(MessageHeader.MessageHeaderType.BindingRequest);
ChangeRequest changeRequest = new ChangeRequest();
sendMH.addMessageAttribute(changeRequest);
byte[] data = sendMH.getBytes();
DatagramSocket s = new DatagramSocket(null);
localPort = s.getLocalPort();
s.setReuseAddress(true);
// s.bind(address);
DatagramPacket p = new DatagramPacket(data,
data.length,address,19302);
s.send(p);
DatagramPacket rp;
rp = new DatagramPacket(new byte[32], 32);
s.receive(rp);
MessageHeader receiveMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingResponse);
// System.out.println(receiveMH.getTransactionID().toString() + "Size:"
// + receiveMH.getTransactionID().length);
receiveMH.parseAttributes(rp.getData());
MappedAddress ma = (MappedAddress) receiveMH
.getMessageAttribute(MessageAttribute.MessageAttributeType.MappedAddress);
ip = ma.getAddress().toString();
port = ma.getPort();
Log.i("XMPP-Stabler",ma.getAddress().toString()+" "+ma.getPort());
s.close();
}catch (Exception e){
e.printStackTrace();
}
then i send the result to the other party and open up a SocketServer on this client using given port , but still i can not connect to this ServerSocket over internet , or probably i am doing some thing wrong ? can you please help me how should i use STUN or TURN results ? thanks
and here is my connecting side of Jingle just in case
otherTransport = (JingleS5BTransport)
jingle.getContents().get(0).getTransport();
ArrayList<JingleContent> contents = new ArrayList<>();
contents.add(content);
session = (JingleS5BTransportSession) JingleS5BTransportManager.getInstanceFor(connection).transportSession(new JingleSession(connection.getUser(),responderFullId,role,sessionId,contents) {
#Override
public XMPPConnection getConnection() {
return connection;
}
#Override
public void onTransportMethodFailed(String namespace) {
Log.i("XMPP-Stabler","transport method failed "+namespace);
}
});
session.setTheirProposal(otherTransport);
session.initiateOutgoingSession(new JingleTransportInitiationCallback() {
#Override
public void onSessionInitiated(BytestreamSession bytestreamSession) {
Log.i("XMPP-Stabler","ON SESSION INITIATED 2!");
Socks5BytestreamSession session = (Socks5BytestreamSession) bytestreamSession;
}
#Override
public void onException(Exception e) {
e.printStackTrace();
}
});
I try to create a Simple TCP Server on Android phone and waiting for client.
I only want to implement the connection between TCPServer and Client , it doesn't need to transmit any data.
I have the another application for client , It use to connect to this TCPServer.
The code of TCPServerthread is like the following.
private class TCPServerThread implements Runnable
{
#Override
public void run() {
// TODO Auto-generated method stub
try {
ServerSocket serverSocket = new ServerSocket(PORT);
//while loop
while (true) {
Log.i(TAG, "TCPServerThread...while loop");
try {
Socket socket = serverSocket.accept();
Log.i(TAG, "TCPServerThread...socket.getInetAddress() = " + socket.getInetAddress());
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
Log.i(TAG, "First IOException");
}
}
//while loop end
} catch (Exception e) {
// TODO: handle exception
//e.printStackTrace();
Log.i(TAG, "Second IOException");
}
}
}
But it seems stop at Socket socket = serverSocket.accept(); and doesn't show the log of TCPServerThread...socket.getInetAddress() = when the client try to connect to this Server.
DO I missing something for TCPServer ?
Is it mean the client doesn't connect to the Server when the code stop at Socket socket = serverSocket.accept(); ??
----------------------------EDIT----------------------------------------
Update the process.
The Server(Android Phone) open the WiFi-Hot-Spot, it also open the TCP-Server like the above code.
After Client connect to WiFi-Hot-Spot , the Client and the Server are in the same network.
The Client will get a IP address of gateway, and the Client try to connect to this IP address of gateway by TCP.
So the connection port and Server address seems correct for Client.
Your code is correct, but it seems that no one is connecting to your TCPserver.
To avoid this blocking situation on
Socket socket = serverSocket.accept();
you have to set the timeout option for your socket when you declare it
serverSocket.setSoTimeout(mTime);
;)
I want to implement service discovery by using the network's broadcast address. I am sniffing packets with WireShark to confirm that my UDP packets are not being sent. The network code is not being run on the UI thread. The DatagramSocket.send call returns with no exception thrown, but nothing is seen by other programs including WireShark. I have verified that the address returned by getWifiBroadcastAddress actually is the broadcast address of my network.
I have verified that the network supports broadcast by writing a C# program, run on another machine, and WireShark is detecting broadcast packets from this program.
Here is my Android Java code:
try {
DatagramSocket socket = new DatagramSocket(Protocol.INQUIRY_PORT);
socket.setBroadcast(true);
InetAddress broadcastAddr = getWifiBroadcastAddress();
byte[] data = new byte[10];
for(int i = 0; i < data.length; i++) {
data[i] = (byte) i;
}
DatagramPacket packet = new DatagramPacket(data, data.length,
broadcastAddr, Protocol.INQUIRY_PORT);
while(true) {
// Loops indefinitely, no errors/exceptions
socket.send(packet);
try {
Thread.sleep(5000);
} catch(InterruptedException ie) {
break;
}
}
} catch(IOException ioe) {
// Not logged
Log.d("Broadcast", "Error sending inquiry.");
}
The getWifiBroadcastAddress() method is as seen here: https://lab.dyne.org/AndroidUDPBroadcast
Does anyone know why this would fail silently? Like I said my C# program running on another box is working just fine, doing the same thing, sending the same data every 5s, and WireShark sees those packets, but nothing from the Android phone.
The following works for me, where I can broadcast a particular string value to a specified port (in your case Protocol.INQUIRY_PORT) on the other end(s), and all of the devices on the local subnet that are monitoring UDP on that port can recognize that string value, and accordingly can respond. I am broadcasting from the main thread, but listening for responses in an async task.
public void sendBroadcast(String messageStr) {
// Hack Prevent crash (sending should be done using an async task)
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
byte[] sendData = messageStr.getBytes();
try {
sendSocket = new DatagramSocket(null);
sendSocket.setReuseAddress(true);
//sendSocket.bind(new InetSocketAddress(Protocol.INQUIRY_PORT));
sendSocket.setBroadcast(true);
//Broadcast to all IP addresses on subnet
try {
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("255.255.255.255"), Protocol.INQUIRY_PORT);
sendSocket.send(sendPacket);
System.out.println(getClass().getName() + ">>> Request packet sent to: 255.255.255.255 (DEFAULT)");
} catch (Exception e) {
}
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.getMessage());
}
}
Following is the corresponding UDP response listener code inside an async task class:
protected String doInBackground(String... params) {
serverIP = "";
try {
//Keep a socket open to listen to all the UDP trafic that is destined for this port
InetAddress myHostAddr = InetAddress.getByName("0.0.0.0");
rcvSocket = new DatagramSocket(null);
rcvSocket.setReuseAddress(true);
rcvSocket.bind(new InetSocketAddress("0.0.0.0",Protocol.INQUIRY_PORT));
rcvSocket.setBroadcast(true);
while (true) {
Log.i("VIS","Ready to receive broadcast packets!");
//Receive a packet
byte[] recvBuf = new byte[15000];
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
rcvSocket.receive(packet);
//Packet received
serverIP = packet.getAddress().getHostAddress();
Log.i("VIS", "Packet received from: " + serverIP);
String data = new String(packet.getData()).trim();
Log.i("VIS", "Packet received; data: " + data);
if (!data.equals("") && !data.equals(myInquiryString)) {
//break while loop and return IP address of server
break;
}
}
} catch (IOException ex) {
Log.i("VIS", "ServerDiscovery" + ex.getMessage());
}
return serverIP;
}
I have to network devices:
1. Server (variable IP) that needs to receive a String for further stuff (e.g. Socket 9999). This server has also another socket (e.g. 8888) where it sends it's device name on pairing.
2. Client (variable IP) that does NOT know the IP of the server but wants to send him the string.
On a IP C-network I could iterate through the last octet (0..255) and check if Socket 8888 transmits something. But on A and B networks I have no chance. Is there any other solution for this? (I could iterate through all four octets but that wouldn't be an elegant solution).
Thank you!
The most appropriate way to do it, if they are in the same LAN is:
Client sends a UDP broadcast to a specific port and matching the network class (A,B,C)
Server is listening on this port, receives the broadcast packet and connect or send his IP to the client.
With just two network packets you know the IP address.
--EDITED--
To broadcast:
InetAddress broadcastAddr = SharedFunctions.getNetworkLocalBroadcastAddressdAsInetAddress();
DatagramSocket socket = null;
try {
socket = new DatagramSocket();
socket.setBroadcast(true);
System.arraycopy(BROADCAST_SIGNATURE, 0, buffSend, 0, BROADCAST_SIGNATURE.length);
DatagramPacket packet = new DatagramPacket(buffSend, buffSend.length, broadcastAddr, BROADCAST_PORT);
socket.send(packet);
} catch (Exception e) {
e.printStackTrace();
if(socket != null) try {socket.close();} catch (Exception e1) {}
}
public static InetAddress getNetworkLocalBroadcastAddressdAsInetAddress() throws IOException {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
if(VERSION.SDK_INT < 9) {
if(!intf.getInetAddresses().nextElement().isLoopbackAddress()){
byte[] quads = intf.getInetAddresses().nextElement().getAddress();
quads[0] = (byte)255;
return InetAddress.getByAddress(quads);
}
}else{
if(!intf.isLoopback()){
List<InterfaceAddress> intfaddrs = intf.getInterfaceAddresses();
return intfaddrs.get(0).getBroadcast(); //return first IP address
}
}
}
return null;
}
To receice broadcast:
try {
socketReceiver = new DatagramSocket(BROADCAST_PORT);
socketReceiver.setBroadcast(true);
DatagramPacket packet = new DatagramPacket(buffRecv, buffRecv.length);
while(Thread.currentThread() == cThreadReceiver){
socketReceiver.receive(packet);
//here you receive the packet and can check the sender IP address
}
} catch (Exception e) {
e.printStackTrace();
if(socketReceiver != null) try {socketReceiver.close();} catch (Exception e1) {}
}
You will need to do some editing but should start you in the right track.
WiBro, which is used as a server module and client Nexus Galaxy ICS.
Both machines are 3g UDP communication.
The server will return only the received data has been implemented.
dSocket.send (sendPacket) is a smooth communication.
However, we have a problem.
dSocket.receive (recvPacket) does not receive the data.
The server sends the packet is wrong? If the client receives the packet is wrong?
The server sends data but, telecom equipment is taken to preserve the situation?
When only sending a packet, the client has not a problem.
but after receive code implementation, the client has a problem.
private class ClientThread implements Runnable{
#SuppressWarnings("finally")
#Override
public void run() {
// TODO Auto-generated method stub
DatagramSocket dSocket = null;
try{
InetAddress serverAddr = InetAddress.getByName(serverIpAddress.toString());
Log.d(TAG, "Connecting");
Log.d(TAG, "IP :::: " + serverAddr.toString());
dSocket = new DatagramSocket(SERVERPORT);
dSocket.setSoTimeout(5000);
byte[] arr_RecvPacket = new byte[1024];
connected = true;
while(connected){
try{
Log.d(TAG, "Sending Command :::: ( " + String.valueOf(i));
String strPacket = "Hey Server ( " + String.valueOf(i);
byte[] arr_Packet = strPacket.getBytes();
sendPacket = new DatagramPacket(arr_Packet, arr_Packet.length, serverAddr, SERVERPORT);
dSocket.send(sendPacket);
Log.d(TAG, "C:Send");
i++;
Log.d(TAG, "C:Make Recv Packet....");
recvPacket = new DatagramPacket(arr_RecvPacket, arr_RecvPacket.length);
Log.d(TAG, "C:Recving...");
dSocket.receive(recvPacket);
handler.sendEmptyMessage(0x01);
Thread.sleep(4000);
}catch(Exception e){
e.printStackTrace();
Log.d(TAG, "S:Error");
}
}
Log.d(TAG, "S:DataSocket close");
dSocket.close();
}catch(Exception e){
Log.d(TAG, "C:Error");
e.printStackTrace();
connected = false;
}finally{
connected = false;
if(dSocket != null){
dSocket.close();
}
return;
}
}
}
The server sends the packet is wrong?
Could be. Hard to say without seeing it. It should send the reply back to the IP:port embedded in the incoming datagram. Easiest way to do that is to reuse it, just change the data.
the client receives the packet is wrong?
It looks OK.
The server sends data but, telecom equipment is taken
to preserve the situation?
I don't know what this means.