Method "lock" the entire screen when a socket server is started - android

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.

Related

Android application is freezed - Socket Exception

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

Android - ObjectInputStream keeps on reading the previous value even with .reset()

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.

TCPsending crashes the App if server is down

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

Android TCP app hanging on inStream.readline()

This is a continuation of this question because it my orginal question was answered, but it did not solve the bug.
Question:
How do I fix the code hanging on this line inStream.readline()
My Intent:
This is in a thread that will loop through checking if there is an outMessage, if there is, it will send the message.
Next it will check it if there is anything in the in-stream, if there is, it will send it to the handler in my main activity.
Lastly, it will sleep for 1 second, then check again.
This should allow me to read/write multiple times without needing to close and open the socket.
Problem:
It is reading and writing better, but still not working properly
What is happening now:
If outMessage is initialized with a value, upon connection with the server, the socket:
writes and flushes the value (server receives & responds)
updates value of outMessage (to null or to "x" depending on how i have it hard-coded)
reads and shows the response message from the server
re-enters for the next loop
IF i set outMessage to null, it skips over that if statements correctly then hangs; otherwise, if i set outMessage to a string (lets say "x"), it goes through the whole if statement, then hangs.
The code it hangs on is either of the inStream.readline() calls (I currently have one commented out).
Additional info:
- once connected, I can type in the "send" box, submit (updates the outMessage value), then disconnect. Upon re-connecting, it will read the value and do the sequence again until it get stuck on that same line.
Changes since the referenced question:
- Made outMessage and connectionStatus both 'volatile'
- added end-of-line delimiters in neccesary places.
Code:
public void run() {
while (connectionStatus != TCP_SOCKET_STATUS_CONNECTED) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
while (connectionStatus == TCP_SOCKET_STATUS_CONNECTED) {
try {
if (outMessage != null){
OutStream.writeBytes(outMessage + "\n");
OutStream.flush();
sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "OUT TO SERVER: " + outMessage);
outMessage = "x";
}
Thread.sleep(100);
// if (InStream.readLine().length() > 0) {
String modifiedSentence = InStream.readLine();
sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "IN FROM SERVER: " + modifiedSentence);
// }
Thread.sleep(1000);
} catch (IOException e) {
connectionLost();
break;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The thread that makes the socket:
public void run() {
setName("AttemptConnectionThread");
connectionStatus = TCP_SOCKET_STATUS_CONNECTING;
try {
SocketAddress sockaddr = new InetSocketAddress(serverIP, port);
tempSocketClient = new Socket(); // Create an unbound socket
// This method will block no more than timeoutMs. If the timeout occurs, SocketTimeoutException is thrown.
tempSocketClient.connect(sockaddr, timeoutMs);
OutStream = new DataOutputStream(tempSocketClient.getOutputStream());
InStream = new BufferedReader(new InputStreamReader(tempSocketClient.getInputStream()));
socketClient = tempSocketClient;
socketClient.setTcpNoDelay(true);
connected();
} catch (UnknownHostException e) {
connectionFailed();
} catch (SocketTimeoutException e) {
connectionFailed();
} catch (IOException e) {
// Close the socket
try {
tempSocketClient.close();
} catch (IOException e2) {
}
connectionFailed();
return;
}
}
Server:
public static void main(String[] args) throws IOException {
String clientSentence;
String capitalizedSentence;
try {
ServerSocket welcomeSocket = new ServerSocket(8888);
SERVERIP = getLocalIpAddress();
System.out.println("Connected and waiting for client input!\n Listening on IP: " + SERVERIP +"\n\n");
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
while(true)
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clientSentence = inFromClient.readLine();
System.out.println("clientSentance == " + clientSentence);
String ip = connectionSocket.getInetAddress().toString().substring(1);
if(clientSentence != null)
{
System.out.println("In from client ("+ip+")("+ System.currentTimeMillis() +"): "+clientSentence);
capitalizedSentence = clientSentence.toUpperCase() + '\n';
outToClient.writeBytes(capitalizedSentence + '\n');
System.out.println("Out to client ("+ip+"): "+capitalizedSentence);
}
}
} catch (IOException e) {
//if server is already running, it will not open new port but instead re-print the open ports information
SERVERIP = getLocalIpAddress();
System.out.println("Connected and waiting for client input!\n");
System.out.println("Listening on IP: " + SERVERIP +"\n\n");
}
}
Thanks in advance!
Edits:
added the server code after updating
I tried messing around with setting the SoTimout for the socket but took that back out
Your server is specifically designed to receive exactly one line from a client and send exactly one line back. Look at the code:
while (true) {
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient = new BufferedReader(
new InputStreamReader(connectionSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(
connectionSocket.getOutputStream());
clientSentence = inFromClient.readLine();
String ip = connectionSocket.getInetAddress().toString()
.substring(1);
System.out.println("In from client (" + ip + "): "
+ clientSentence);
if (clientSentence != null) {
capitalizedSentence = clientSentence.toUpperCase() + '\n';
System.out.println("Out to client (" + ip + "): "
+ capitalizedSentence);
outToClient.writeBytes(capitalizedSentence + "\n");
}
Notice that inside the loop it accepts a new connection, reads exactly one line, and then writes exactly one line. It doesn't close the connection. It doesn't sanely end the conversation. It just stops reading.
A client that worked with this server would have to connect, send exactly one line, read exactly one line back, and then the client would have to close the connection. Your client doesn't do that. Why? Because you had no idea that's what you had to do. Why? Because you had no design ... no plan.
So that's your specific issue. But please, let me urge you to take a huge step back and totally change your approach. Before you write a single line of code, please actually design and specify a protocol at the byte level. The protocol should say what data is sent, how messages are delimited, who sends when, who closes the connection, and so on.
Otherwise, it's impossible to debug your code. Looking at the server code above, is it correct? Well, who knows. Because it's unclear what it's supposed to do. When you wrote the client, you assumed the server behaved one way. Was that assumption valid? Is the server broken? Who knows, because there's no specification of what the server is supposed to do.
You need to check if there is data available:
if (InStream.available > 0) {
String modifiedSentence = InStream.readLine();
sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "IN FROM SERVER: " + modifiedSentence);
}
But to be honest, even that is not ideal because you have no gurantee that the eond-of-line will have been received. If the server sends a few bytes but never sends the end-of-line then you will still be blocking forever. Production socket code should never rely on readLine but instead read into a buffer and check that buffer for end-of-line (or whatever criteria your protocol needs).
Didn't read closely enough, I thought InStream was an InputStream instance. InputStream has available. InputStreamReader has ready (which in turn calls InputStream.available. As long as you keep a refernce to either of these then you can see if data is available to be read.

getSocketAddress() method causes delay which leads to communication lag in Android

I'm developing a UDP responder to handle basic SSDP commands. The purpose of this piece of code is to do auto discovery, so when the server sends a multicast to a specific group all other subscribed devices should send back a UDP packet announcing its presence to the host and port of who sent the multicast. My android device receives and sends the packet just fine but because it takes too long to get back the SocketAddress object from getSocketAddress() method the server times out, closes the listening port and never gets a packet back from the android device.
Here's my code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MulticastSocket ms = null;
byte[] packBuf = new byte[128];
try {
ms = new MulticastSocket(32410);
ms.joinGroup(InetAddress.getByName("239.255.255.250"));
} catch (IOException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
while (true)
{
DatagramPacket receivedPack = new DatagramPacket(packBuf, packBuf.length);
try {
ms.receive(receivedPack);
Log.d(TAG, "Received data");
} catch (IOException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
String responseStr = "HTTP/1.0 200 OK\n" +
"Content-Type: app\n" +
"Resource-Identifier: 945e7dd5913ab45f1db4f271a1620b9471fb7d4d\n" +
"Name: Test App\n" +
"Port: 8888\n" +
"Updated-At: 1319511680\n" +
"Version: 0.9.3.4-29679ad\n" +
"Content-Length: 23\n\n" +
"<message>test</message>";
byte[] response = responseStr.getBytes();
DatagramSocket sendSocket = null;
try {
sendSocket = new DatagramSocket();
} catch (IOException e2) {
// TODO Auto-generated catch block
Log.e(TAG,"Erro",e2);
}
DatagramPacket outPack;
try {
outPack = new DatagramPacket(response, responseStr.length(), receivedPack.getSocketAddress());
sendSocket.send(outPack);
} catch (UnknownHostException e1) {
Log.e(TAG,"Erro",e1);
}
catch (IOException e) {
Log.e(TAG,"Erro",e);
}
catch (Exception e)
{
Log.e(TAG,"Erro",e);
}
}
}
Any ideas?
thanks in advance,
fbr
The most likely problem is that getSocketAddress() is trying to resolve the DNS name of the IP address, which is timing out either due to it being a multicast address or just general DNS lag.
The InetSocketAddress class has a constructor option needResolved which can control this behavior. Unfortunately, it does not appear that DatagramPacket.getSocketAddress() allows you to specify that you want that set to false.
This is apparently a known issue, with some recent discussion of it here:
Issue 12328: DatagramChannel - cannot receive without a hostname lookup
The thread suggests that this has been fixed in Android 3.0, and offers a couple of workarounds for Android 2.0 which may or may not work.
In your case, you could try creating an InetSocketAddress set to INADDR_ANY and port 0 with needsResolved set to 0, and then pass that in when you create receivedPack. Hopefully receive() will reuse that and remember the setting.
2 things come to mind...
1) What happens when you change:
outPack = new DatagramPacket(response, responseStr.length(), receivedPack.getSocketAddress());
to
outPack = new DatagramPacket(response, responseStr.length(), receivedPack.getAddress(), receivedPack.getPort());
2) I remember having this sort of problem with an embedded Java on a Home Automation system. Our short term solution was to put most of the machine and multicast addresses in the hosts file. Long term we ended up with a local DNS server.
There is a parameter somewhere in the Java Network stack that tells it how long to cache DNS failures in memory. We cranked that number up to, I think, 5 minutes instead of 10 seconds.

Categories

Resources