Why AsyncTask to avoid "NetworkOnMainThreadException" is not working? - java

Trying to implement a simple UDP Client/Server datagram between an AndroidStudio-Java application as a client, to a Visual Studio C# Server. I am completely sure of the server side being working.
Here is a UDP Client and on a ButtonClick a UDP message should be sent to the localhost on port 15000 "for now".
my StackTrace popped the Android.os.NetworkOnMainThreadException Error. I found here that I can use an easy solution which is to import StrictMode and set a new policy to permitAll(). However still my application couldn't work and literally nothing happens on ButtonClick "No Exception to trace + No received message" and here is my code:
ButtonOne.setOnClickListener(
new Button.OnClickListener() {
public void onClick(View v) {
TextView TextOne = (TextView) findViewById(R.id.TestText);
TextOne.setText("Hi");
String host = "127.0.0.1"; // localhost
int port = 15000;
String message = "Test";
DatagramSocket dsocket = null;
if (android.os.Build.VERSION.SDK_INT > 9)
{
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
try {
// Get the Internet address of the specified host
InetAddress address = InetAddress.getByName(host);
// wrap a packet
DatagramPacket packet = new DatagramPacket(
message.getBytes(),
message.length(),
address, port);
// Create a datagram socket, send the packet through it, close it.
dsocket = new DatagramSocket();
dsocket.send(packet);
dsocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
);
Then I found here here that it's strongly not recommended to use StrictMode and that I need to use AsyncTask. However on Android Documentation it says "AsyncTask must be subclassed to be used. The subclass will override at least one method (doInBackground(Params...)), and most often will override a second one (onPostExecute(Result).)" which I don't get because each time I add Async within MainActivity class I get errors and it's frustrating..
Is't okay to use StrictMode for this simple task? If yes, why it's not working? If No, can anyone tell me please how to import AsyncTask into this piece of code? and should I use Params, Progress, Result functions??

Since your packet is send and forget and you do not monitor its progress or do something at its end, you do not need async task. You need to start network activity in a new thread. The code is below, may have minor compilation issues since I do not have access to one right now.
ButtonOne.setOnClickListener(
new Button.OnClickListener() {
public void onClick(View v) {
TextView TextOne = (TextView) findViewById(R.id.TestText);
TextOne.setText("Hi");
String message = "Test";
Thread networkThread = new Thread() {
String host = "127.0.0.1"; // localhost
int port = 15000;
DatagramSocket dsocket = null;
public void run() {
try {
// Get the Internet address of the specified host
InetAddress address = InetAddress.getByName(host);
// wrap a packet
DatagramPacket packet = new DatagramPacket(
message.getBytes(),
message.length(),
address, port);
// Create a datagram socket, send the packet through it, close it.
dsocket = new DatagramSocket();
dsocket.send(packet);
dsocket.close();
} catch (Exception e) {
e.printStackTrace();
}//catch
}//run
};// Networkthread
networkThread.start();//networkThread.start()
}//onClick
}//onClickListener
);//setOnClickListener

Related

Connect two Android devices using the socket through the Router

Android especially.
I will try to establish a connection between two devices (android - android) where one will create a server socket, connect the other device to the client, close the socket, and the connection between the two devices remains. So simple.
Server
#Override
public void onResume() {
super.onResume();
//// !!! only for test !!!
(new Thread(new Runnable() {
#Override
public void run() {
try {
int port = 33000;
SocketAddress allInterfaces = new InetSocketAddress("0.0.0.0", port);
ServerSocketChannel channel = MuxServerSocketChannelFactory
.openAndBindServerSocketChannel(null, allInterfaces, 3);
ServerSocket server = channel.socket();
Socket socket = server.accept();
Log.i("test", "host was connected!!!: " + socket.getInetAddress().getHostAddress());
callback.onConnected(socket);
server.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
})).start();
if (true) return;
//// !!! end test on real device !!!
}
Client
int privateServerPort = 33000;
int publicServerPort = 25000;
InetAddress privateServerIpAddr = InetAddress.getByName("172.23.9.120");
InetAddress publicServerIpAddr = InetAddress.getByName("xx.xx.xx.xx"); // correct IP address
Socket socket = new Socket(publicServerIpAddr, publicServerPort,
privateServerIpAddr, privateServerPort);
// never connected
The problem arises when these devices are not in one LAN or in one, but via a VPN. It is not possible to create this connection at this time.
I've been looking for a long time here (Stackoverflow), but it does not work for me. Some of the Libraries I tried:
Portmapper
// Discover port forwarding devices and take the first one found
List<PortMapper> mappers = PortMapperFactory.discover(networkBus, processBus);
PortMapper mapper = mappers.get(0);
// mappers always return null
Cling
final PortMapping desMapp = new PortMapping(
33000,
Tool.getLocalHost(false).getHostAddress(),
PortMapping.Protocol.TCP
);
UpnpService service = new UpnpServiceImpl(new AndroidUpnpServiceConfiguration());
RegistryListener registryListener = new PortMappingListener(desMapp) {
#Override
public synchronized void deviceAdded(Registry registry, Device device) {
super.deviceAdded(registry, device);
// this callback is never call
}
};
service.getRegistry().addListener(registryListener);
Collection<Device> all = service.getControlPoint().getRegistry().getDevices();
// the value all has 0 size
service.getControlPoint().search();
Thread.sleep(5000); // anything value
all = service.getControlPoint().getRegistry().getDevices();
// again the size is 0
Is there a really simple example of How the server and client should look?
All IP addresses and ports i know. I'm testing it on Huawei P9 Lite, Elephone P9000.
I do not work with UPnP, NAT and so on.
Thank you very much for your help.

Java-Client connecting to C# Server: Connection Timeout

I am trying to connect two Android devices to a c#-server and I always get a connection timeout.
The java-code is simple:
Socket socket = new Socket(mAddress, PORT);
If I start a java-server on the pc then the connection is successful. So its not a network/firewall problem.
But my c#-server just won't accept any connections, code:
private TcpListener serverSocket;
private TcpClient clientSocket1;
private TcpClient clientSocket2;
private void Form1_Load(object sender, EventArgs e)
{
serverSocket = new TcpListener(IPAddress.Any, port);
clientSocket1 = default(TcpClient);
clientSocket2 = default(TcpClient);
serverSocket.Start();
clientListenerThread = new Thread(wait4Clients);
clientListenerThread.Start();
}
private void wait4Clients()
{
logToConsole("Clientlistener started");
clientSocket1 = serverSocket.AcceptTcpClient();
logToConsole("Client No 1 started!");
clientSocket2 = serverSocket.AcceptTcpClient();
logToConsole("Client No 2 started!");
}
I also tried System.Net.Sockets.Socket instead of System.Net.Sockets.TcpClient, didnt worked either.
Thanks a lot
EDIT: Seems the code is perfectly fine. If I run the exe and not debug mode via Visual Studio, everything works. So the debug mode somehow prevents the server socket from working correctly. Any ideas why this happens?
// TCP Server C#, look at [msdn][1]
try
{
// Set the TcpListener on port 8080 of Any IP Address.
TcpListener server = new TcpListener(IPAddress.Any, 8080);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[1024];
String data = null;
// Enter the listening loop.
while(true) {
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
data = null;
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while((i = stream.Read(bytes, 0, bytes.Length))!=0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
// Send back a response.
stream.Write(msg, 0, msg.Length);
Console.WriteLine("Sent: {0}", data);
}
}

Sending a string through a socket using TCP

I am trying to send a string (and later also an image) from one Android app, to another Android app. I know that I am very close.
The code "SendString" is one Android app on one phone. And the code "AppListener" is on the other phone. "SendString" seems to be working correctly and sending the string because all of my print statements are printing.
"SendString", which is sending a string to "AppListener":
(the string that I am sending "applicationName" is getting passed to "SendString" from a different activity in the project)
I know this code is working because I get all the print statements in "try" and it never gets passed to the catch Exception.
public class SendString extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
Log.d("tag_name", "Entered AsyncTask");
String applicationName = params[0];
// SEND APPLICATION NAME AND ICON TO OTHER APP
try {
Log.d("tag_name", "TRY TO SEND STRING");
Socket socket = new Socket("192.168.0.26", 1755);
DataOutputStream DOS = new DataOutputStream(socket.getOutputStream());
DOS.writeUTF(applicationName);
Log.d("tag_name", "Application Name Sent!");
socket.close();
}
catch (Exception e){
Log.d("tag_name", "Did not send string");
}
return null;
}
}
Here is the other Android app code that is listening for a port connection, and then it should be receiving the string from "SendString".
public class AppListener extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... uri) {
String msg_received = null;
System.out.println("LISTENING FOR LAST INSTALLED APP");
try {
System.out.println("TRY");
ServerSocket socket = new ServerSocket(1755);
System.out.println("Connect to Socket and listening");
Socket clientSocket = socket.accept(); //This is blocking. It will wait.
System.out.println("This should print after connection");
DataInputStream DIS = new DataInputStream(clientSocket.getInputStream());
msg_received = DIS.readUTF();
System.out.println("Message from server" + msg_received);
clientSocket.close();
socket.close();
} catch (Exception e) {
System.out.println("Did not connect to SendString");
}
System.out.println("Return Statement is Reached");
return msg_received;
}
}
The problem is that it seems to be getting stuck at the line
Socket clientSocket = socket.accept(); //This is blocking. It will wait.
because I never get the print statement "this should print after connection", but I get all the print statements before that. Does anyone see what the problem is and why my AppListener activity seems to not connect to the port to receive the string, even though I know that the "SendString" app is connecting and sending the string as it should be (because I see all the print statements).
Does anyone see what the problem is and why my Client seems to not connect to the port to receive the string, even though I know that the server side is connecting and sending the string as it should be.
You have 'server' and 'client' mixed up. Clients connect: servers accept.
Your real server, which you described as your client, isn't accepting a connection.
This can only mean that your real client, which you described as your server, isn't creating one.
You must have either not executed your real client at all, or else got a ConnectException you haven't told us about.

TCP connection to send and receive Java/Android with Visual Basic .NET Server

I have searched everywhere to find an answer for this question:
I have a TCP client on my android application that sends an message to the server which is written in Visual Basic .NET Framework 4.
Now i want to send an message from my server to the phone over 3g, it works on wifi and 3g..
private class startserver extends Thread
{
public void server() throws Exception
{
String clientSentence;
String capitalizedSentence;
ServerSocket welcomeSocket = new ServerSocket(8765);
while(true)
{
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient =
new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
clientSentence = inFromClient.readLine();
System.out.println(clientSentence.substring(1));
msgshower = clientSentence.substring(1);
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(MainActivity.this, "Received: " + msgshower , Toast.LENGTH_LONG).show();
}
});
capitalizedSentence = clientSentence.toUpperCase() + '\n';
outToClient.writeBytes(capitalizedSentence);
}
}
#Override
public void run() {
try {
server();
} catch (Exception e) {
e.printStackTrace();
}
}
I start it in the OnCreate method
Now i send a message with (VB.NET)
Private Sub sends(ByVal message As String)
Dim tcp As New TcpClient
tcp.Connect(connectedIP, 8765)
Dim bw As New IO.BinaryWriter(tcp.GetStream)
bw.Write(message)
bw.Close()
tcp.Close()
End Sub
On wifi it will arrive, on 3g it wont... any idea's how to do this?
How do other applications archive this?
I think you're having problem with the ip address asigned by your mobile phone operator. The fact that works on wifi, but not on 3G, I think that is because your mobile(when connected through 3G) doesn't have a public IP address.
When you use SocketServer in your mobile, you're opening a port a waiting for others to connect to it. If your IP address is not reachable from internet, it won't happen (it's like having a computer behind a firewall.)
Could you try to implement the server in the VB machine, assuming that it has a public reachable address? This way, the phone wouldn't act as a server, it wouldn't be necessary to have a reachable address, as long as the VB machine has one. Then, you should use Socket class to bind to the server ip and port.
Totally confused by your code list above..
If you want to host a server in VB.NET, you should not use TcpClient class but TcpListener and if you need a better performance, use Socket class directly.
At the Android client side, you should new Socket(server,servPort), when you want to send message, write the outputStream, and read the inputStream to receive message.

Android: NAT Traversal?

It appears to me that newer Android devices run behind a NAT, where the local address is an internal carrier or LAN address and the public address is the router or carrier assigned external address.
Nevertheless, newer phones don't return the same address using the NetworkInterface as when accessing an IP detection service.
Therefore, connecting via direct P2P SocketChannels inherently fails.
Are there any common workarounds to this problem designed for the Android platform? Can anyone clarify what is causing this NAT-like security issue?
Any links to Java NAT traversal tutorials or examples (NOT essays or theses) would also be appreciated as being helpful (as I'm not quite sure how to implement it in Java).
I will of course also accept any other solutions anyone has to offer!
Almost every phone or PC you will ever touch won't have a static public IP address, and therefore will require NAT traversal. It's not because of the device; the carrier or ISP put routers between your device and the public internet. Depending on your application, usually there are NAT-traversal libraries you can use, such as ice4j or STUNT.
I do that in my own project and have found this issue is not that complicated.
Here's a very simple UDP echo server in node.js
var dgram = require('dgram');
var socket =
dgram.createSocket('udp4');
socket
.on('listening', function()
{
var address = socket.address();
console.log('socket listening ' +
address.address + ':' + address.port);
})
.on('error', function(err)
{
console.log('socket error:\n' + err.stack);
socket.close();
})
.on('message', function(message, rinfo)
{
console.log('message: ' + message + ' from ' +
rinfo.address + ':' + rinfo.port);
var msg = new Buffer(rinfo.address + ':' + rinfo.port);
socket
.send(msg, 0, msg.length,
rinfo.port, rinfo.address,
function(err, bytes)
{
//socket.close();
});
})
.bind(15000);
An android client simply send a msg to this node server
System.out.println("UDP hole punching=======================");
class IOth extends Thread {
#Override
public void run() {
String sendMsg = "UDP hole punching";
byte[] buf = sendMsg.getBytes();
DatagramPacket packet;
System.out.println(HPremoteHost); // node server IP
System.out.println(HPremotePort); // 15000
try {
packet = new DatagramPacket(buf, buf.length, InetAddress.getByName(HPremoteHost), HPremotePort);
ds.send(packet);
} catch (Exception e) {
System.out.println("error================");
System.out.println(e);
}
}
}
IOth io00 = new IOth();
io00.start();
Android Client UDP listener to obtain general msg and your own Global ip&port via UDPholepunching
class IOLoop extends Thread {
#Override
public void run() {
try {
String msg = "Native.UDPserver.open";
SocketAddress sockAddress;
String address;
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
while (true) {
try {
ds.receive(packet);
sockAddress = packet.getSocketAddress();
address = sockAddress.toString();
msg = new String(buf, 0, packet.getLength());
System.out.println(msg + " received !!! by " + address);
// this case is UDP HolePunching reaction
if (address.equals(HPaddress1)) {
System.out.println(msg + "hole punched");
// So you can obtain own Global ip& port here.
// exchange this information
// `remoteHost` `remotePort` to another client
// with some method (signaling server)
}
} catch (IOException e) {
}
}
} catch (Exception e) {
}
}
}
IOLoop io00 = new IOLoop();
io00.start();
Android Client UDP sender using other client's IP remoteHost remotePort
class IOth extends Thread {
#Override
public void run() {
String sendMsg = "This is a test message";
byte[] buf = sendMsg.getBytes();
DatagramPacket packet;
try {
packet = new DatagramPacket(buf, buf.length, InetAddress.getByName(remoteHost), remotePort);
ds.send(packet);
} catch (Exception e) {
}
}
}
IOth io00 = new IOth();
io00.start();
Look at http://sourceforge.net/projects/jnat-pmplib/
It is an implementation of NAT-PMP in java.
I've managed to establish sockets just by forwarding the sockets you're using during the connection in your router. It worked for me.
UPDATE
Find out your IP address through cmd.exe if your using Windows (ipconfig) or through a terminal session if your on Linux (ifconfig). Then connect to it through the browser and there should be a security section. Go to port forwarding and open up the ports your using when establishing you're ServerSocket and Socket. Use TCP as the protocol.
Please note that this only applies if you're trying to connect from outside your wlan.

Categories