I have an application which communicates with a bluetooth device via async task
if I receive a phone call and during the call I return to the app
the screen dims and the application is unresponsive
back button doesn't work... and no ANR dialog is shown
any ideas?
here is the code which handles the connection:
#Override
protected Object doInBackground(Object... params) {
//boolean protocolUpdated;
int read = 0; // The amount of bytes read from the socket.
byte[] buff = new byte[MessageHandler.BUFFERSIZE]; // The data buffer.
byte[] tmpSend = null; // Misc bytes arrays returned from ProtocolParser as answers to send after decoding calls.
in = null;
out = null;
try {
if (Float.parseFloat(version) > 2.2){
Method m = dev.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
sock = (BluetoothSocket) m.invoke(dev, 1);
}
else sock = dev.createRfcommSocketToServiceRecord(UUID_RFCOMM_GENERIC); // UUID is constant for serial BT devices.
sock.connect(); // connect to the BT device. This is rather heavy, may take 3 secs.
sendMessage(MESSAGE_CONNECTION_ESTABLISHED);
in = sock.getInputStream();
out = sock.getOutputStream();
timer = new Timer();
startFinishTimer(); //initialize finish timer
while(read != -1) { // read = -1 means EOF.
do { // as long as there is anything to send in the send queue - send it.
tmpSend = parser.nextSend();
if(tmpSend != null){
String msg = parseMessage(tmpSend);
Log.d("Writing:",msg);
out.write(tmpSend);
}
} while(tmpSend != null);
read = in.read(buff); // read. This is a blocking call, to break this, interrupt the thread.
timer.cancel();
startFinishTimer(); //read is a blocking call so timer should be restarted only after read bytes.
parser.parse(buff,read); // parse the read message using the logic in the ProtocolParser derived class.
tmpSend = parser.getPool(); // if pool ack is required - send it.
if (tmpSend != null){
Log.d("Writing:",parseMessage(tmpSend));
out.write(tmpSend);
}
if (read != 0){
Log.d("Read:",parseMessage(buff));
tmpSend = parser.getAnswer(); // if answer is required (based on message) - send it.
if(tmpSend != null){
out.write(tmpSend);
}
}
else {
Exception e = new IOException();
throw e;
}
}
}catch (IOException e){
e.printStackTrace();
Log.d("Connection: ", "Bluetooth Connection CRASHED!");
sendMessage(MESSAGE_CONNECTION_LOST);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
Actually there is not enough context to find your problem.
Make sure that you launch this task from Main thread in other case PostExecute will be attached to wrong thread, you could get a race.
Make sure that you don't send same message to multiple handlers in your code.
Message it's a linked list and your could get ANR in that case.
Get /data/anr/traces.txt to make sure that it's not ANR.
You could make sure by time in the beginning of the file.
Related
I've been editing androids toyvpn sample project for vpn and i got this one for my sample app
I know there is something wrong/missing with my code because when i manually set up the vpn via android settings, there are packets Receive that's why
i've been searching how to receive packets and i dont know how to get this working.
here is my source code that VCL that extends VpnService
import android.app.PendingIntent;
import android.net.VpnService;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
/**
* Created by Jameshwart Lopez on 8/18/15.
*/
public class VCL extends VpnService {
private static final String TAG = "VpnClientLibrary";
private Thread mThread;
private ParcelFileDescriptor mInterface;
private String mServerAddress;
private String mServerPort;
private PendingIntent mConfigureIntent;
private String mParameters;
//a. Configure a builder for the interface.
Builder builder = new Builder();
public void vclRun(){
try {
//a. Configure the TUN and get the interface.
mInterface = builder.setSession("thesessionname")
.addAddress("192.168.0.1",24)
.addDnsServer("8.8.8.8")
.addRoute("0.0.0.0", 0).establish();
//b. Packets to be sent are queued in this input stream.
FileInputStream in = new FileInputStream(mInterface.getFileDescriptor());
//b. Packets received need to be written to this output stream.
FileOutputStream out = new FileOutputStream(mInterface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(32767);
//c. The UDP channel can be used to pass/get ip package to/from server
DatagramChannel tunnel = DatagramChannel.open();
// Connect to the server, localhost is used for demonstration only.
mServerAddress="";//some of the vpn ip address here
mServerPort="1723";
InetSocketAddress server = new InetSocketAddress(mServerAddress, Integer.parseInt(mServerPort) );
tunnel.connect(server);
// For simplicity, we use the same thread for both reading and
// writing. Here we put the tunnel into non-blocking mode.
tunnel.configureBlocking(false);
// Authenticate and configure the virtual network interface.
handshake(tunnel);
//d. Protect this socket, so package send by it will not be feedback to the vpn service.
protect(tunnel.socket());
int timer = 0;
//e. Use a loop to pass packets.
while (true) {
//get packet with in
//put packet to tunnel
//get packet form tunnel
//return packet with out
//sleep is a must
// Assume that we did not make any progress in this iteration.
boolean idle = true;
// Read the outgoing packet from the input stream.
int length = in.read(packet.array());
if (length > 0) {
// Write the outgoing packet to the tunnel.
packet.limit(length);
tunnel.write(packet);
packet.clear();
// There might be more outgoing packets.
idle = false;
// If we were receiving, switch to sending.
if (timer < 1) {
timer = 1;
}
}
// Read the incoming packet from the tunnel.
length = tunnel.read(packet);
if (length > 0) {
// Ignore control messages, which start with zero.
if (packet.get(0) != 0) {
// Write the incoming packet to the output stream.
out.write(packet.array(), 0, length);
}
packet.clear();
// There might be more incoming packets.
idle = false;
// If we were sending, switch to receiving.
if (timer > 0) {
timer = 0;
}
}
// If we are idle or waiting for the network, sleep for a
// fraction of time to avoid busy looping.
if (idle) {
Thread.sleep(100);
// Increase the timer. This is inaccurate but good enough,
// since everything is operated in non-blocking mode.
timer += (timer > 0) ? 100 : -100;
// We are receiving for a long time but not sending.
if (timer < -15000) {
// Send empty control messages.
packet.put((byte) 0).limit(1);
for (int i = 0; i < 3; ++i) {
packet.position(0);
tunnel.write(packet);
}
packet.clear();
// Switch to sending.
timer = 1;
}
// We are sending for a long time but not receiving.
//if (timer > 20000) {
// throw new IllegalStateException("Timed out");
//}
}
}
} catch (Exception e) {
// Catch any exception
e.printStackTrace();
} finally {
try {
if (mInterface != null) {
mInterface.close();
mInterface = null;
}
} catch (Exception e) {
}
}
}
private void handshake(DatagramChannel tunnel) throws Exception {
// To build a secured tunnel, we should perform mutual authentication
// and exchange session keys for encryption. To keep things simple in
// this demo, we just send the shared secret in plaintext and wait
// for the server to send the parameters.
// Allocate the buffer for handshaking.
ByteBuffer packet = ByteBuffer.allocate(1024);
// Control messages always start with zero.
String password = "";//vpn password here
packet.put((byte) 0).put(password.getBytes()).flip();
// Send the secret several times in case of packet loss.
for (int i = 0; i < 3; ++i) {
Log.e("packetsdata", packet.toString());
packet.position(0);
tunnel.write(packet);
}
packet.clear();
// Wait for the parameters within a limited time.
for (int i = 0; i < 50; ++i) {
Thread.sleep(100);
// Normally we should not receive random packets.
int length = tunnel.read(packet);
if (length > 0 && packet.get(0) == 0) {
configure(new String(packet.array(), 1, length - 1).trim());
return;
}
}
//throw new IllegalStateException("Timed out");
}
private void configure(String parameters) throws Exception {
// If the old interface has exactly the same parameters, use it!
if (mInterface != null) {
Log.i(TAG, "Using the previous interface");
return;
}
// Configure a builder while parsing the parameters.
Builder builder = new Builder();
for (String parameter : parameters.split(" ")) {
String[] fields = parameter.split(",");
try {
switch (fields[0].charAt(0)) {
case 'm':
builder.setMtu(Short.parseShort(fields[1]));
break;
case 'a':
builder.addAddress(fields[1], Integer.parseInt(fields[2]));
break;
case 'r':
builder.addRoute(fields[1], Integer.parseInt(fields[2]));
break;
case 'd':
builder.addDnsServer(fields[1]);
break;
case 's':
builder.addSearchDomain(fields[1]);
break;
}
} catch (Exception e) {
throw new IllegalArgumentException("Bad parameter: " + parameter);
}
}
// Close the old interface since the parameters have been changed.
try {
mInterface.close();
} catch (Exception e) {
// ignore
}
// Create a new interface using the builder and save the parameters.
mInterface = builder.setSession(mServerAddress)
.setConfigureIntent(mConfigureIntent)
.establish();
mParameters = parameters;
Log.i(TAG, "New interface: " + parameters);
}
}
this is how i use the class above
private Thread mThread;
/*
* Services interface
* */
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Start a new session by creating a new thread.
mThread = new Thread(this, "VpnRunnable");
//start the service
mThread.start();
/*
*service is left "started" and will later be restarted by the system
* http://android-developers.blogspot.com.au/2010/02/service-api-changes-starting-with.html
*/
return START_STICKY;
}
#Override
public void onDestroy() {
if (mThread != null) {
mThread.interrupt();
}
super.onDestroy();
}
#Override
public synchronized void run() {
/*
* to run the vpn interface call the vclRun method inside VCL class
* */
this.vclRun();
}
Firstly, check that there are bytes being sent to your android device. As it won't be reading anything if there is nothing to receive.
Then have a look at this, as it may be messing up your connection.
You need to include this in the onStartCommand:
// The handler is only used to show messages.
if (mHandler == null) {
mHandler = new Handler(this);
}
// Stop the previous session by interrupting the thread.
if (mThread != null) {
mThread.interrupt();
}
// Extract information from the intent.
String prefix = getPackageName();
mServerAddress = intent.getStringExtra(prefix + ".ADDRESS");
mServerPort = intent.getStringExtra(prefix + ".PORT");
mSharedSecret = intent.getStringExtra(prefix + ".SECRET").getBytes();
// Start a new session by creating a new thread.
mThread = new Thread(this, "ToyVpnThread");
mThread.start();
return START_STICKY;
And also the details (some shown below) of the sychronized void.
#Override
public synchronized void run() {
try {
Log.i(TAG, "Starting");
// If anything needs to be obtained using the network, get it now.
// This greatly reduces the complexity of seamless handover, which
// tries to recreate the tunnel without shutting down everything.
// In this demo, all we need to know is the server address.
InetSocketAddress server = new InetSocketAddress(
mServerAddress, Integer.parseInt(mServerPort));
// We try to create the tunnel for several times. The better way
// is to work with ConnectivityManager, such as trying only when
// the network is avaiable. Here we just use a counter to keep
// things simple.
for (int attempt = 0; attempt < 10; ++attempt) {
mHandler.sendEmptyMessage(R.string.connecting);
// Reset the counter if we were connected.
// See BELOW
if (run(server)) {
attempt = 0;
}
// Sleep for a while. This also checks if we got interrupted.
Thread.sleep(3000);
} /..../
You are not managing your thread actions well. It is advised to receive any bytes that need to be received before attempting your run. That not doing so can cause problems.
I would go back through your code and put in the things you took out.
I also suggest you change your code here:
packet.put((byte) 0).put(password.getBytes()).flip();
Try to use explicit encoding:
packet.put((byte) 0).put(password.getBytes("UTF-8")).flip();
As data can be lost without it. See this answer:
https://stackoverflow.com/a/7947911/3956566
I have checked and your project is using "UTF-8".
Let me know if this doesn't help.
I am having a bit of an issue with my app. I receive a data through a socket, via a BufferedReader. I loop round with while ((sLine = reader.readLine ()) != null) and append the sLine to a StringBuilder object. I also spend a new line \n to the builder.
The plan is that once the builder is all finished, String sTotal = builder.toString()is called and a total is passed to the next routine.
However, the next routine is instead being called once for each line rather than with the string as a whole. The routine call is outside the loop above so I really don't know why!
Hope someone can help...
Edit: Code extract below.
public void run() {
try {
oServerSocket = new ServerSocket(iPort);
while ((!Thread.currentThread().isInterrupted()) && (!bStopThread)) {
try {
oSocket = oServerSocket.accept();
this.brInput = new BufferedReader(new InputStreamReader(this.oSocket.getInputStream()));
StringBuilder sbReadTotal = new StringBuilder();
String sReadXML = "";
while ((sReadXML = brInput.readLine()) != null) {
sbReadTotal.append("\n");
sbReadTotal.append(sReadXML);
}
sReadXML = sbReadTotal.toString();
Log.d("XMLDATA", sReadXML);
processXML(sReadXML);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
/* Nothing Yet */
e.printStackTrace();
}
}
If you're exiting your internal while loop, it means you reached the end of your input stream (that's when readLine() returns null according to the docs).
You should be looking into the client, and not the server. What's establishing the client socket? Are you sure it's not establishing a separate connection for each line it sends?
I been searching for my answer for a couple of hours now and I can't figure it out. Please help.
What I want to do is to use the VpnService in Android to grab network packets like the application tPacketCapture
I started by using the ToyVpn sample code from google and modifying it so I don't send the data to a server. However, I'm not sure if this is correct.
My configure method uses the wlan ip address for binder.addAddress() before calling establish(). I am using a nexus 7 and I used "adb shell netcfg | grep wlan0" to get the address:
wlan0 UP 192.168.0.6/24 0x00001043 10:bf:48:bf:5f:9d
And add it in my method:
private void configure() throws Exception {
// If the old interface has exactly the same parameters, use it!
if (mInterface != null) {
Log.i(TAG, "Using the previous interface");
return;
}
// Configure a builder while parsing the parameters.
Builder builder = new Builder();
builder.setMtu(1500);
builder.addAddress("192.168.0.6", 24);
try {
mInterface.close();
} catch (Exception e) {
// ignore
}
mInterface = builder.establish();
}
After calling this, I call the run method which I modified to pass a String instead of a InetSocketAddress and this is not important because I am not using it anywhere:
private void run(String run) throws Exception {
configure();
FileInputStream in = new FileInputStream(mInterface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(32767);
// We use a timer to determine the status of the tunnel. It
// works on both sides. A positive value means sending, and
// any other means receiving. We start with receiving.
int timer = 0;
// We keep forwarding packets till something goes wrong.
while (true) {
// Assume that we did not make any progress in this iteration.
boolean idle = true;
// Read the outgoing packet from the input stream.
int length = in.read(packet.array());
if (length > 0) {
Log.i(TAG,"************new packet");
while (packet.hasRemaining()) {
Log.i(TAG,""+packet.get());
//System.out.print((char) packet.get());
}
// Write the outgoing packet to the tunnel.
packet.limit(length);
// tunnel.write(packet);
packet.clear();
// There might be more outgoing packets.
idle = false;
// If we were receiving, switch to sending.
if (timer < 1) {
timer = 1;
}
}
}
}
When I do adb logcat, nothing is happening. Am I going about this correctly? I feel like I am missing something.
Thank you!
EDIT:
From the logs I see the following lines:
I/ActivityManager( 460): START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.android.toyvpn/.ToyVpnClient} from pid 10247
I/ActivityManager( 460): Start proc com.example.android.toyvpn for activity com.example.android.toyvpn/.ToyVpnClient: pid=10287 uid=10122 gids={50122, 3003, 1028}
I/ActivityManager( 460): Displayed com.example.android.toyvpn/.ToyVpnClient: +1s144ms
I/Vpn ( 460): Switched from [Legacy VPN] to com.example.android.toyvpn
D/Vpn ( 460): setting state=IDLE, reason=prepare
I/ToyVpnService(10287): running vpnService
D/Vpn ( 460): setting state=CONNECTING, reason=establish
D/VpnJni ( 460): Address added on tun0: 192.168.0.6/24
I/Vpn ( 460): Established by com.example.android.toyvpn.ToyVpnService on tun0
W/ContextImpl( 460): Calling a method in the system process without a qualified user: android.app.ContextImpl.bindService:1406 com.android.server.connectivity.Vpn.establish:289 com.android.server.ConnectivityService.establishVpn:3263 android.net.IConnectivityManager$Stub.onTransact:504 android.os.Binder.execTransact:351
D/Vpn ( 460): setting state=AUTHENTICATING, reason=establish
So it seems to be connecting.
Full source:
public class ToyVpnService extends VpnService implements Handler.Callback, Runnable {
private static final String TAG = "ToyVpnService";
private Handler mHandler;
private Thread mThread;
private ParcelFileDescriptor mInterface;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// The handler is only used to show messages.
if (mHandler == null) {
mHandler = new Handler(this);
}
// Stop the previous session by interrupting the thread.
if (mThread != null) {
mThread.interrupt();
}
// Start a new session by creating a new thread.
mThread = new Thread(this, "ToyVpnThread");
mThread.start();
return START_STICKY;
}
#Override
public void onDestroy() {
if (mThread != null) {
mThread.interrupt();
}
}
#Override
public boolean handleMessage(Message message) {
if (message != null) {
Toast.makeText(this, message.what, Toast.LENGTH_SHORT).show();
}
return true;
}
#Override
public synchronized void run() {
Log.i(TAG,"running vpnService");
try {
runVpnConnection();
} catch (Exception e) {
e.printStackTrace();
//Log.e(TAG, "Got " + e.toString());
} finally {
try {
mInterface.close();
} catch (Exception e) {
// ignore
}
mInterface = null;
mHandler.sendEmptyMessage(R.string.disconnected);
Log.i(TAG, "Exiting");
}
}
private boolean runVpnConnection() throws Exception {
configure();
FileInputStream in = new FileInputStream(mInterface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(32767);
// We keep forwarding packets till something goes wrong.
while (true) {
// Assume that we did not make any progress in this iteration.
boolean idle = true;
// Read the outgoing packet from the input stream.
int length = in.read(packet.array());
if (length > 0) {
Log.i(TAG,"************new packet");
System.exit(-1);
while (packet.hasRemaining()) {
Log.i(TAG,""+packet.get());
//System.out.print((char) packet.get());
}
packet.limit(length);
// tunnel.write(packet);
packet.clear();
// There might be more outgoing packets.
idle = false;
}
Thread.sleep(50);
}
}
public String getLocalIpAddress()
{
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
Log.i(TAG,"****** INET ADDRESS ******");
Log.i(TAG,"address: "+inetAddress.getHostAddress());
Log.i(TAG,"hostname: "+inetAddress.getHostName());
Log.i(TAG,"address.toString(): "+inetAddress.getHostAddress().toString());
if (!inetAddress.isLoopbackAddress()) {
//IPAddresses.setText(inetAddress.getHostAddress().toString());
Log.i(TAG,"IS NOT LOOPBACK ADDRESS: "+inetAddress.getHostAddress().toString());
return inetAddress.getHostAddress().toString();
} else{
Log.i(TAG,"It is a loopback address");
}
}
}
} catch (SocketException ex) {
String LOG_TAG = null;
Log.e(LOG_TAG, ex.toString());
}
return null;
}
private void configure() throws Exception {
// If the old interface has exactly the same parameters, use it!
if (mInterface != null) {
Log.i(TAG, "Using the previous interface");
return;
}
// Configure a builder while parsing the parameters.
Builder builder = new Builder();
builder.setMtu(1500);
builder.addAddress("192.168.0.6", 24);
try {
mInterface.close();
} catch (Exception e) {
// ignore
}
mInterface = builder.establish();
}
}
Ok, it was not easy at all but I figured out how to capture packets. Since I am not extremely familiar with networking (but this new job is requesting that I am) I had difficulty with setting everything correctly. Basically after setting the right route in the VpnService.builder I got to receiving packets correctly.
So:
builder.addAddress("192.168.0.6", 24); // was wrong, you need to put an internal IP (10.0.2.0 for example)
and
builder.addRoute("0.0.0.0", 0); // needs to be this.
you don't need to set up a DnsServer through builder.addDnsServer() to make it work. Hope this helps anyone!
My configure method uses the wlan ip address for binder.addAddress() before >calling establish(). I am using a nexus 7 and I used "adb shell netcfg | grep >wlan0" to get the address:
wlan0 UP 192.168.0.6/24 0x00001043 10:bf:48:bf:5f:9d
I have wrote a simple script in python to show you netcfg graphically from adb.
It is updating every second.
https://github.com/ilanben/graphical_netcfg
Enjoy :)
I have implemented a bluetooth connection using the now-classic Google Bluetooth Chat code. However, I have a question which I just cannot seem to wrap my brain around.
The reading of the input stream goes something like this:
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
break;
}
}
}
Now, that's fine if I was just printing out the characters I was receiving as in the original example. However, suppose I wanted to transfer an image file. I don't know the size of the file, so I cannot count the bytes received or anything like that. In my tests, I don't seem to be ever receiving a "-1" from the input stream, which appears to be the "norm" for reading from input streams. So how can I know that I have reached the end of the file that was being sent?
Thank you for your help and your time.
It seems Android bluetooth input streams never return -1.
I guess setup a simple protocol by sending file size in the first place and EOF signals at last will help.
No it does not. Android sends -1 only when the Socket is closed as far as I know. So a workaround could be to do a reconnect, but I was trying that for hours and did not get it working, since I do not understand this "special" Code here (copied from a Stackoverflow Thread) for setting up the socket:
BluetoothSocket tmp = null;
Log.d(TAG, "New Connection initialized");
Method m;
try {
m = device.getClass().getMethod("createRfcommSocket",
new Class[] { int.class });
tmp = (BluetoothSocket) m.invoke(device, 1);
} catch (Exception e) {
e.printStackTrace();
}
mmSocket = tmp;
This Socket only works, when my App is started for the first filetransfer. If I want to "Reconnect" with a completely new instantiated Object (and a new Socket created with that Code), the program freezes on the blocking method mmSocket.connect(). It seems like the Method never comes to an ending. This is driving me nuts...
Try
while ((bytes = mmInStream.read(buffer) != -1)
and see if that helps.
Try this:
public void run() {
byte[] buffer;
ArrayList<Integer> arr_byte = new ArrayList<Integer>();
while (true) {
try {
int data = mmInStream.read();
if(mmInStream.available()>0) {
arr_byte.add(data);
} else {
arr_byte.add(data);
buffer = new byte[arr_byte.size()];
for(int i = 0 ; i < arr_byte.size() ; i++) {
buffer[i] = arr_byte.get(i).byteValue();
}
Log.e("INPUT",new String(buffer));
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
arr_byte = new ArrayList<Integer>();
}
} catch (IOException e) {
break;
}
}
}
I need to have a "stable" connection to a server.
The client tries to connect to the server every 5 (10, N)-seconds.
After having connected successfully the client receives data from the server.
In case of service interruption (server shutdown, for example), go to step #1.
How I test:
I start the server
I start the client (to be sure that client gets data from the server)
I stop the server
I wait for about 200 client attempts to connect to the server.
I restart the server.
The server sends data, but the client doesn't get it.
socket.connect(...) is sucessfull, but
socket.getInputStream().read(byte[]) is not: the Thread blocks on input.read(..).
If I uncomment this line:
//socket.setSoTimeout(500);
then input.read(..) throws a TimeoutException.
But the server receives data from the client.
Where is my wrong?
Thanks.
Part of client code:
private void initSocket() {
try {
if (socket == null || socket.isClosed() == true
|| socket.isConnected() == false) {
socket = new Socket();
// socket.setSoTimeout(500);
InetSocketAddress socketAddress = new InetSocketAddress("192.168.1.3"
, 12344);
notifyDataListener(4);
socket.connect(socketAddress, 500);
notifyDataListener(5);
}
} catch (Throwable t) {
System.err.println(t);
}
}
private void closeSocket() {
try {
if (socket != null && socket.isClosed() == false) {
socket.close();
}
} catch (Throwable t) {
System.err.println(t);
}
}
private byte[] buffer = new byte[1024];
public void run() {
while (isActive) {
try {
notifyDataListener(1);
initSocket();
InputStream input = socket.getInputStream();
int length = input.read(buffer);
if (length < 0) {
throw new EOFException("Was got -1");
}
notifyDataListener(2);
} catch (Throwable t) {
closeSocket();
notifyDataListener(3);
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
}
}
}
}
On J2SE the same code works fine. Connection repairs after many wrong attempts.
It looks like Android has limit slosts of sockets (FileDescriptior?), takes them, but don't release after.
Your likely running out of file descriptors, i'm sure the limit is much lower on android than on a typical desktop configuration but the specific values will vary.
With the way you've coded this, the socket will hang around until its garbage collected, additionally on some platforms, the OS level sockets do not close instantly but hang around for a period of time to clean up any hanging data.
The first thing you should do is move your socket.close() code to finally {} statements which will free the socket immediately rather than waiting for garbage collection.