I am trying to send UDP packets with Android to a server written in C# on my computer. When I run the app on my phone, I get an illegal state exception. I think it may have something to do with performing network operations on the main activity, but I'm not sure how to resolve that problem. Here is my client:
public class MainActivity extends Activity {
WifiManager wifi;
InetAddress dev_ip;
final int serverPort = 31337;
Thread drawThread = new Thread(new drawer());
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//set up wifi and connection
wifi = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
WifiInfo info = wifi.getConnectionInfo();
int ip = info.getIpAddress();
String ipaddr = (ip & 0xff) + "." + (ip >> 8 & 0xff) + "." + (ip >> 16 & 0xff) + "." + (ip >> 24 & 0xff);
try {
dev_ip = InetAddress.getByName(ipaddr);
} catch (UnknownHostException e) {
Toast.makeText(this, "host error", Toast.LENGTH_LONG).show();
}
if (!wifi.isWifiEnabled())
wifi.setWifiEnabled(true);
Toast.makeText(this, "IP: " + ipaddr, Toast.LENGTH_LONG).show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public void draw(View view) throws IOException, SocketException
{
drawThread.start();
}
public class drawer implements Runnable {
public void run() {
//transmit data
try {
DatagramSocket socket = new DatagramSocket(serverPort, /*myip*/);
String test_data = "It works!";
byte btest[] = new byte[50];
btest = test_data.getBytes();
DatagramPacket p1 = new DatagramPacket(btest, btest.length, /*myip*/, serverPort);
socket.send(p1);
socket.close();
}
catch (IOException e) {
}
}
}
}
LogCat:
07-27 00:10:17.155: D/CLIPBOARD(1711): Hide Clipboard dialog at Starting input:
finished by someone else... !
07-27 00:10:18.020: W/System.err(1711): java.net.BindException: bind failed: EADDRNOTAVAIL (Cannot assign requested address)
07-27 00:10:18.020: W/System.err(1711): at libcore.io.IoBridge.bind(IoBridge.java:89)
07-27 00:10:18.020: W/System.err(1711): at java.net.PlainDatagramSocketImpl.bind(PlainDatagramSocketImpl.java:68)
07-27 00:10:18.020: W/System.err(1711): at java.net.DatagramSocket.createSocket(DatagramSocket.java:133)
07-27 00:10:18.020: W/System.err(1711): at java.net.DatagramSocket.<init>(DatagramSocket.java:95)
07-27 00:10:18.020: W/System.err(1711): at com.ls.styloid.MainActivity$drawer.run(MainActivity.java:67)
07-27 00:10:18.025: W/System.err(1711): at java.lang.Thread.run(Thread.java:856)
07-27 00:10:18.025: W/System.err(1711): Caused by: libcore.io.ErrnoException: bind failed: EADDRNOTAVAIL (Cannot assign requested address)
07-27 00:10:18.025: W/System.err(1711): at libcore.io.Posix.bind(Native Method)
07-27 00:10:18.025: W/System.err(1711): at libcore.io.ForwardingOs.bind(ForwardingOs.java:39)
07-27 00:10:18.025: W/System.err(1711): at libcore.io.IoBridge.bind(IoBridge.java:87)
07-27 00:10:18.025: W/System.err(1711): ... 5 more
07-27 00:10:42.090: D/CLIPBOARD(1711): Hide Clipboard dialog at Starting input: finished by someone else... !
07-27 00:11:30.150: W/System.err(2535): java.net.BindException: bind failed: EADDRNOTAVAIL (Cannot assign requested address)
07-27 00:11:30.155: W/System.err(2535): at libcore.io.IoBridge.bind(IoBridge.java:89)
07-27 00:11:30.155: W/System.err(2535): at java.net.PlainDatagramSocketImpl.bind(PlainDatagramSocketImpl.java:68)
07-27 00:11:30.155: W/System.err(2535): at java.net.DatagramSocket.createSocket(DatagramSocket.java:133)
07-27 00:11:30.155: W/System.err(2535): at java.net.DatagramSocket.<init>(DatagramSocket.java:95)
07-27 00:11:30.155: W/System.err(2535): at com.ls.styloid.MainActivity$drawer.run(MainActivity.java:67)
07-27 00:11:30.155: W/System.err(2535): at java.lang.Thread.run(Thread.java:856)
07-27 00:11:30.155: W/System.err(2535): Caused by: libcore.io.ErrnoException: bind failed: EADDRNOTAVAIL (Cannot assign requested address)
07-27 00:11:30.155: W/System.err(2535): at libcore.io.Posix.bind(Native Method)
07-27 00:11:30.155: W/System.err(2535): at libcore.io.ForwardingOs.bind(ForwardingOs.java:39)
07-27 00:11:30.155: W/System.err(2535): at libcore.io.IoBridge.bind(IoBridge.java:87)
07-27 00:11:30.155: W/System.err(2535): ... 5 more
07-27 00:11:36.515: D/CLIPBOARD(2535): Hide Clipboard dialog at Starting input: finished by someone else... !
EDIT: There seem to be numerous problems with the server that I didn't notice before. They started happening when I rewrote the listener according to one of the answers. I sometimes get a "Cannot access a disposed object" error with label3, a socket exception 0x80004005, and still no packets received. However, when checking the socket state it appears to be readable. I probably screwed up the threading, help me fix this please. Server:
public partial class Form1 : Form
{
Socket listener;
Thread udp_listener;
public Form1()
{
InitializeComponent();
//set up listener thread
udp_listener = new Thread(listen);
udp_listener.IsBackground = true;
udp_listener.Start();
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
listener.Close();
udp_listener.Join();
}
private void listen()
{
//set up UDP
const int serverPort = 31337;
bool terminate = false;
IPHostEntry iphost = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipaddr = iphost.AddressList[0];
IPEndPoint endpoint = new IPEndPoint(ipaddr, serverPort);
listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
label3.Text = ipaddr.ToString();
try
{
do
{
byte[] buffer = new byte[100];
listener.Receive(buffer);
label3.Text = "Connected";
label3.ForeColor = Color.Red;
label3.Text = Encoding.UTF8.GetString(buffer);
}
while (!terminate);
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
finally
{
listener.Close();
}
listener.Close();
}
}
EDIT2:
I tried making a client with C# on my computer. The packet was sent but my server did not receive anything.
EDIT3: Server works fine now, but the android app refuses to run. Here's the code:
package com.tests.contest;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
public class MainActivity extends Activity {
private Socket sock;
private BufferedWriter out;
private Thread thrd;
@Override
public void onResume() {
super.onResume();
thrd = new Thread(new Runnable() {
public void run() {
while (!Thread.interrupted()) {
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
sock = new Socket("THEIP", 31337);
} catch (UnknownHostException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
out = new BufferedWriter(new OutputStreamWriter(sock
.getOutputStream()));
out.write("WORKS");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
});
thrd.start();
}
@Override
public void onPause() {
super.onPause();
if (thrd != null)
thrd.interrupt();
try {
if (sock != null) {
sock.getOutputStream().close();
sock.getInputStream().close();
sock.close();
}
} catch (IOException e) {}
thrd = null;
}
/*private void sendText() {
String text = "HI";
try {
out.write(text + "\n");
out.flush();
} catch (IOException e) {}
}*/
}
The problem occurs because I'm running network operations on the main thread, which I am clearly not doing.
In order to avoid java. lang. IllegalStateException in Java main Thread we must ensure that any method in our code cannot be called at an illegal or an inappropriate time. In the above example if we call start() method only once on thread t then we will not get any java.
To avoid the IllegalStateException in Java, it should be ensured that any method in code is not called at an illegal or inappropriate time. Calling the next() method moves the Iterator position to the next element.
The IllegalArgumentException is thrown in cases where the type is accepted but not the value, like expecting positive numbers and you give negative numbers. The IllegalStateException is thrown when a method is called when it shouldn't, like calling a method from a dead thread.
public class IllegalStateException extends RuntimeException. Signals that a method has been invoked at an illegal or inappropriate time. In other words, the Java environment or Java application is not in an appropriate state for the requested operation.
The exception is telling you exactly what to do: create the Socket
object in a separate Thread
. You can use an AsyncTask
for this as well.
The reasoning behind not allowing Sockets
on the main UI thread is that it can cause the app to get the dreaded Application Not Responding
message from waiting for a Socket
.
edit: http://thinkandroid.wordpress.com/2010/03/27/incorporating-socket-programming-into-your-applications/
You can just skip down to the client example since you already have a desktop server.
edit2: Since I happen to also be working on a C# server for my Android app, here is how my desktop app creates a listener Socket
:
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 27015); //Port 27015
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp); // Create a TCP/IP socket.
I'm almost certain that the problem lies within your server/network. The Android code to send out a simple UDP packet looks correct. You might also want to try connecting over localhost
or 127.0.0.1
by writing a simple C# client program.
edit 3:
With this basic app you should be able to connect to the server after you put the correct IP address in. Pressing Send will send some bytes to the server. Use this to make sure that your connection is working. I've confirmed that it works on my end. If this works, then I would open a new SO question for your server issues, otherwise something is wrong with your network configuration.
I think that the problem comes from the do while loop because you are attempting to modifiy a UI component ( label3 ) in the loop which is by the way a infinite loop sins the terminate variable is always false. Try getting the code witch modifies the UI ( label3.*) out of the loop.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With