I am trying to write client for Android which is supposed to communicate with PC server application on local network. Server app is written by my friend in C#. Currently there is an iPhone app that is using this server application with no problems.
I have very simple code for TCP client:
1. Socket s = new Socket(server, port);
2. OutputStream out = s.getOutputStream();
3. PrintWriter output = new PrintWriter(out);
4. output.println("ACTION=Next&VALUE=0&");
5. BufferedReader input = new BufferedReader(new nputStreamReader(s.getInputStream()));
6. String st = input.readLine();
I went through many TCP implementation examples, and they are all similar. Pretty much like my code above. My app freezes on line 6 when I try to read response from the server.
It doesn't cause any errors (no exceptions), nothing shows in debugger, just timeout error after awhile. Server is supposed to return string after executing my action in line 4.
I don't understand why this code hangs. Input is not NULL (I've checked it). I would expect some exception to be thrown or simply empty string to be returned.
So? What am I missing? Could it be problem with some special characters that server app is sending and android can't handle that? Do I need any special permission in my manifest?
I am positive that I have correct IP address and correct port number. I can see that on server application running on my PC.
Thanks.
String st = input.readLine(); Does this command make the program wait until something is being read or it just takes straight whatever is in the buffer. I guess you will need to check continuosly if something came from the server. I mean, you need one infinite loop, something like
While (True){
st = input.readLine();
This will check if anything came the whole time. If u dont use it and if String st = input.readLine(); command doesnt make the program wait, then your code will end without taking anything.
You of course need internet permission in the manifest.
If it were me I'd add instrumentation to the server so that it can tell you when there's been a connection, when that connection has received data, and when a reply is being sent. Or else run tcpdump on the server.
You could also temporarily try grabbing the input character by character rather than a whole line at a time.
Try to figure out how far the "conversation" is progressing so you can figure out where it is really getting stuck
Related
im trying to control a bluetooth bracelet with vibration function via HFP (hands free profile) in Android. I've been able to connect to the bracelet and access the input- and outputstream.
My goal is to simulate an incoming call so that the bluetooth bracelet starts vibrating (which seems to be the only way to do that). To do this, im using AT commands. In the bluetooth specs at https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=238193 on page 22 you can see the handshake to establish service level connection.
I need to establish this connection to use the "+CIEV" command (see handshake page 48).
But when my bracelet returns the command "AT+CIND=?" I dont know how to respond. I can't find any hints on how to answer with the "CIND:" command. Also I dont know how to send the acknowledgement (is it just "OK"?).
That might even be the completely wrong way to do this. Every suggestion is appreciated. I only found one post on stackoverflow that helped me in some way, rest of the posts I found were unanswered.
By the way, im using a smartphone with Android 4.1.2. The bracelet supports HFP and HSP. Thanks in advance.
UPDATE 10/29/2014
===== Connection through RFCOMM Socket established at this point =====
// read AT+BRSF=0 from device
byte[] buffer = new byte[200];
mBluetoothSocket.getInputStream().read(buffer);
Log.d(TAG, new String(buffer).trim());
//write answer BRSF: ...
mBluetoothSocket.getOutputStream().write("+BRSF=20\r".getBytes());
mBluetoothSocket.getOutputStream().write("OK\r".getBytes());
// read AT+CIND=? command
buffer = new byte[200];
mBluetoothSocket.getInputStream().read(buffer);
Log.d(TAG, new String(buffer).trim());
//write answer CIND: ...
mBluetoothSocket.getOutputStream().write("+CIND: (\"battchg\",(0-5)),(\"signal\",(0-5)),
(\"service\",(0,1)),(\"call\",(0,1)),(\"callsetup\",(0-3)),
(\"callheld\",(0-2)),(\"roam\",(0,1))".getBytes());
mBluetoothSocket.getOutputStream().write("OK".getBytes());
// read AT+CIND?
buffer = new byte[200];
mBluetoothSocket.getInputStream().read(buffer);
Log.d(TAG, new String(buffer).trim());
Following the procedure of the protocol, I should receive the "AT+CIND?" command and then I could send the command "+CIND: 5,5,1,0,0,0,0", but...I dont receive the "AT+CIND?" command. Actually im not receiving anything. Am I missing something? Sending an "OK" doesnt change anything btw...
I was fiddeling with exaclty the same problem. After days of trial and error, I finally got it to work.
I think it depends on the speed at wich you answer the HF's commands, as well as on the correct line-endings ("COMMAND").
Here is my DroidScript which works. It's not cleaned up, but it works.
https://gist.github.com/t-oster/68a568ac4c4e133f67ac
Also, the one example I found that seemed to almost work, it's expecting the responses to be top and tailed with crlf:
"\r\n+BRSF=20\r\n"
"\r\nOK\r\n"
Still struggling with the rest of it myself.
refer to bluetooth hfp 1.5 spec in which you can understand CIEV response
normally when not in any call setup, response can be +CIND = 1,0,0,0,5,0,5
Note these values are based on the hfp spec, on incoming call return +CIEV: ,
ind- indicator for callsetup and value as 1 and then RING commands to the bracelet
I am using the class HttpUrlConnection for requesting JSON responses
I realized that no matter if I set or not
System.setProperty("http.keepAlive", "false");
The first response is always going to take longer, while the next responses are very quick, with and without keepAlive. I am not even using SSL.
Notice that, my app doesn't need to perform any authentication with the server, so there isn't any startup call to the webservices. The first request I make to the webservices is actually the very first.
I am also verifying server-side with "netstat", that by setting keepAlive false on the Android client the connections disappear straight away, while without specifying keepAlive false they keep staying as "ESTABLISHED".
How can you explain that subsequent responses are quicker even if the connection doesn't persist?
ANDROID CODE:
line 1) URL url = new URL(stringUrl);
line 2) HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
line 3) InputStream instream = new BufferedInputStream(urlConnection.getInputStream());
Until line 2 everything always gets executed very quickly, either with keepAlive or not. Line 3 in the first request takes around 3 seconds, while in all subsequent always less than 1 second. Each request is about 0.5KB gzipped.
SYSTEM:
I am testing using a Nexus 5, connected via 3G
My webservices are written in Go, running on a CentOS 6.4 linux server
I am using standard tcp v4
UPDATE:
For the moment I have decided to use a trick: when the fragment is resuming, I make a HTTP HEAD request to the server. In this way all subsequent calls in the next 10 seconds are very quick. If the user waits more than 10 seconds then the first one will be slow, and the next ones will be quick again. This is all happening without using KeepAlive.
It's a really big mistery now. It looks like there is some kind of "awake" period which lasts for about 10 seconds. I don't think there is anything strange on my code which can result on that. Also because everything seems to happen during the line 3 I reported above.
SOLVED! thanks to Mark Allison!
Here is a very clear explanation:
http://developer.android.com/training/efficient-downloads/efficient-network-access.html
Also, everything can easily be monitored using Android DDMS's Network Statistics. If you wait some seconds (let's say 20) from last request, you can see that it takes 2 seconds to transmit a new request.
I suspect that the lag that you are seeing is simply down to the cellular radio transitioning from either low power or idle state to full power (which can take over 2 seconds).
Check out Reto Meier's excellent DevBytes series on Efficient Data Transfer for an in-depth explanation of what's going on.
The first request cannot leverage a keep-alive obviously, because thankfully Android doesn't keep the connections alive for minutes or hours. Only subsequent requests can reuse keep-alive connections and only after a short period of time.
It's natural that you have to wait in line 3. Before something like conn.getResponseCode() or conn.getInputStream() the HttpURLConnection is in CREATED state. There is no network activity until it's getting in CONNECTED state. Buffered* shouldn't make any difference here.
I've observed long delays when using SSL and there was a time-shift between server and device. This happens very often when using an emulator which is not cold-booted. For that I've a small script running before test. It's important that PC and emulator are in the same time-zone, otherwise it's very contra-productive: (see below, because it's hard to show the command inline).
I can imagine that Android saves battery in putting 3G into sleep mode when there is no activity. This is just speculation, but you could make a test by creating some other network activity with other apps (browser, twitter, ...) and then see whether your app needs the same long "think time" until first connection.
There are other good options for losing time: DNS resolution, Server-side "sleep" (e.g. a virtual machine loading "memory" from disk).
The command to set time of Android emulator:
adb -e shell date -s `date +"%Y%m%d.%H%M%S"`
Edit
To further analyze the problem, you could run tcpdump on your server. Here is tutorial in case you don't know it well. Store the dumps to files (pcap) and then you can view them with wireshark. Depending on the traffic on your CentOS server you have to set some filters so you only record the traffic from your Android device. I hope that this gives some insight to the problem.
To exclude your server from being the bad guy, you could create a small script with curl commands doing the equivalent as your app.
You could create a super-tiny service without database or other i/o dependencies and measure the performance. I don't know "Go", but the best thing would be a static JSON file delivered by Apache or nginx. If you only have Go, then take something like /ping -> { echo "pong" }. Please tell us your measurements and observations.
Instead of using so many classes I suggest you use this library
you can have a look at here
http://loopj.com/android-async-http/
your code will become very very less , instead of declaring so many classes writing bulk of code , you can just use 4 lines of code
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
#Override
public void onSuccess(String response) {
System.out.println(response);
}
});
It is very efficient in geting the response very quickly(1 or 2 secs including parsing).
I hope this will help you out. :)
i'm developing a small example about socket connection between android and ios (via wifi), after trying, the connection hasn't been established. Here is what I have done so far, I created a server on ios (used Bonjour to publish the service). I also created a client on android. However, after starting the server on ios, I also got the log:
ServerSocketConnection[3487:c07] Bonjour Service Published: domain(local.) type(_serversocket._tcp.) name(Macmini) port(54065)
Which means the server starting ok.
To the client part(android), I created the client through Socket class, some few lines of code:
Socket s = new Socket("local.", 54065);
OutputStream out = s.getOutputStream();
PrintWriter output = new PrintWriter(out);
output.println("Hello Android!");
BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
String st = input.readLine();
Putting it into AsyncTask to execute. However, I got the UnknowHostException:
08-06 12:45:44.460: W/System.err(873): java.net.UnknownHostException: Unable to resolve host "local.": No address associated with hostname
I'm a newbie to this kind of problem so any ideas what the problem is? I know it's related to the "host" thing but need the way to fix it.
*Note: I run 2 apps on 2 simulators (ios and android) as the same wifi network and same MAC, maybe this is the problem? any help would be appreciated and sorry for my English, it's not my native one.
Use the actual IP address of the iPhone instead of 'local.'.
On Android you can find a phone's IP via Settings -> WiFi -> Advanced. Not sure if iPhone offers the same option.
ps. Also be sure to have the internet permission in your manifest;
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
I am new to android and is trying to develop an application. I have a local server that has the address like http://abc:9070/
i.e: the server is running only on port number 9070 in my laptop.
Now i want to debug my program using a android device and i have to make sure that the android device listens to port number 9070, So that i can make the post http request call to the url and fetch some information.
Can someone tell me how can i make my device to listen to port number 9070?
Also can someone tell me whether changing default port number of adb solve this.
I have tried a lot to search for a solution. But i am not able to come up with any good answers.
Thanks in advance.
Nobody has expressed an opinion yet. May be the question is not clear, at least I found it very difficult to understand what you are trying to do.
You say you have a server (laptop) listening on port 9070 and you want a device to connect to this server thru this port? Is that right?
Have you try, from your device, launch the navigator and connect to that address? http://abc:9070
Anyway, the java code to make a socket connection is something similar to this:
try
{
Socket clientSocket = new Socket("YOUR_LAPTOP_IP", 9070);
// 1024 is an arbitrary number, could be 512, 65535, etc
byte[] buffer = new byte[1024];
int ret=0;
while ((ret=clientSocket.getInputStream().read(buffer)) > 0)
{
// from now on it's up to you what to do with the data you read
}
clientSocket.close();
}
catch (Exception e)
{
e.printStackTrace();
}
I'm using Eclipse for an android application. I'm starting two emulators and sending a message between them. There is a server running on both of them and a new message creates a client socket and sends the message over it.
I can't see the message being received by the server. And when I debug step by step, it doesn't proceed after the in.readLine() call, it just says "stepping": http://i.imgur.com/8Jcxl.png (The code you see in the image is the server code).
Can anybody tell me what is happening and what I can do to correct it?
That means that the readLine() method blocks until it finds an EOL character, or the end of the stream has been reached. Make sure the client actually sends an EOL character or closes its socket.