I'm working on an application that receives data from a bluetooth sensor, and I need to pass that data to a server socket running on a local machine. The data received is about 40 messages per second.
First, first i tried to solve it by using a seprate AsyncTask for each write, opening the socket, writing the data and closing the socket, and it worked fine, but raised some perfomance issues, so i had to find another solution.
I wrote a service that keeps the socket connection alive, but when I try to write data to the socket, I keep getting a broken pipe exception for each write.
Here's the code for the service:
public class SocketService extends Service {
public static final String SERVERIP = "10.64.64.197";
public static final int SERVERPORT = 4444;
private DataOutputStream out;
private Socket socket;
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
SocketService getService() {
return SocketService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onCreate() {
super.onCreate();
Runnable connect = new connectSocket();
new Thread(connect).start();
}
public void sendMessage(byte[] message) {
try {
out.write(message);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
class connectSocket implements Runnable {
#Override
public void run() {
try {
Log.e("connectSocket", "Connecting...");
socket = new Socket(SERVERIP, SERVERPORT);
try {
out = new DataOutputStream(socket.getOutputStream());
Log.e("connectSocket", "Done.");
} catch (Exception e) {
Log.e("connectSocket", "Error", e);
}
} catch (Exception e) {
Log.e("connectSocket", "Error", e);
}
}
}
#Override
public void onDestroy() {
super.onDestroy();
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
socket = null;
}
And the code where I call the sendMessage method:
if (action.equals(UartService.ACTION_DATA_AVAILABLE)) {
final byte[] txValue = intent.getByteArrayExtra(UartService.EXTRA_DATA);
try {
mSocketService.sendMessage(txValue);
} catch (Exception e) {
Log.e(TAG, "data_available");
}
}
I'm stuck on this for a while now, so any help would be appreciated!
Related
I am building an application that starts a Connection via a Thread but when i initialize the Connection the Application doesn't connect and stops (it continues to work but it does nothing).
1 week ago it did work without any troubles, but when i updated Android Studio it started causing me this problem.
This is the abstract class of the Connection:
public abstract class Connection implements Runnable{
private Socket socket;
private PrintWriter writer;
private BufferedReader reader;
private Semaphore semaphore;
private ArrayList<String> messageQueue;
private Thread connection;
//private String state; // CONNECTED,RUNNING,STOPPED,RESTARTED,CLOSED
Connection(InetAddress address, int port) {
try {
socket = new Socket(address,port);
onConnectionEstablished(socket);
writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
semaphore = new Semaphore(1);
messageQueue = new ArrayList<>();
} catch (Exception e) {
close();
}
}
#Override
public void run() {
connection = Thread.currentThread();
while(!connection.isInterrupted()){
this.read();
}
}
// Checks if connection is established
boolean isConnectionEstablished(){
return socket != null && !socket.isClosed();
}
public abstract Socket onConnectionEstablished(Socket socket);
// Restarts the connection
public abstract void onConnectionClose();
// Launched when message is received
public abstract String onMessageReceived(String message);
// Launched when message is posted
public abstract String onMessagePosted(String message);
// Launched when message is sent
public abstract String onMessageSent(String message);
// Post message
public void postMessage(String message){
messageQueue.add(message);
sendMessage();
}
// Send Message
private void sendMessage() {
final String message = messageQueue.get(0);
onMessagePosted(message);
new Thread(new Runnable() {
#Override
public void run() {
try {
semaphore.acquire();
System.out.println(Colors.color("[*] Sending: \'"+message+"\' [*]","blue"));
writer.print(message);
writer.flush();
messageQueue.remove(0);
semaphore.release();
} catch (Exception e) {
close();
}
}
}).start();
onMessageSent(message);
}
// Read messages
private void read(){
try {
String message = reader.readLine();
if(message != null && message.length() > 0)
onMessageReceived(message);
else
throw new Exception();
} catch (Exception e) {
close();
}
}
// Close the connection
private void close(){
try{
connection.interrupt();
this.writer.close();
this.reader.close();
this.socket.close();
}catch(Exception e){
System.out.println(Colors.color("[X] Error while closing [X]","red"));
}
onConnectionClose();
}
// Restart the connection
void restart(){
new Thread(new Runnable() {
#Override
public void run() {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
System.out.println(Colors.color("[X] Error while restarting [X]","red"));
}
new Thread(new ConnectionInitializer()).start();
}
}).start();
}
}
While doing some debugging i found out that it apparently blocks when the socket is instantiated.
I'm trying to get working a Service that hosts a server, and whenever it receives data from it's one client it sends the data off to another server. Both of which are connected by a tcp socket that remains open indefinitely. I'm having trouble implementing single tcp sockets that both read and write correctly.
I'm receiving XML from both ends, and they're well defined. Some processing is done on the xml received and it needs to be added to a queue that handles it's order.
Ideally the connection going in either direction should remain open indefinitely.
But so far I'm seeing the Sockets just keep closing both this Service and the ServerCode are getting closed sockets and I'm not sure why.
Is there a way to establish connections to my two endpoints and keep the sockets open indefinitely?
public class routing extends Service {
private static final String TAG = "[RoutingService]";
private final IBinder mBinder = new RoutingBinder();
private final ScheduledThreadPoolExecutor mRoutingThreadPool = new ScheduledThreadPoolExecutor(2);
private boolean running = false;
private URI serverAddress;
private URI clientAddress;
private Thread serverServiceThread = new ClientService();
private Thread clientServiceThread = new ServerService();
private PriorityBlockingQueue<String> clientQueue;
private PriorityBlockingQueue<String> serverQueue;
public void setClientAddress(URI testServer) {
this.serverAddress = testServer;
this.mRoutingThreadPool.remove(clientServiceThread);
this.mRoutingThreadPool.scheduleWithFixedDelay(clientServiceThread, 0, 100, TimeUnit.MILLISECONDS);
}
public URI getServerAddress() {
return serverAddress;
}
public void setServerAddress(URI testServer) {
startRunning();
this.serverAddress = testServer;
this.mRoutingThreadPool.remove(serverServiceThread);
this.mRoutingThreadPool.scheduleWithFixedDelay(serverServiceThread, 0, 100, TimeUnit.MILLISECONDS);
}
public void startRunning() {
running = true;
}
public void stopRunning() {
running = false;
}
#Override
public void onCreate() {
super.onCreate();
serverQueue = new PriorityBlockingQueue<>();
clientQueue = new PriorityBlockingQueue<>();
}
#Override
public void onDestroy() {
stopRunning();
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public int onStartCommand(#Nullable Intent intent, int flags, int startId) {
clientAddress = URI.create("127.0.0.1:8054");
serverAddress = URI.create("192.168.2.1:7087");
startRunning();
setClientAddress(clientAddress);
setServerAddress(serverAddress);
return Service.START_STICKY;
}
public class RoutingBinder extends Binder {
public routing getService() {
return routing.this;
}
}
class ClientService extends Thread {
private Socket socket;
private Runnable ClientReader = new Runnable() {
#Override
public void run() {
if (socket != null && socket.isConnected()) {
try (InputStreamReader sr = new InputStreamReader(socket.getInputStream())) {
StringBuilder xml = new StringBuilder();
char[] buffer = new char[8192];
String content = "";
int read;
while ((read = sr.read(buffer, 0, buffer.length)) != -1) {
serverQueue.add(new String(buffer));
}
} catch (IOException e) {
Log.e("clientReader", "Error in testReading Thread.", e);
}
}
}
};
private Runnable ClientWriter = new Runnable() {
#Override
public void run() {
if (socket != null && socket.isConnected()) {
while (serverQueue != null && !serverQueue.isEmpty()) {
try (OutputStream os = socket.getOutputStream()) {
String xml = serverQueue.poll();
os.write(xml.getBytes());
os.flush();
} catch (IOException e) {
Log.e("clientWriter", "Error in testReading Thread.", e);
}
}
}
}
};
#Override
public void run() {
try (ServerSocket server = new ServerSocket(clientAddress.getPort())) {
try (Socket socket = server.accept()) {
socket.setSoTimeout(0);
Log.d("SOCKET", String.format("Local Port: %s. Remote Port: %s", socket.getLocalPort(), socket.getPort()));
this.socket = socket;
//Make the Threads
Thread reader = new Thread(ClientReader);
Thread writer = new Thread(ClientWriter);
//Start the Threads
reader.start();
writer.start();
//Start the Server
startRunning();
//Join on the Threads so this driver thread will wait until they finish.
reader.join();
writer.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
stopRunning();
}
}
class ServerService extends Thread {
private Socket socket;
private Runnable ServerReader = new Runnable() {
#Override
public void run() {
if (socket != null && !socket.isClosed()) {
try (InputStreamReader sr = new InputStreamReader(socket.getInputStream())) {
StringBuilder xml = new StringBuilder();
char[] buffer = new char[8192];
String content = "";
int read;
while ((read = sr.read(buffer, 0, buffer.length)) != -1) {
clientQueue.add(new String(buffer));
}
} catch (IOException e) {
Log.e("ServerReader", "Error in testReading Thread.", e);
}
}
}
};
private Runnable ServerWriter = new Runnable() {
#Override
public void run() {
if (socket != null && socket.isConnected()) {
try (OutputStream os = socket.getOutputStream()) {
while (clientQueue != null && !clientQueue.isEmpty()) {
String xml = clientQueue.poll();
os.write(xml.getBytes());
os.flush();
}
} catch (IOException e) {
Log.e("ServerWriter", "Error in testReading Thread.", e);
}
}
}
};
#Override
public void run() {
if (running) { //Service will keep spinning unti the testService ends the loop
try (Socket socket = new Socket(serverAddress.getHost(), serverAddress.getPort())) {
socket.setSoTimeout(0);
Log.d("SOCKET", String.format("Local test Port: %s. Remote test Port: %s", socket.getLocalPort(), socket.getPort()));
this.socket = socket;
//Make the Threads
final Thread writer = new Thread(ServerWriter);
final Thread reader = new Thread(ServerReader);
//Start the Threads
writer.start();
reader.start();
//Join on the Threads so this driver thread will wait until they finish.
writer.join();
reader.join();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Closing the input or output stream of a socket closes the other stream and the socket.
What should I do to keep the server running and listening when the application is in the background?
I'm currently throwing an error: I can't make a connection because the target computer is actively refusing to connect.
I have server on android and client on pc/python.
anyone could explain I will be grateful.
Code with my server.
public class MainActivity extends Activity {
private ServerSocket serverSocket;
Handler updateConversationHandler;
Thread serverThread = null;
private TextView text;
public static final int SERVERPORT = 8080;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.textView);
updateConversationHandler = new Handler();
this.serverThread = new Thread(new ServerThread());
this.serverThread.start();
}
#Override
protected void onStop() {
super.onStop();
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
class ServerThread implements Runnable {
public void run() {
Socket socket = null;
try {
serverSocket = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()) {
try {
socket = serverSocket.accept();
CommunicationThread commThread = new CommunicationThread(socket);
new Thread(commThread).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class CommunicationThread implements Runnable {
private Socket clientSocket;
private BufferedReader input;
public CommunicationThread(Socket clientSocket) {
this.clientSocket = clientSocket;
try {
this.input = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
try {
String read = input.readLine();
updateConversationHandler.post(new updateUIThread(read));
} catch (IOException e) {
e.printStackTrace();
}
}
}
class updateUIThread implements Runnable {
private String msg;
public updateUIThread(String str) {
this.msg = str;
}
#Override
public void run() {
if (msg == null) {
text.setText(msg);
}
else{
text.setText(msg);
createNotification();
}
}
}
void createNotification() {
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);
Bitmap icon = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
Notification noti = new NotificationCompat.Builder(this)
.setContentTitle("NOTIFICATION")
.setContentText("NOTIFICATION")
.setTicker("NOTIFICATION")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setLargeIcon(icon)
.setAutoCancel(true)
.setContentIntent(pIntent)
.build();
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(0, noti);
}}
To perform background tasks in Android you should use Services.
A service for the Server would look like:
public class MyService extends Service {
public static final String START_SERVER = "startserver";
public static final String STOP_SERVER = "stopserver";
public static final int SERVERPORT = 8080;
Thread serverThread;
ServerSocket serverSocket;
public MyService() {
}
//called when the services starts
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//action set by setAction() in activity
String action = intent.getAction();
if (action.equals(START_SERVER)) {
//start your server thread from here
this.serverThread = new Thread(new ServerThread());
this.serverThread.start();
}
if (action.equals(STOP_SERVER)) {
//stop server
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException ignored) {}
}
}
//configures behaviour if service is killed by system, see documentation
return START_REDELIVER_INTENT;
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
class ServerThread implements Runnable {
public void run() {
Socket socket;
try {
serverSocket = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()) {
try {
socket = serverSocket.accept();
CommunicationThread commThread = new CommunicationThread(socket);
new Thread(commThread).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class CommunicationThread implements Runnable {
private Socket clientSocket;
private BufferedReader input;
public CommunicationThread(Socket clientSocket) {
this.clientSocket = clientSocket;
try {
this.input = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
try {
String read = input.readLine();
//update ui
//best way I found is to save the text somewhere and notify the MainActivity
//e.g. with a Broadcast
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
In your Activity, you can start the Service by calling:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//will start the server
Intent startServer = new Intent(this, MyService.class);
startServer.setAction(MyService.START_SERVER);
startService(startServer);
//and stop using
Intent stopServer = new Intent(this, MyService.class);
stopServer.setAction(MyService.STOP_SERVER);
startService(stopServer);
}
also you have to declare the Internet permission in your AndroidManifest.xml. Add these to lines above of the tag:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Are you testing this on a local area network or through the internet(WAN)?
It must be taken into account that currently many mobile phone providers do not assign public IP addresses to the connected devices, they assign private IP and therefore the device can not act as a server due its ports are inaccessible from the WAN
I am creating bound service for socket connection.Which means it is creating a long polling connection and listens my server.If user closes the app in task manager my service is killing i have no problem with this.But when user presses the back button I am calling activity.finish() method for close app.But with this method my service doesn't kill,it is still connected to socket server.
Is this normal ? And Could be this drain the battery ?
My service:
public class SocketService extends Service {
//you need constants to tell servise and activity what you are sending a message for
public static final int REGISTER_CHAT_ACTIVITY = 1;
public static final int MESSAGE_RECEIVED = 2;
final Messenger mMessenger = new Messenger(new IncomingHandler());
Messenger chat;
private Socket socket;
#Override
public void onCreate() {
try {
socket = IO.socket("ip");
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
}
}).on("connected", new Emitter.Listener() {
#Override
public void call(Object... args) {
}
}).on("message", new Emitter.Listener() {
#Override
public void call(Object... args) {
try {
chat.send(android.os.Message.obtain(null, MESSAGE_RECEIVED, args[0]));
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
//and add all the other on listeners here
socket.connect();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (socket != null) {
socket.disconnect();
socket.connect();
} else {
try {
socket = IO.socket("ip");
socket.connect();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
class IncomingHandler extends Handler {
#Override
public void handleMessage(android.os.Message msg) {
switch(msg.what){
case REGISTER_CHAT_ACTIVITY:
chat = msg.replyTo;
break;
}
}
}
public class LocalBinder extends Binder {
SocketService getService() {
return SocketService.this;
}
}
}
I had something similar a while ago i solved the issue by using shared preferences.(Note: I dont think it's the best answer but it solved my problem)
I saved in preferences a boolean to register when i dont need the service anymore but lost reference of it.
public class YourService extends Service {
private YourService serv;
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
serv = this;
Then Somehwere on your code that the service does frequently.
if(!sharedPref.getBoolean("TurnOffService", false)){
serv.stopSelf();
}
Hope it helps.
I am facing a grave problem. Inside a service I am opening Wifi connection and closing it after my task completes. Since, a service exits at any point i face a problem wherein the connection opens and remains open.
Is there a way i can handle this as i am using START_STICKY or i will have to handle it programmatically only?
EDIT : Can i share my intent information across couple of receivers (BroadcastReceiver). For example, I will write another receiver for action android.net.wifi.wifi_state_changed and my existing receiver is for android.intent.action.PHONE_STATE.
IF that can be achieved i can do something about it.
EDIT2 : My code is as follows:
public class CallReceiver extends BroadcastReceiver {
private static final String LOG_TAG = "CallReceiver";
private static final String CALL_ACTION = "android.intent.action.PHONE_STATE";
#Override
public void onReceive(Context context, Intent callIntent)
{
Log.d(LOG_TAG, "----------------Inside onReceive of CallReceiver----------------");
if (callIntent.getAction().equals(CALL_ACTION))
{
try
{
Intent myIntent = new Intent(context, MyService.class);
context.startService(myIntent);
}
catch (Exception e)
{
e.printStackTrace();
Log.d(LOG_TAG,"----------------Exception occured while starting service----------------");
}
}
}
}
public class MyService extends Service {
private Context context;
private static final String LOG_TAG = "MyService";
private Thread thread = null;
public MyService()
{
super();
Log.d(LOG_TAG, "----------------Inside Email Service constructor----------------");
}
public int onStartCommand(Intent myIntent, int flags, int startId)
{
Log.d(LOG_TAG, "----------------Email Service Command Started----------------");
try
{
context = getApplicationContext();
if(thread == null || !thread.isAlive())
{
thread = new Thread(new MyRunnable("Email Sender", myIntent));
thread.start();
}
}
catch (Exception e)
{
e.printStackTrace();
Log.d(LOG_TAG,
"----------------Exception occured in Email Service onStartCommand----------------");
}
return START_REDELIVER_INTENT;
}
class MyRunnable implements Runnable {
String name;
Intent myIntent;
public MyRunnable(String name, Intent myIntent) {
this.name = name;
this.myIntent = myIntent;
}
#Override
public void run()
{
try
{
doStuff(emailIntent);
}
catch (NumberFormatException e)
{
e.printStackTrace();
Log.d(LOG_TAG, e.getMessage());
}
catch (InterruptedException e)
{
e.printStackTrace();
Log.d(LOG_TAG, e.getMessage());
}
catch (Exception e)
{
e.printStackTrace();
Log.d(LOG_TAG, e.getMessage());
}
finally
{
stopSelf();
}
}
}
private void doStuff(Intent emailIntent) throws InterruptedException, Exception
{
if (context != null)
{
boolean isWifiConnection = false;
try
{
// Check if WiFi connection is available ,if yes try opening it;
// Attempt to open WiFi connection
isWifiConnection = Utility.isEnableWifiSuccessful(getApplicationContext());
Log.d(LOG_TAG, "----------------Wifi conn enabled = " + isWifiConnection
+ "----------------");
if (isWifiConnection)
{
// Do more stuff
}
}
catch (Exception e)
{
e.printStackTrace();
throw e;
}
finally
{
// Code never reaches here !! Somehow, the service stops and by
// the time the service stops,
// WiFi has been enabled
try
{
if (isWifiConnection)
{
Utility.isDisableWifiSuccessful(getApplicationContext());
}
}
catch (Exception e)
{
e.printStackTrace();
Log.d(LOG_TAG,
"----------------Error occured while closing network connections----------------");
}
}
}
else
{
Log.d(LOG_TAG, "----------------Context is null----------------");
}
}
#Override
public IBinder onBind(Intent intent)
{
// TODO Auto-generated method stub
return null;
}
}
Now, if i have another receiver as NetworkReceiver
public class NetworkReceiver extends BroadcastReceiver {
private static final String ACTION = "android.net.wifi.WIFI_STATE_CHANGED";
private static final String LOG_TAG = "NetworkReceiver";
#Override
public void onReceive(Context context, Intent networkIntent)
{
if(networkIntent.getAction().equals(ACTION))
{
Log.d(LOG_TAG, "----------------Inside Network Receiver----------------");
//Do something which will keep track who has opened the WiFi connection
}
}
}
then can myIntent and networkIntent share information and can MySerivce read that information.
Any help would be really grateful.
Service exits when the memory is too low, since you are already using START_STICKY, the service will be restarted once the memory resources are available. I beleive you might need to check if the connection is opened and you are done with the task, then you have stop the service by using stopSelf().
Hope this helps.
Thanks,
Ramesh