I'm developing an Android application.
This application will have a server to start a DatagramSocket as a server. It will wait for incoming message. When the socket get a message I will process it.
To start a UDP Server socket I'm going to use a Local Service. This service will have a worker thread where I'm going to listen to incoming messages.
This is my unfinished Local Service implementation:
public class UDPSocketBackgroundService extends Service
{
private static final String TAG = "UDPSocketBackgroundService";
private ThreadGroup myThreads = new ThreadGroup("UDPSocketServiceWorker");
private Handler mServiceHandler;
#Override
public void onCreate()
{
super.onCreate();
Log.v(TAG, "in onCreate()");
}
#Override
public IBinder onBind(Intent arg0)
{
try
{
new Thread(myThreads, new UDPServerThread("X", 8888)).start();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
And this is my also unfinished Worker Thread implementation:
public class UDPServerThread extends Thread
{
private static final int MESSAGE_SIZE = 256;
protected DatagramSocket socket = null;
protected boolean end = false;
public UDPServerThread(String serverName, int port) throws IOException
{
super(serverName);
socket = new DatagramSocket(port);
}
public void run()
{
while (!end)
{
try
{
byte[] buf = new byte[MESSAGE_SIZE];
// Wait an incoming message.
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
// TODO: Notify Service with packet received
}
catch (IOException e)
{
// TODO Mensaje de error.
e.printStackTrace();
}
}
}
}
Those classes have their own file (they are on different files).
Here:
socket.receive(packet);
//TODO: Notify Service with packet received
How can I notify service that we have received a packet? I want to send to service that packet also.
Here there is an example on how to communicate from Main thread to worker thread. But, I don't need that, I'm looking for an example on how to communicate from worker thread to service.
I've found this example, but I don't understand it very well because on that example both classes are declare it on the same file.
As you can see, I'm a newbie on Android development.
If you know a better approach, please tell me.
When you create the UDPServerThread, you could pass in a reference to the UDPSocketBackgroundService and then call a method on it (processPacket() for example) when packets are received. This processPacket() method will need to use some sort of synchronization.
Here's a small code excerpt of the related functions:
public class UDPSocketBackgroundService extends Service
{
....
#Override
public IBinder onBind(Intent arg0)
{
try
{
new Thread(myThreads, new UDPServerThread(this, "X", 8888)).start();
// Notice we're passing in a ref to this ^^^
}
...
}
public void processPacket(DatagramPacket packet)
{
// Do what you need to do here, with proper synchronization
}
}
public class UDPServerThread extends Thread
{
private static final int MESSAGE_SIZE = 256;
protected DatagramSocket socket = null;
protected boolean end = false;
protected UDPSocketBackgroundService = null;
public UDPServerThread(UDPSocketBackgroundService service, String serverName, int port) throws IOException
{
super(serverName);
this.service = service;
socket = new DatagramSocket(port);
}
...
public void run()
{
while (!end)
{
try
{
byte[] buf = new byte[MESSAGE_SIZE];
// Wait an incoming message.
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
service.processPacket(packet);
}
...
}
...
}
}
Notice that going this approach, the UDPSocketBackgroundService is now "tightly coupled" with the UDPServerThread. Once you get this working, you may consider refactoring it with a more elegant design where there is less coupling, but for now this should get you going :)
Related
I have a UDP Server/Client running in background with Service, these are my operations:
I launch the app
The Service starts
I close the app but the Service is running in background (this is
what I want)
I send udp message and the phone receives correctly and answer me
I don't send messages for about 5 minutes
I send message, my phone doesn't answer me
I try to send another message again, my phone now answer
How could it happen? My App seems to sleep and wake up when I send the first message but it could answer only the second or sometimes I need 4-5 messages before get an answer, maybe is this latency or other?
If I flood my App it always will answer me correctly, but if I don't send messages for an amount of time it will cause the problem.
I want my App answer me everytime, even if the app is closed or the phone is locked.
This is my code:
public class UDPListenerService extends Service {
DatagramSocket socket;
private Boolean shouldRestartSocketListen = true;
Thread UDPBroadcastThread;
private void listenAndWaitAndThrowIntent() throws Exception {
try {
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
DatagramSocket serverSocket = new DatagramSocket(9876);
while (true) {
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String sentence = new String( receivePacket.getData());
System.out.println("RECEIVED: " + sentence);
InetAddress IPAddress = receivePacket.getAddress();
int port = receivePacket.getPort();
String capitalizedSentence = sentence.toUpperCase();
sendData = capitalizedSentence.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port);
serverSocket.send(sendPacket);
receiveData = new byte[1024];
}
} catch (Exception e) {
}
}
void startListenForUDPBroadcast() {
UDPBroadcastThread = new Thread(new Runnable() {
public void run() {
try {
while (shouldRestartSocketListen) {
listenAndWaitAndThrowIntent();
}
//if (!shouldListenForUDPBroadcast) throw new ThreadDeath();
} catch (Exception e) {
Log.i("UDP", "no longer listening for UDP broadcasts cause of error " + e.getMessage());
}
}
});
UDPBroadcastThread.start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
shouldRestartSocketListen = true;
startListenForUDPBroadcast();
Log.i("UDP", "Service started");
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
}
#Override
public void onDestroy() {
stopListen();
}
void stopListen() {
shouldRestartSocketListen = false;
socket.close();
}
}
The reason your app stops is because the service is put to sleep by the system. Maybe you need use the bindService() method in the calling activity.
Check https://developer.android.com/guide/components/services.html for more info about the methods and the lifecycles of services.
I am creating an application that will monitor movements in a particular Android device (client) and report such instances to another Android device (server). Also, under specific conditions, the client will take a picture and transmit the image to the server.
I am using WiFi direct to setup the connection between the two devices. After that I am using socket connections as explained in the WiFi Direct Demo. I am using port 8988 to send the motion sensor events and I am using port 8987 to send the images capture.
On the server side, I am using two different instances of the same Async Task with serversocket connecting to different ports to listen for the incoming messages. Everything works fine as long as only the motion sensor events are being sent across. The first image capture is also being sent/received correctly. However, after that the server doesn't receive any additional messages. I tried having two different Async Task classes to avoid having two instances of the same class but that didn't work as well. I also tried having one as an Async Task and another as an Intent Service but even that doesn't work.
This is IntentService I am using to send the messages across to the server.
public class MessageSender extends IntentService {
public static final String EXTRAS_TIMEOUT = "timeout";
public static final String EXTRAS_ADDRESS = "go_host";
public static final String EXTRAS_PORT = "go_port";
public static final String EXTRAS_DATA = "data";
private Handler handler;
public MessageSender(String name) {
super(name);
}
public MessageSender() {
super("MessageTransferService");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
handler = new Handler();
return super.onStartCommand(intent, flags, startId);
}
#Override
protected void onHandleIntent(Intent intent) {
String host = intent.getExtras().getString(EXTRAS_ADDRESS);
Socket socket = new Socket();
int port = intent.getExtras().getInt(EXTRAS_PORT);
byte[] data = intent.getExtras().getByteArray(EXTRAS_DATA);
int timeout = intent.getExtras().getInt(EXTRAS_TIMEOUT);
try {
socket.bind(null);
socket.connect((new InetSocketAddress(host, port)), timeout);
OutputStream stream = socket.getOutputStream();
stream.write(data);
} catch (final IOException e) {
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "Exception has occurred: " + e.getMessage(),
Toast.LENGTH_SHORT).show();
}
});
} finally {
if (socket != null) {
if (socket.isConnected()) {
try {
socket.close();
/*handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "Socket Connection closed now..",
Toast.LENGTH_SHORT).show();
}
});*/
} catch (IOException e) {
// Give up
e.printStackTrace();
}
}
}
}
}
}
This is Async Task on the server that starts listeners on two ports (8987 and 8988) to receiver the information of motion sensor events and images.
public class MessageReceiver extends AsyncTask<Void, Void, String> {
private Context context;
private int port;
private Bitmap mBitmap;
public MessageReceiver(Context context, int port) {
this.context = context;
this.port = port;
}
#Override
protected String doInBackground(Void... params) {
try {
ServerSocket serverSocket = new ServerSocket(port);
Socket client = serverSocket.accept();
InputStream inputstream = client.getInputStream();
String returnString = "";
if (port == MainActivity.PORT_SENSOR_COMM) {
// do something
} else if (port == MainActivity.PORT_IMAGE_COMM) {
//do something
}
serverSocket.close();
return returnString;
} catch (Exception e) {
return "Exception Occurred:" + e.getMessage();
}
}
#Override
protected void onPostExecute(String result) {
boolean startNewTask = true;
if (port == MainActivity.PORT_SENSOR_COMM) {
//do something
} else if (port == MainActivity.PORT_IMAGE_COMM) {
//do something
}
//doing this to start listening for new messages again
new MessageReceiver(context, port).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
#Override
protected void onPreExecute() {
}
}
I am now wondering whether Android WiFiDirect allows parallel communication between two devices on different ports. Searched the docs but could'nt find much help. What I am doing wrong? What is the correct method to accomplish what I am trying to do? Any help would be greatly appreciated. Thanks for looking.
I write an Android socket demo which just post user's input to server.
I establish a socket from android client through wifi connection, and everything goes well, the server can receive the message send from android client. The problem is, then I close WIFI of phone, but the socket can write without exception.
The code of Android client:
public class MyActivity extends Activity {
private SocketHandlerThread thread;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
thread = new SocketHandlerThread("ScoketTest");
thread.start();
}
class SocketHandlerThread extends HandlerThread {
private Socket socket;
private Handler handler;
public SocketHandlerThread(String name) {
super(name);
}
public SocketHandlerThread(String name, int priority) {
super(name, priority);
}
#Override
public void run() {
try {
socket = new Socket("192.168.60.184", 1990);
} catch (IOException e) {
Log.e("SocketTest", e.getLocalizedMessage(), e);
}
super.run();
}
Handler getHandler() {
if (handler == null) {
handler = new Handler(getLooper());
}
return handler;
}
void send(final String text) {
Runnable runnable = new Runnable() {
public void run() {
Log.e("SocketTest", "Start send text: " + text);
try {
socket.getOutputStream().write((text + "\n").getBytes());
socket.getOutputStream().flush();
} catch (Exception e) {
Log.e("SocketTest", e.getLocalizedMessage(), e);
}
Log.e("SocketTest", "Text has been send:" + text);
}
};
getHandler().post(runnable);
}
#Override
protected void onLooperPrepared() {
runOnUiThread(new Runnable() {
#Override
public void run() {
findViewById(R.id.button).setEnabled(true);
}
});
}
}
public void send(View view) {
String text = ((EditText) findViewById(R.id.text)).getText().toString();
thread.send(text);
}
}
The code of Server:
public class SocketTestServer {
ServerSocket serverSocket;
SocketTestServer() throws IOException {
serverSocket = new ServerSocket(1990);
}
void start() throws IOException {
Socket clientSocket = serverSocket.accept();
clientSocket.getInputStream();
PrintWriter out = new PrintWriter(System.out, true);
BufferedReader in =
new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
out.println(inputLine);
}
}
public static void main(String[] args) throws IOException {
SocketTestServer server = new SocketTestServer();
server.start();
}
}
I try on several phones. On Galaxy Nexus(4.2.1) an exception was thrown as expected, but on some MOTO or HTC phones socket can still write without any exception, which means I may loss some messages that I thought has been received successfully.
How could I get known that the socket connection was broken on any type of phone?
Any suggestion will be appreciated.
p.s
I know the Connective Change Broadcast, but before receive the broadcast the client may have write some message through the broken socket.
Though adding receive check on application protocol can solve the message lossing problem, I prefer to guarantee reliability on transport layer which the TCP protocol promise to do.
I use Writer & IOException in my socket, it works fine. Try this:
public static void sendUTF(String str)
{
try
{
outWriter.write(str + '\n');
outWriter.flush();
}
catch (IOException e)
{
e.printStackTrace();
outServ.setText("Connection lost!");
}
}
public static Writer outWriter = new OutputStreamWriter(outputStream, "UTF-8");
This is a problem with the TCP stack (OS level) and is a problem difficult to solve.
It happens also if the server is the one which lose connection (try to restart your server after opening the socket and no client will notice)... you will suffer a "broken pipe error" next time you send a packet through the socket.
So, there are two scenarios:
1- broken pipe when client sends information.
In this scenario you should capture the IOException and retry to open the connection (you will have to define your retry policies).
2- broken pipe when the server lose connectivity
When the server lose connection the client doesn't notice so, In this scenario you should send packets to the server in a regular basis (polling technique) and try to reconnect just in case the connection is lost.
This is needed just if you receive from the server updates, if you traffic is always client-->server only the scenario 1 applies.
Using socket connection i need to have two threads, one for reading and one for writing. I found other questions about socket connections but I don't understand how i can use the same socket in two different threads.
I have to create a socket in a different thread from the UI thread, so i need to start a thread to create the socket. Where can i start the two threads?
Sample code structure to give you an idea.
public class SocketActivity extends Activity {
Socket s;
OutputStream dout;
String ip = "127.0.0.1";
int port = 8080;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Thread(new Runnable() {
#Override
public void run() {
try {
s = new Socket(ip, port);
new Thread(new ReaderRunnable(s));
new Thread(new WriteRunnable(s));
} catch (IOException e) {
e.printStackTrace();
//Handle error state
}
}
});
}
// You can put this class outside activity with public scope
class ReaderRunnable implements Runnable {
Socket socket;
public ReaderRunnable(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
if (socket != null && socket.isConnected()) {
try {
OutputStream out = new BufferedOutputStream(socket.getOutputStream());
//Do reader code
} catch (IOException e) {
e.printStackTrace();
}
} else {
//Handle error case
}
}
}
// You can put this class outside activity with public scope
class WriteRunnable implements Runnable {
Socket socket;
public WriteRunnable(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
if (socket != null && socket.isConnected()) {
try {
InputStream out = new BufferedInputStream(socket.getInputStream());
//Do writer code
} catch (IOException e) {
e.printStackTrace();
}
} else {
//Handle error case
}
}
}
}
Judging by your question this is client side. You don't have to use the socket itself in two different threads. For the read thread you use the InputStream of the socket, and for the write thread you use the OutputStream.
That way you don't have to create a seperate thread just for the socket. Both the read and write threads can be started from the UI thread. For creating the threads i refer you to the Android Documentation Processes and Threads.
im trying to implement a tcp socket connection between an android app (as server) and a java based client running on windows. (short version below, without code)
Im using some sensor listener to implement a game movement (everybody knows this sensor based movement of racing games.
Ive implemented a service for that purpose, which is started out of the first activity. This service is implemented as follows (im just pasting the relevant code snippets, not the whole class):
public class ServerService extends Service {
ConnectionHandler conHandler;
#Override
public void onCreate() {
startListener();
}
private void startListener() {
conHandler = new ConnectionHandler(this);
conHandler.execute();
}
private void sendMessage(String s)
{
conHandler.write(s);
}
public void messageNotify(String s) {
//Log.d("receivedMessage", s);
}
}
The ConnectionHandler class:
public class ConnectionHandler extends AsyncTask<Void, Void, Void>{
public static int serverport = 11111;
ServerSocket s;
Socket c;
ConnectionListening conListening;
ConnectionWriting conWriting;
DataOutputStream dos;
DataInputStream dis;
ServerService server;
public ConnectionHandler(ServerService server)
{
this.server = server;
}
#Override
protected Void doInBackground(Void... params) {
try {
Log.i("AsyncTank", "doInBackgoung: Creating Socket");
s = new ServerSocket(serverport);
} catch (Exception e) {
Log.i("AsyncTank", "doInBackgoung: Cannot create Socket");
}
try {
//this is blocking until client connects
c = s.accept();
Log.d("ConnectionHandler", "client connected");
dis = new DataInputStream(c.getInputStream());
dos = new DataOutputStream(c.getOutputStream());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
conWriting = new ConnectionWriting(this.c, this.dos);
conWriting.execute();
conListening = new ConnectionListening(this.c, this.dis, this.server);
if(this.c != null)
{
Timer timer = new Timer();
timer.schedule(conListening, 0, 10);
}
Log.i("AsyncTank", "doInBackgoung: Socket created, Streams assigned");
return null;
}
public void write(String s)
{
conWriting.writeToStream(s);
}
public void messageNotify(String s) {
// TODO method stub
}
}
The ConnectionHandler ist implemented as AsyncTask similarly to the ConnectionWriting, so that the blocking of tcp methods doenst affect the whole communication.
The client is able to send messages to the server to. Because i dont know when this messages will arrive, im using a TimerTask which is executed every 10ms, to check if there is a new message.
ConnectionWriting looks as follows:
public class ConnectionWriting extends AsyncTask<Context, Void, Boolean>{
public DataOutputStream dos;
Socket c;
public ConnectionWriting(Socket c, DataOutputStream dos) {
this.dos = dos;
this.c = c;
}
#Override
protected Boolean doInBackground(Context... params) {
return true;
}
public void writeToStream(String s) {
try {
if (c != null){
//Log.i("AsynkTask", "writeToStream");
dos.writeBytes(s+"\n");
dos.flush();
Log.i("AsynkTask", "write: " +s);
} else {
Log.i("AsynkTask", "writeToStream : Cannot write to stream, Socket is closed");
}
} catch (Exception e) {
Log.i("AsynkTask", "writeToStream : Writing failed");
}
}
}
And the ConnectionListening class:
public class ConnectionListening extends TimerTask{
public DataInputStream dis;
Socket c;
ServerService server;
public ConnectionListening(Socket c, DataInputStream dis, ServerService server)
{
this.c = c;
this.dis = dis;
this.server = server;
}
#Override
public void run() {
String message = "";
try {
if (c != null) {
//Log.i("AsynkTask", "readFromStream : Reading message");
message = dis.readLine();
Log.i("AsynkTask", "read: " + message);
} else {
Log.i("AsynkTask", "readFromStream : Cannot Read, Socket is closed");
}
} catch (Exception e) {
Log.i("AsynkTask", "readFromStream : Writing failed");
}
if(message != null)
{
this.server.messageNotify(message);
}
}
}
I choose this complex, asynchronous way because the server is almost continuous sending data to the client and there are situations where the client has to send data back.
With the traditional way of using tcp sockets, it is not possible to realise a non blocking communication, so that means if the server is sending (writing), the read function blocks and i will never get the client message.
to keep it short:
Ive tested my approach but the server is always sending his data first and then getting the client messages. It is not asynchronous!? :-/
Maybe anybody can help me to solve this problem.
Or is there even a simpler way to implement that approach?
It is necessary that the communication is asynchronous! And the read has to be done automatically (what i tried to implement with this polling approach).
Ive read that i can use a single thread for the reading and one for the writing, but then i have a problem with using the write functionality (dont know how to call a function in a running thread) and with calling functions in my activities.
Im thankful for every help!
regards