This question already has answers here:
How can I fix 'android.os.NetworkOnMainThreadException'?
(66 answers)
Closed 5 years ago.
Help! I'm trying to do some simple java socket networking in Android Studio and I can't even get in the door. The server program seems to be working ok but the android app client crashes with the error "Unfortunately InTouch has stopped" while executing the line:
sock = new Socket("Mark2015jun08", 4415);
where the hostname I put in is what is reported by the C:>hostname command, the windows Networking Control Panel and it shows up in the DHCP table when I log into the router. It even crashes when I put in "" for a hostname which the documentation says should open a loopback. I've tried calling Socket() a dozen different ways as you can see from my code below. I could sure use some help.
Thanks, -Mark
In the android client program I put the following try statement in the onResume() method:
try {
//sock = new Socket("Mark2015jun08", 4415);
byte[] ip = {(byte)192, (byte)168, (byte)1, (byte)124};
//sock = new Socket(InetAddress.getByAddress(ip), 4415);
//sock = new Socket(InetAddress.getByName("192.168.1.124"), 4415);
//sock = new Socket("LOCALHOST", 4415);
sock = new Socket("", 4415);
// ommitted logic to set socket timeout and
// open object streams based on sock
} catch (IOException e){
sock = null;
log(e.toString());
}
Both Windows ipconfig and the router DHCP table both confirm my ip address but I still get the same error. Three different sources all agree on my hostname but no matter what string I put in for hostname, even "", it doesn't work. What am I doing wrong?
I use the following permissions in my Manifest.xml file:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
This is my server program below created in Netbeans and I run it from the Windows cmd.exe window with the command C:>java -jar intouchserver.jar. This runs the server program on the laptop and it gets to the line
sock = serversock.accept();
and stops exactly as the documentation for accept() explains. As far as I can tell it's listening to port 4415. (Note: I checked serversock before this statement: it is non-null.)
package intouchserver;
import ...
public class InTouchServer {
private static ServerSocket serversock;
private static Socket sock;
public static void main(String[] args) {
try {
serversock = new ServerSocket(4415);
sock = serversock.accept();
} catch (IOException e){
System.out.println("Can't establish socket");
System.out.println(e);
System.exit(1);
}
// ommitted logic to open object streams based on sock
// and read and write to them
}
}
I solved my own problem. It turns out that if the Socket() call is in the onResume() function where I put it then you get a fairly useless error message but if you put the Socket() command in the onCreate() function you get a much more informative error: namely "NETWORK ON THE MAIN THREAD". So then putting the Socket() call in a thread solved the problem and off I went. THANK YOU so much James K Polk for the tip on logcat. I've been struggling with those "Application has Stopped" messages all along.
Related
hi have at home a rasperry pi running a server java app, connected to de router with the dynamic DNS configured and the in/out communication ports openned.
When i run the android apication client througt 4g everithing is working sucessfull. But when i run the same app connected to the wifi on my local net, where the server are running, the server application looks like death.
Any ideas?
Thanks.
router config
I think the problem is related to your DNS. If you are connected using your wifi, you have to return a local IP-Address. Do you have any chance of configuring your router to return the raspberries local IP-Address for wifi-clients?
Take a look here: link
A simple solution, even if it is not very elegant, is adding the following conditions to your code:
If there is an error connecting to the Dyn DNS, try to connect to the local IP address. (In case you are in the Wifi LAN)
If the local IP address fails, try again your Dyn DNS (in case the user is a real user with real communication problems)
(repeat until the connection is successful)
You can also identify your testing devices (using Settings.Secure.ANDROID_ID, or the IMEI) and use the local IP only for them. Another option is making the URL configurable (with a hidden option for example).
Because of my app can run local, only needs to connect to server for updates. I have block the connection on the server app if the ip from client and server are equals.
At the moment is the best solution to keep the server app running properly.
URL whatismyip = new URL("http://checkip.amazonaws.com");
BufferedReader in = new BufferedReader(new
InputStreamReader(whatismyip.openStream()));
String ip = in.readLine();
try {
SSLServerSocketFactory sslFactory = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
SSLServerSocket ss = (SSLServerSocket) sslFactory.createServerSocket(PORT);
int idSession = 0;
while (true) {
SSLSocket socket = (SSLSocket)ss.accept();
if(socket.getInetAddress().getHostAddress().equals(ip)){
if (socket != null && !socket.isClosed()) {
socket.close();
}
}
((ServidorThread) new ServidorThread(socket, idSession)).start();
idSession++;
}
} catch (IOException ex) {
ex.printStackTrace(System.out);
Logger.getLogger(Servidor.class.getName()).log(Level.SEVERE, null, ex);
}
}
I have a datacard ZTE MF190. I want to use AT commands to register in 2G or 3G and access internet via datacard. Found this article about how to make data call:
AT+cgatt=1
AT+CGDCONT=1,”IP”,”epc.tmobile.com” //I used my operator PDP context
AT+CGACT=1,1
But ping from OS terminal shows 100% package loss.
I've tried on Ubuntu 14 and Windows 7.
How can I connect internet with AT commands using datacard on Ubuntu?
UPDATE
I gave bounty to #tripleee's answer because it's more full than first one and answered all my questions. But I'm not satisfied with answers, so I'll answer my own question in a week.
In my answer I'll show how to handle this process with Java. So, please do not move this question to other Stack Exchange websites.
Creating a connection between the card and your provider is not sufficient. You need some mechanism for creating a network interface out of this connection, and set up your network stack to route packets over this interface.
Traditionally, the pppd daemon has been a popular choice for this task. You would create a "chat script" with the commands for establishing a data call (these days, pppd might come packaged with a suitable canned script) and the daemon would handle the entire process of placing the call, authenticating, setting up a network interface over the circuit, and configuring the system to route packets over it, as well as configuring DNS etc to use it for resolver queries, etc.
I tried to sniff USB port but on this case dashboard can not connect because of busy port
It is certainly possible. See this question
Found this article about how to make data call
What that article is about is how to set up the call, not how to make it.
After you made correct setup, connect to internet with this command:
ATD*99***1#
UPDATE1: After a bit of research I believe that article was written only to promote their software and has no practical use. In reality dialing is made with pppd or wvdial
UPDATE2: We discussed ways to solve the problem in a chat room (in Russian). It turned out cnetworkmanager will be the way to go
As far as I know wvdial uses ppp daemon to connect to the internet using modem. wvdial is preinstalled on desktop version of Ubuntu.
wvdial uses a config file located /etc/wvdial.conf. Let's edit this file. Type in your terminal
sudo nano /etc/wvdial.conf
and you will see something like this
[Dialer Defaults]
Init1 = ATZ
Init2 = ATQ0 V1 E1 S0=0 &C1 &D2
Stupid Mode = yes
ISDN = 0
Modem Type = Analog Modem
New PPPD = yes
Phone = *99#
Modem = /dev/ttyUSB2
Username = ''
Password = ''
Baud = 9600
Dial Timeout = 30
Dial Attempts = 3
Explanation of all keys you can find in wvdial.conf(5) - Linux man page. If you need to change your provider dial number, username, password or any other information about connection and device you can change file content and save it.
There are 3 serial ports for ZTE MF190. Normally it's ttyUSB0, ttyUSB1 and ttyUSB2. And in my case ttyUSB2 is for internet connection. It would not work on other ports. So you need to find the right serial port for your modem.
There is an automatic configurator which edits wvdial.conf file, sets serial port baud rate etc. Since it is not always configure correctly I would not recommend to use it:
sudo wvdialconf /etc/wvdial.conf
It would be better if you configure wvdial manually.
Now, when your device connected and wvdial configured to work with device, you can execute this line from terminal:
wvdial
You will see a lot of lines. But if you see those lines - you have succeeded.
local IP address XX.XX.XX.XX
remote IP address XX.XX.XX.XX
primary DNS address XX.XX.XX.XX
secondary DNS address XX.XX.XX.XX
Now, how we can use it in programming? I'll provide some code to work with it on Java. You can use this code to dial.
public int dialer() {
// status for debug. If status == 4 then you connected successfully
int status;
// create process of wvdial
ProcessBuilder builder = new ProcessBuilder("wvdial");
try {
// start wvdial
final Process process = builder.start();
// wvdial listener thread
final Thread ioThread = new Thread() {
#Override
public void run() {
try {
final BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getErrorStream()));
// wvdial output line
String line;
while ((line = reader.readLine()) != null) {
// if "local IP address" line detected set status 1
if (line.contains("local IP address")) {
status = 1;
}
if (line.contains("remote IP address")) {
status = 2;
}
if (line.contains("primary DNS address")) {
status = 3;
}
if (line.contains("secondary DNS address")) {
status = 4;
}
}
reader.close();
} catch (final Exception e) {
}
}
};
// start listener
ioThread.start();
// wait 6 secs and return status. Some kind of timeout
Thread.sleep(6000);
} catch (Exception e) {
}
return status;
}
And here is a disconnector method. All you need is to kill wvdial process and thread will be destroyed:
public boolean disconnect() {
ProcessBuilder builder = new ProcessBuilder("pkill", "wvdial");
try {
builder.start();
return true;
} catch (IOException e) {
return false;
}
}
I want to create a super basic Android App that connects to a python server running on my PC but the python server never gets the connection
my java code:
public class WriteToSocket {
Socket sock;
public void Test() {
try {
this.sock = new Socket("PCName", 9871);
} catch (UnknownHostException e) {
System.out.println("Unknown host: PCName");
System.exit(1);
} catch (IOException e) {
System.out.println("No I/O");
System.exit(1);
}
}
public void Test1(){
try {
this.sock.close();
} catch (IOException e) {
System.out.println("No I/O");
System.exit(1);
}
}
and
public void onClick(View v) {
WriteToSocket a = new WriteToSocket();
a.Test();
}
and my python server is
import socket
sock = socket.socket()
name = "PCName"
port = 9871
sock.bind((name,port))
sock.listen(1)
s,a = sock.accept()
I expected after the button click for the python server to accept the connection (I also tried changing "PCName" to "127.0.0.1")
I've looked around but nothing helped me so far :S
Bind your server socket to one of the IP addresses of your PC which is accessible from your android, and not to 127.0.0.1. Or alternatively bind it to all available interfaces (0.0.0.0).
Then connect from your android to that IP.
E.g. if your PC has IP address 1.2.3.4 then use this IP in both applications.
Use netstat to see if the port is really open on your PC.
Check to see if your android application has the permission to use the internet (specified in the manifest: "USES_INTERNET" or something like that).
Also your python script discards the connection as soon as it is made.
In python change bind address to 0.0.0.0. It will bind for all IPs attached to your machine. Then in android app change to correct IP of your computer.
IP 127.0.0.1 is a loopback and you can't connect to it from outside of the system.
The android phone doesn't know what PCName is, change "PCName" in the python code back to '127.0.0.1', then in the android project put in the local IP address of the server.
This of course assuming that both the phone and the server are on the same local network.
Why do I get this error...
java.net.UnknownHostException: http://google.com
...when I do this in my Activity -> onCreate?
try {
Socket socket = new Socket("http://google.com", 80);
} catch(Exception e) {
Log.e(tag, e.toString());
return;
}
And yes, I do have the Internet permission set in my manifest.
<uses-permission android:name="android.permission.INTERNET" />
This is being tested on a physical Nexus S phone
Use www.google.com, without the http:// part.
Is it throwing an UnknownException or UnknownHostException?
UnknownHostException means there is a problem with the hostname lookup. Try it without the "http://" and if that doesn't work, try it with the direct IP address.
Its not your app permissions that is failing, otherwise it would throw a SecurityException.
Socket throws an
UnknownHostException - if the IP address of the host could not be determined.
Do you have Internet Access enabled? Try it with another host or with the IP and/or try restarting your phone.
Can anybody tell my why this doesn't work in the Android emulator? From the browser I have access and the server is internal. All I can think of is that I'm missing some configuration on my app so it can access the network layer.
try {
InetAddress server = Inet4Address.getByName("thehost");
//Doesn't work either
//or InetAddress server2 = Inet4Address.getByAddress(new String("192.168.1.30").getBytes());
if(server.isReachable(5000)){
Log.d(TAG, "Ping!");
}
Socket clientsocket = new Socket(server, 8080);
} catch (UnknownHostException e) {
Log.e(TAG, "Server Not Found");
} catch (IOException e) {
Log.e(TAG, "Couldn't open socket");
}
Throws an UnknownHostException
Thanks
As far as configuration goes, the only setting you should need to access the Internet from your application is the INTERNET permission, enabled by adding the following line outside the Application tags within your application Manifest.
<uses-permission android:name="android.permission.INTERNET" />
So the manifest would follow this general construction
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.apis">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name="MyApplication"
android:label="#string/application_title"
android:icon="#drawable/my_icon">
[ .. Your Activities go here ]
</application>
</manifest>
It might still not work, because of the timeout. Since you need root permissions to send an ICMP Package and the implemetation of isReachable will use the slow TCP version of ECHO. Chekcout the javaDoc.