i wrote a Server for our global Leadbord which actually works now.
I can send data to it if it's active. But if it's down my app does not stop. I dont get a solution for it i hope you can help me. Here is the sending:
public void saveToDatabase(LeadboardElement element2) {
final LeadboardElement element = element2;
send = false;
// Need to be a thread! else android blocks it because it could take to
// long to send!
this.thread = new Thread() {
public void run() {
try {
Socket soc = new Socket(Config.TCP_SERVERNAME_IP,
Config.TCP_PORT);
DataOutputStream out = new DataOutputStream(
soc.getOutputStream());
DataInputStream in = new DataInputStream(
new BufferedInputStream(soc.getInputStream()));
// to call the save statement!
out.writeInt(0);
// give the stuff
out.writeUTF(element.getName());
out.writeInt(element.getLevel());
out.writeInt(element.getKillPoints());
// close it
out.close();
in.close();
soc.close();
send = true;
//join at every error
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
};
// start it
thread.start();
// join thread
if (!send) {
boolean retry = true;
while(retry)
try {
this.thread.join();
retry = false;
Log.w(TAG, "sending to server stopped!");
} catch (InterruptedException e2) {
Log.w(TAG, "Thread could not be joined");
}
}
}
I noticed that i need to do it in a thread since API 5 so it works like this. It's called at the end of an Game if the player touches the screen. Everything get stopped and the data is sent to the Server. If hes down it does not work we stuck in the fade to black.
I guess i need something like a timeout. I tried it with a CountDownTimer but this acutally does not solve the problem.
Thanks alot!
Changing the way you initialize the socket, you can set a timeout.
Socket s1 = new Socket();
s1.setSoTimeout(200);
s1.connect(new InetSocketAddress("192.168.1." + i, 1254), 200);
Add a timeout when creating a new Socket
Related
I made android application that connects to remote server and send some data.
Remote server is Windows application.
Connection method:
private void ConnectToMonitor() {
try {
s = new Socket(SERVER_ADDRESS, TCP_SERVER_PORT);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This works perfectly if server is online. Application is sending data and server is receiving. But if server is offline android app. is blocked. My question is how to handle this? How to continue with application and avoid error even the server is down?
Remember to call this outside the UIThread.
Follow this tutorial. In android all connections need to be managed outside the UIThread, in the tutorial I linked you will find easy ways to post your results back to the UI (handlers, asynctasks...)
Of course we don't know if the problem is about the thread with just the given code, but it is the most usual error.
First remember to set the socket timeout :
mSocket.setSoTimeout(timeout); //in milliseconds
You can however specify different timeout for connection and for all other I/O operations through the socket:
private void connectToMonitor() {
try {
socket = new Socket();
InetAddress[] iNetAddress = InetAddress.getAllByName(SERVER_ADDRESS);
SocketAddress address = new InetSocketAddress(iNetAddress[0], TCP_SERVER_PORT);
socket.setSoTimeout(10000); //timeout for all other I/O operations, 10s for example
socket.connect(address, 20000); //timeout for attempting connection, 20 s
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Second, in Android, you should perform any network I/O in separate threads!
As an example, using regular Java Threads :
String threadName = getClass().getName() + "::connect";
new Thread(new Runnable() {
#Override
public void run() {
connectToMonitor();
}
}, threadName).start();
You can set A timeout for the socket. Use Socket.setSoTimeout method
socket.setSoTimeout(timesinmilis);
by using this your socket will throw a socket timout exception. You can catch that and do what you want
I'm building an application for sending files between two Android phones, now i have a ListActivity that retrieves the sdcard and lists the files, when the ListActivity first starts on the two devices a ServerSocket is set up and listening with .accept() ...
this thread starts when the ListActivity starts :
ReceiveFileSendRequestThread ReceiveFileSendRequestThread = new ReceiveFileSendRequestThread();
ReceiveFileSendRequestThread.start();
and here is the full thread class:
static public class ReceiveFileSendRequestThread extends Thread {
public void run() {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(6789, 200);
connectionServ = serverSocket.accept();
requestFileInServer = new ObjectInputStream(
connectionServ.getInputStream());
requestFileString = (String) requestFileInServer.readObject();
handler.post(new AcceptFileSendAlertDialogRunnable());
while (okToSend == null) {
}
if (okToSend == true) {
requestFileOutServer = new ObjectOutputStream(
connectionServ.getOutputStream());
requestFileOutServer.writeObject("oktosend");
requestFileOutServer.flush();
serverSocket.close(); // // Receive File
} else if (okToSend == false) {
requestFileOutServer = new ObjectOutputStream(
connectionServ.getOutputStream());
requestFileOutServer.reset();
requestFileOutServer.writeObject("notosend");
requestFileOutServer.flush();
serverSocket.close();
ReceiveFileSendRequestThread ReceiveFileSendRequestThread = new ReceiveFileSendRequestThread();
ReceiveFileSendRequestThread.start();
}
} catch (IOException e) {
Log.d("Connection Error:", "Error binding port!");
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
And when onLongClick on an item (to send file) the following thread starts:
public boolean onItemLongClick(AdapterView<?> parentView, View childView,
int position, long id) {
// TODO Auto-generated method stub
fileClickedName = (((TextView) childView).getText()).toString();
fileClickedPath = file.toString() + "/" + fileClickedName;
fileClickedFile = new File(fileClickedPath);
SendFileThread SendFileThread = new SendFileThread();
SendFileThread.start();
return true;
}
SendFile Thread:
static public class SendFileThread extends Thread {
public void run() {
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(sharedIp, 6789), 200);
requestFileOutClient = new ObjectOutputStream(
socket.getOutputStream());
requestFileOutClient.writeObject(fileClickedName);
requestFileOutClient.flush();
requestFileInClient = new ObjectInputStream(
socket.getInputStream());
toSendOrNot = (String) requestFileInClient.readObject();
if (toSendOrNot.equals("oktosend")) {
socket.close();
} else if (toSendOrNot.equals("notosend")) {
socket.close();
ReceiveFileSendRequestThread ReceiveFileSendRequestThread = new ReceiveFileSendRequestThread();
ReceiveFileSendRequestThread.start();
handler.post(new ClientFileSendAlertDialogRunnable());
}
// //
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Now, when I launch the ListActivity and longClick on an item, the the file name is sent to the second device, the second device pops up an alertDialog asking the user if to accept the file or not, (accepting file is still not ready for now) if the user presses on CANCEL (on the ReceiveFileSendRequestThread) a string is sent to the first device "notosend", the first user receives the string "notosend" and depending on that the thread closes the socket and re invoke the thread to listen to the second peer if he wants to send another file , AND pops up an alertDialog telling the first user that your file was refused to be received ... >>>> this is totally works >>>> but when the first device attempts to send another file (long press again on a file [item on the list] ) the second user receives the new file name selected by the first user successfully and alertDialog pops up if to accept or cancel BUT the first user receives that the file send was refused ... without having the second user pressing on the cancel button !!! ... i don't know why toSendOrNot = (String) requestFileInClient.readObject(); keeps on taking the previous value without even waiting for the second device to write the new object.
I would appreciate it if someone could help me with this , Many thanks.
AFTER HOURS OF DEBUGGING >>> I FINALLY FOUND THE BUG!
in thread ReceiveFileSendRequestThread() the Boolean variable okToSend is null when first receiving a request from the second device, when the second device cancels the request the oKtoSend will be set to notosend, so whenever the second device attempts to send another file the variable okToSend will always has the previously assigned value. So I simply added okToSend = null; before the while loop, and now is working perfectly.
Below is the receive method that implements a socket server and works perfectly.
private void Receive(){
log.info("Server started - waiting for the clients.");
try {
Boolean end = false;
ServerSocket ss = new ServerSocket(12345);
while(!end){
//Server is waiting for client here, if needed
Socket s = ss.accept();
BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter output = new PrintWriter(s.getOutputStream(),true); //Autoflush
String st = input.readLine();
JSONObject jsonObj;
try {
jsonObj = new JSONObject(st);
long id = jsonObj.optLong("DeviceID", count.addAndGet(1) );
String name = jsonObj.toString();
table.put(id, name);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
etResult.setText(st);
Log.d("Tcp Example", "From client: "+st);
output.println("Response from Sever: Connectivity ok");
s.close();
if (st != null ){ end = true; }
}
ss.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The only problem is, when I hit the button to call that method, the socket starts listening and waits for a client messages. While it does not happen, the app remains freezes and I try to hit any other button, the app may crashes.
Does anyone have a hint about how could handle it and leave the socket listening in "background" withou locking the entire screen?
thank you
Make a thread or AsyncTask and do all the socket functions on that. IF it's something you're going to rarely do and want to fire it off and process the results, use an AsyncTask. If it's something you're going to want to do constantly and don't want to run multiple workers at the same time or have multiple workers queued up, use a Thread.
I have been using InputStream.read( byte[] b, int off, int len ) method to read in data, but now have run into a timeout problem. I am sometimes expecting timeouts from reading, and should have the program adjust itself accordingly after a timeout. I have tried to implement a Thread but I really know nothing about Threads and cannot get it to work. I also want to add that this thread is being initialized within another thread. I'm not sure what the implications of this are but it may cause a problem.
My initial code had worked for the majority of times I need to read, but whenever I'm expecting a timeout, my program freezes at the read() call and never times out. When I implemented this new code, the times when my initial code worked now time out. I use Thread.wait(500) which I assume is 500 milliseconds, but I cannot find any Javadocs including the wait() function. Here and Here.
Other posts relating to this: 1, 2, 3.
I have also looked into declaring a timeout for the BluetoothSocket, but I cannot find it anywhere in the documentation.
Here is what my initial code looks like:
public void run(int length) throws IOException {
buffer = new byte[1024];
try {
bytes = mmInStream.read(buffer, 0, length);
mHandler.obtainMessage(MainMenu.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Message msg = mHandler.obtainMessage(MainMenu.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString( TOAST, "Device has disconnected from the Bluetooth Module." );
msg.setData(bundle);
mHandler.sendMessage(msg);
connectionLost();
BluetoothService.this.start();
}
This is what I have tried to implement:
public void run(int length) throws IOException {
buffer = new byte[1024];
length1 = length;
Thread myThread = new Thread(new Runnable() {
public void run() {
try {
bytes = mmInStream.read( buffer, 0, length1 );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
synchronized (myThread) {
myThread.start();
try {
myThread.wait(500);
if(myThread.isAlive()) {
mmInStream.close();
Log.i( "InStream", "Timeout exceeded!");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
myThread.run();
mHandler.obtainMessage(MainMenu.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Message msg = mHandler.obtainMessage(MainMenu.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString( TOAST, "Device has disconnected from the Bluetooth Module." );
msg.setData(bundle);
mHandler.sendMessage(msg);
connectionLost();
BluetoothService.this.start();
}
EDIT:
So I'm trying to recreate
buffer = new byte[1024];
bytes = mmInStream.read(buffer, 0, length);
I have done the following:
Scanner scan = new Scanner(new InputStreamReader(mmInStream));
String readIn;
try {
readIn = scan.next();
bytes = 5; // I tried with or without this, since I do not think it matters...
buffer = readIn.getBytes( Charset.forName( "US-ASCII" ) );
}
Later in my code I make this call....Sorry edit again, the buf=read( 5 ) call goes to what is shown above.
byte[] buf = buffer;
write( a );
buf = read( 5 );
Log.i(TAG, "Before buf[5]" );
try {
buf[5] = '\0';
} catch( NullPointerException e ) {
return false;
}
When I use the original method, It passes this buf[5] call fine. But when I use the new method, it gives me an IndexOutOfBoundsException at that spot. Am I missing something? The expected input should be CMD\r\n
The bluetooth chat example is really poor in this respect, you should use an input scanner instead of mmInStream.read. Here's what I use and it works reasonably well...
For your use case you skip the entire buffer and byte and write and read (no need to use any of those when you are using a scanner and inputstreamreader as those handle that stuff for you)... in other words the below code takes care of all that for you. I changed the delimiter for you to CRLF. What the code below does is you send a string and it writes it and then reads. If you don't need to send anything to the remote device, just start at scan = new Scanner. Each time a line is read and it ends with \r\n it will store it in the string instring.
So if you want to send "a", you would write
String readIn = beginListenForData("a");
The a will be sent under the mmOutStream and then the scanner will read the mmInStream and collect all the characters, then once it sees a CRLF it will return the characters it read and return them in your readIn string. Make sense?
private String beginListenForData(String msg0) {
msg0 += "\r"; //this adds a return character to the string, you can omit this if you just send an a and the remote device understands what that means.
String instring = "";
try {
mmOutStream.write(msg0.getBytes());
} catch (IOException ex) {
stop();
}
scan = new Scanner(new InputStreamReader(mmInStream));
scan.useDelimiter(Pattern.compile("[\\r\\n]+"));
instring = scan.next();
scan = null;
return instring;
}
Hi I have a service in Android that handles the HTTP method POST as specified below. Now, I need to call an Intent in
replaceResourceSegment()
method. It has a handler that takes nearly 90 seconds to complete the task. Within that time, control exits the handler block. But I want my program to continue within handler for POST. In short, I want my service to pause for sometime inside the POST handler, till my Intent (with handler) completes its execution and I need to delay sending the response of HTTP Post. Can some one guide me how to do this implementation?
if(method.equals("POST"))
{
conn.receiveRequestEntity((HttpEntityEnclosingRequest)request);
HttpEntity entity = ((HttpEntityEnclosingRequest)request).getEntity();
String content_type = ""+entity.getContentType();
JSONReceived = EntityUtils.toString(entity);
if(content_type.contains("json"))
{
Log.d(TAG,"Content received is: "+JSONReceived);
bufferedWriter = new BufferedWriter(new FileWriter(new File(getFilesDir()+File.separator+constants.UPDATED_SCRIPT_FILE)));
bufferedWriter.write(JSONReceived);
bufferedWriter.close();
try {
parseJSON(JSONReceived);
replaceResourceSegment(); //Call to an intent with startActivityForResult()
continueExecution(); //Continue the execution from here
} catch (IOException e) {
e.printStackTrace();
Log.d(TAG,"IOException line 157");
}
Code for sending response back:
HttpResponse postResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
postResponse.setEntity(new StringEntity("Got it"));
conn.sendResponseHeader(postResponse);
conn.sendResponseEntity(postResponse);
I managed to solve the problem by using a boolean variable with default value false. It will be checked periodically and keeps the control inside the POST method's handler.
android.os.SystemClock.sleep(30000); //Sleeps for 30 seconds and invoke busy waiting in a thread
Thread syncThread = new Thread(new LoopCheck());
syncThread.start();
synchronized(syncThread)
{
Log.d(TAG,"Inside synchronized blockk");
try
{
syncThread.wait();
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
The thread class is defined as below:
class LoopCheck extends Thread{
public LoopCheck(){
}
public void run(){
while(true)
{
try {
Thread.sleep(10000);
if(write)
{
write = false;
synchronized(syncThread)
{
syncThread.notify();
}
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}