I'm programming a game in Android that uses AI, which requires big CPU power, that a normal Android device just doesn't have. So I decided to write a server in Java using sockets that will calculate everything and return a value to the client (the android device).
Now, I'm used to program for PC, but not for phones. In mobile, the IP of the device can change back and forth due to data roaming and WIFI.
My question is, how do you handle a changing IP? How do you tell a new connection is the same device? Or maybe the Android device does all of that automatically?
I'm new to stackoverflow, I hope I didn't ask too many questions. :)
Thank you very much for your answers!
You don't need to handle ip changing at all. A client(an android device) must know server host/ip and reconnect if it was disconnected from network, nothing more.
private static class ConnectionTask implements Runnable {
private boolean connected;
#Override public void run() {
try {
InetAddress serverAddress = InetAddress.getByName("host");
Socket socket = new Socket(serverAddress, 9999);
connected = true;
while (connected) {
// sending or writing data
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
//here you lost the connection due to some reason
//you need to notify user about the problem and wait for connection
}
}
}
To receive event about network state you need to register receiver:
context.registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (isNetworkAvailable()) {
unregisterReceiver(this);
tryToConnect();
}
}
}, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
Okay guys I figured out a way, thank to Fox in socks' answer.
Each time a user connects to the server socket, you take his UUID (or an hashed version of it, if you want more security :P ).
Then, when that user disconnects for some reason and tries to connect to the server socket again, he'll send the same UUID. That way, you can tell both of the connections are the same, and continue with the processing.
For more information about UUID, look here:
Is there a unique Android device ID?
Thank you all! :)
Now how do I mark this question as a closed one? :P
Related
I have a wear-os standalone application written in java, which connects as client (org.java_websocket.client.WebSocketClient) via WLAN websockets to a server (org.java_websocket.server.WebSocketServer) running on the smartphone (TicWatch Pro 3). When I run the code, everything works fine (web sockets connect) as long as the smartwatch is charging. As soon as I disconnect the charger and try to connect the smartwatch client via websockets to the smartphone server no connection can be established. No error is shown, there is simply no connection established.
This is a simplified version of the Runnable class used to start the web socket client.
public class BackgroundReceiverThread implements Runnable {
public static void startBackgroundReceiver(){
AsyncTask.execute(new BackgroundReceiverThread());
}
private BackgroundReceiverThread() {}
//#Override
public void run() {
try {
client=new BackgroundReceiverClient(new URI("ws://localhost:8887"));
client.connect();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
The BackgroundReceiverClient class looks the following:
public class BackgroundReceiverClient extends WebSocketClient {
public BackgroundReceiverClient(URI serverUri) {
super(serverUri);
}
#Override
public void onOpen(ServerHandshake serverHandshake) {
Log.i("mytag","On Open");
}
#Override
public void onError(Exception e) {
Log.i("mytag","On Error:"+e.getMessage());
}
}
When the smartwatch is charging and BackgroundReceiverThread.startBackgroundReceiver() is invoked, the onOpen() method is invoked. When the charger is disconnected the onOpen() method is not invoked.
I assume this is due to energy saving precautions of the smartwatch, which are activated when not charging. I have already tried to identify the respective setting on the smartwatch but couldn't find it.
How can I get the client connecting to the server when the smartwatch is not charging?
I had a fairly similar problem, I was trying to connect via Socket.IO with my Ticwatch E2 and it only worked when charging. After searching for all kinds of energy saving precautions that I could disable the real problem after all was this:
My Ticwatch automatically connects with my phone via Bluetooth and uses the wi-fi my phone is connected to through my phone (You can see the connection status in the Wear OS app on your phone). In order to establish a Socket Connection, the watch needs to be connected to the wi-fi itself. It does not do that by default when connected to your phone.
You can easily test this hypothesis by enabling flight mode on your phone and try the application on your Ticwatch again, it worked for my socket.IO application.
I'm currently developping my first app in java.
This app requires a direct connection with my BL652, which doesn' t accept any kind of pairing option. That being said, I'm stuck with the code below, which still tries to pair with my bluetooth device instead of just connecting. Therefore, I wanted to know what am i supposed to do in order to make a connection that doesnt require pairing.
Thanks in advance for any response.
String mac_address = "DA:72:21:29:0F:F0";
private static final UUID MY_UUID = UUID.fromString("E54B0002-67F5-479E-8711-B3B99198CE6C");
lvNewDevices.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
BluetoothDevice device = (BluetoothDevice) mBluetoothAdapter.getRemoteDevice(mac_address);
try {
socket = device.createInsecureRfcommSocketToServiceRecord(MY_UUID);
socket.connect();
} catch (IOException e) {
e.printStackTrace();
}
I'm not sure about connection to external hardware but it's definetly possible to connect 2 phones without pairing. I made it using Android Nearby Connections . And yeah it's basically working with BLE. As far as I know it's possible to connect to RaspberryPi using that API.
Bluetooth devices can be made to communicate with each other using master-slave configuration. I first tried with two BLE-HC05s, made one as master and the other as slave, and as expected the master is able to send data, slave is able to receive data, that can be seen using the Serial Monitor in Arduino IDE. I have developed a similar app, which connects to a BLE-HC05 device, sends and receives data. But since you are trying to get data or send data to the App on your phone, Android will not support such unpaired anonymous communications. If you are having trouble with connection or pairing Bluetooth device and your app, I may help you with that. But as far as Bluetooth communication without pairing is concerned, you may not be able to find a way.
Edit: The code to connect any bluetooth device, like BLE-HC06 as you have mentioned, is 1234 (Only if you have not changed it)
I've made a ListView with devices currently paired to my phone so that I can select one of them and connect to it. To determine which device was selected, I'm storing their MAC Addresses in an array so that I can get a device by its address. When I select a device, the app freezes for a bit then restores with no success of connecting. I cannot find the solution anywhere and I'm stuck. I'm still a beginner and do not understand much. An exception occurs that goes like:
java.io.IOException: read failed, socket might be closed or timeout, read ret: -1
Here is my code.
// If the UUID is incorrect then this one does not work as well
// 00001101-0000-1000-8000-00805f9b34fb
private static final UUID CONNECTION_UUID = UUID.fromString("0000110E-0000-1000-8000-00805F9B34FB");
public static boolean connectDevice(final int a) {
try {
BluetoothDevice mBluetoothDevice = btAdapter.getRemoteDevice(deviceAddress[a]);
BluetoothSocket mBluetoothSocket = mBluetoothDevice.createInsecureRfcommSocketToServiceRecord(CONNECTION_UUID);
btAdapter.cancelDiscovery();
mBluetoothSocket.connect();
mmOutputStream = new DataOutputStream(mBluetoothSocket.getOutputStream());
mmInputStream = new DataInputStream(mBluetoothSocket.getInputStream());
mBluetoothSocket.close();
} catch (NullPointerException e) {
e.printStackTrace();
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
From the CONNECTION_UUID that you provided in your code, I assume that you are connecting with a Bluetooth serial board. I am not sure about the problem yet, however, I thought of writing this answer to provide a probable solution that might solve your issue.
I think in case of the paired devices, you need to initiate the connection with a secure channel. Currently, you are using an insecure channel.
From the documentation...
The communication channel will not have an authenticated link key i.e
it will be subject to man-in-the-middle attacks. For Bluetooth 2.1
devices, the link key will be encrypted, as encryption is mandatory.
For legacy devices (pre Bluetooth 2.1 devices) the link key will be
not be encrypted. Use createRfcommSocketToServiceRecord(UUID) if an
encrypted and authenticated communication channel is desired.
Hence you might consider using createRfcommSocketToServiceRecord() for your case.
Instead of this
BluetoothSocket mBluetoothSocket = mBluetoothDevice.createInsecureRfcommSocketToServiceRecord(CONNECTION_UUID);
Use this...
BluetoothSocket mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(CONNECTION_UUID);
I hope that solves your problem.
From the comment below - The UUID that actually worked here is 00001101-0000-1000-8000-00805f9b34fb
I'm trying to send some bytes from java code to a bluetooth module that is connected to an Arduino. Here is my code.
import gnu.io.*;
import java.io.IOException;
import java.io.OutputStream;
public class ArduinoSerialWriter {
private static OutputStream arduinoOutputStream;
public static void init() throws NoSuchPortException, PortInUseException,
UnsupportedCommOperationException, IOException {
SerialPort arduino = (SerialPort) CommPortIdentifier.getPortIdentifier("COM6")
.open(ArduinoSerialWriter.class.getName(), 2000);
arduino.setSerialPortParams(9600,
SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
arduinoOutputStream = arduino.getOutputStream();
}
public static void writeToArduino(byte[] bytes) throws IOException {
arduinoOutputStream.write(bytes);
}
public static void main(String[] args) {
try {
ArduinoSerialWriter.init();
} catch (Exception e) {
e.printStackTrace();
}
try {
arduinoOutputStream.write(new byte[]{(byte) -1, (byte) 90, (byte) 40});
} catch (IOException e) {
e.printStackTrace();
}
}
}
The init() seems to be working properly and connecting to the bluetooth module. The problem is that the call to arduinoOutputStream.write() is blocking indefinitely. I can also tell that the bytes have not been sent because the Arduino is not doing anything. However, no exceptions were thrown.
I read somewhere that it might be because the Arduino is resetting and needs time before it is ready to receive data, so I tried adding Thread.sleep(10000); before writing to the port, but that didn't change anything.
I also used a debugger to figure out where exactly the code was blocking and I traced it to these lines from the write(byte[]) method from RXTXPort.class in the RXTX library:
RXTXPort.this.waitForTheNativeCodeSilly();
RXTXPort.this.writeArray(var1, 0, var1.length, RXTXPort.this.monThreadisInterrupted);
From what I can gather, waitForTheNativeCodeSilly(); is called right before the bytes are actually sent in the next line, and this is where the code freezes.
I also tried adding arduinoOutputStream.flush(); after the call to the write method, but that didn't help either because the code froze before that line was even reached.
Any help would be appreciated.
Update:
I tried using removing the bluetooth module and using the USB cable for the Arduino instead and it worked perfectly. I think there might be something I need to setup with the bluetooth module.
It is an HC-06 bluetooth module. Here's where I got it from:
https://www.amazon.ca/JMT-Wireless-Bluetooth-Serial-Arduino/dp/B00HXAE0PQ/
The only thing I'm doing to set it up is going to manage bluetooth devices on my windows 10 pc and clicking pair. It says paired underneath it, so I'm not sure what the problem is.
Update Again:
I tried sending data to the bluetooth module using the serial monitor in the Arduino IDE, and the entire IDE completely froze. The only way I could shut it down was by killing the process in task manager. I'm fairly certain the Arduino IDE is having the same problem that I am, so its definitely something to do with the bluetooth chip and not my code itself.
Turns out I had the completely wrong idea. I was much better off using bluetooth connection as opposed to trying to treat the bluetooth chip as a COM port. I guess I was just fixated on that because I was used to it from Arduino.
I used the bluecove library for java and its working great now!
i'm using SPP profile for connect to my device:
Set<BluetoothDevice> devices = ba.getBondedDevices();
for(BluetoothDevice bd : devices)
{
String name = bd.getName();
if(name.equals("CELLMETER"))
{
try
{
BluetoothSocket bs = bd.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
bs.connect();
} catch (IOException e)
{
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
All seems okay, i created function where i'm closing input output buffers and close socket.
But when application crashes or i'm stopping application when breakpoints arrives socket doesn't closes, even after i kill process manually and it's not avalible for new connection from new instance of app.
What i'm doing wrong? For each crash/debug operation i have to reboot phone :(
It's manifested only to Android 2.3.5 (Samsung 5830i) and on Android 4.0.4 (Freelander P10). On my Android 4.2.1 (Galaxy Nexus) all okay, after app crash connection closes automatically. (it seems because there is new Bluetooth stack)
I can see 2 options to work that out:
1- Add an UncaughtExceptionHandler in your app, best in Application-derived class:
mUEHandler = new Thread.UncaughtExceptionHandler()
{
#Override
public void uncaughtException(Thread t, Throwable e)
{
// Close any opened sockets here
defaultUEH.uncaughtException(t, e);
}
};
Thread.setDefaultUncaughtExceptionHandler(mUEHandler);
But that only takes care of app crashes. If user kills the app, won't get in there at all.
2- Store some socket identification that allow you to close it when app restarts.
It's not perfect, but that could work-around your issue.
I solved this problem by letting my BluetoothSockets be managed by a Service running in its own process. I open, close, read, and write the sockets by passing Messages to and from the Service. If the app crashes, the Service shuts down cleanly, closing the sockets. (It does not shut down cleanly if it's running in the same process as the app.)