I have a android application with lots of buttons. If a button is pressed it sends a short cmd to a server via a socket.
Currently, when a button is pressed this adds a cmd to a list.
I have a worker thread that constantly checks the list for cmds and if it finds one opens a socket and sends the cmd.
This is not very efficient as the worker thread is constantly running. What would be the best way to improve this?
public class Arduino implements Runnable{
private static PrintWriter arduinoOutput;
private static Socket ss;
private static Queue<String> cmdsToSend=new LinkedList<String>();
private static String cmd;
public void run(){
while(true){
if(!cmdsToSend.isEmpty()){
cmd = cmdsToSend.poll();
System.out.println("send:"+cmd);
if(connect()){
arduinoOutput.println(cmd);
disconnect();
}
}
}
}
public static void sendCmd(String newcmd){
cmdsToSend.add(newcmd);
}
private static boolean connect(){
try {
ss = new Socket();
InetAddress addr = InetAddress.getByName("192.168.1.8");
int port = 23;
SocketAddress sockaddr = new InetSocketAddress(addr, port);
ss.connect(sockaddr, 2000);
arduinoOutput = new PrintWriter(ss.getOutputStream(),true); //Autoflush
return true;
} catch (UnknownHostException e) {
return false;
} catch (IOException e) {
return false;
}
}
private static void disconnect(){
arduinoOutput.close();
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
The UI activity adds a cmd by calling Arduino.sendCmd("cmdName"); The cmds need to be sent as quickly as possible so a sleep in the loop is no good.
Any ideas or examples would be appreciated.
Use a wait/notify pattern. Put the sender on a thread with the list. Whenever there is something to write to the worker thread, have the writer add the command, and then notify the thread. If the thread is already awake, the notify will do nothing.
Here is a quick example, clearly the mechanism you will use to start the writing thread will be different.
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.ThreadFactory;
public class Notifier
{
public static void main( String args[] )
{
Writer writingThread = new Writer();
writingThread.addToQueue( "Command 0" );
ThreadFactory.submitInSingleThread( writingThread );
for (int i = 1; i < 1000; i++)
{
writingThread.addToQueue( "Command " + i );
writingThread.notify();
}
}
static class Writer implements Runnable
{
private static Queue<String> cmdsToSend = new LinkedList<String>();
public void addToQueue( String cmd )
{
cmdsToSend.add( cmd );
}
#Override
public void run()
{
while( true )
{
if( !cmdsToSend.isEmpty() )
{
String cmd = cmdsToSend.poll();
System.out.println( "send:" + cmd );
if( connect() )
{
arduinoOutput.println( cmd );
disconnect();
}
}
synchronized( this )
{
wait(); //Can add a timer (100ms, for example)
}
}
}
}
}
Related
I built a server using node.js and socket.io for a chat application and I want to connect to the server from my android client application that uses native java.net.Socket. Can I do it?
Here I found a solution that works fine. This code section is for server side socket.
var net = require('net');
var sockets = [];
var svr = net.createServer(function(sock) {
console.log('Connected: ' + sock.remoteAddress + ':' + sock.remotePort);
sockets.push(sock);
sock.write('Welcome to the server!\n');
sock.on('data', function(data) {
for (var i=0; i<sockets.length ; i++) {
if (sockets[i] != sock) {
if (sockets[i]) {
sockets[i].write(data);
}
}
}
});
sock.on('end', function() {
console.log('Disconnected: ' + sock.remoteAddress + ':' + sock.remotePort);
var idx = sockets.indexOf(sock);
if (idx != -1) {
delete sockets[idx];
}
});
});
var svraddr = '192.168.0.8';
var svrport = 1234;
svr.listen(svrport, svraddr);
console.log('Server Created at ' + svraddr + ':' + svrport + '\n');
Android client side code is given below: connect to the given ip and port for server through android client side.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
public class Client {
private Socket socket;
private OutputStream socketOutput;
private BufferedReader socketInput;
private String ip;
private int port;
private ClientCallback listener=null;
public Client(String ip, int port){
this.ip=ip;
this.port=port;
}
public void connect(){
new Thread(new Runnable() {
#Override
public void run() {
socket = new Socket();
InetSocketAddress socketAddress = new InetSocketAddress(ip, port);
try {
socket.connect(socketAddress);
socketOutput = socket.getOutputStream();
socketInput = new BufferedReader(new InputStreamReader(socket.getInputStream()));
new ReceiveThread().start();
if(listener!=null)
listener.onConnect(socket);
} catch (IOException e) {
if(listener!=null)
listener.onConnectError(socket, e.getMessage());
}
}
}).start();
}
public void disconnect(){
try {
socket.close();
} catch (IOException e) {
if(listener!=null)
listener.onDisconnect(socket, e.getMessage());
}
}
public void send(String message){
try {
socketOutput.write(message.getBytes());
} catch (IOException e) {
if(listener!=null)
listener.onDisconnect(socket, e.getMessage());
}
}
private class ReceiveThread extends Thread implements Runnable{
public void run(){
String message;
try {
while((message = socketInput.readLine()) != null) { // each line must end with a \n to be received
if(listener!=null)
listener.onMessage(message);
}
} catch (IOException e) {
if(listener!=null)
listener.onDisconnect(socket, e.getMessage());
}
}
}
public void setClientCallback(ClientCallback listener){
this.listener=listener;
}
public void removeClientCallback(){
this.listener=null;
}
public interface ClientCallback {
void onMessage(String message);
void onConnect(Socket socket);
void onDisconnect(Socket socket, String message);
void onConnectError(Socket socket, String message);
}
}
MainActivity is:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Client socket = new Client("192.168.0.8", 1234);
socket.setClientCallback(new Client.ClientCallback () {
#Override
public void onMessage(String message) {
}
#Override
public void onConnect(Socket socket) {
socket.send("Hello World!\n");
socket.disconnect();
}
#Override
public void onDisconnect(Socket socket, String message) {
}
#Override
public void onConnectError(Socket socket, String message) {
}
});
socket.connect();
}
}
The answer to your question is No. A java.net.socket cannot be connected with a nodejs socket.io because the protocol specifications are different for both.
Note: Socket.IO is not a WebSocket implementation. Although Socket.IO indeed uses WebSocket as a transport when possible, it adds some metadata to each packet: the packet type, the namespace and the ack id when a message acknowledgement is needed. That is why a WebSocket client will not be able to successfully connect to a Socket.IO server, and a Socket.IO client will not be able to connect to a WebSocket server (like ws://echo.websocket.org) either. Please see the protocol specification here.
Quoted From nodejs socket.io github page.So when web socket cannot be connected to socket.io so the java.net.socket can also be not connected.
If you want to have communication with the java client you can use the Socket.io library designed for java.
In Nodejs, You can use from this example
And in Sockect.io blog
In Java, as a server, you can use PrintWriter to write your data on Socket in a very simple situation. like below open socket on port 9090 and send current date to the client:
/**
* Runs the server.
*/
public static void main(String[] args) throws IOException {
ServerSocket listener = new ServerSocket(9090);
try {
while (true) {
Socket socket = listener.accept();
try {
PrintWriter out =
new PrintWriter(socket.getOutputStream(), true);
out.println(new Date().toString());
} finally {
socket.close();
}
}
}
finally {
listener.close();
}
}
Code from here
I'm developing an Android application, I have to implement a function that discover all the host of the network where I'm connected (for example WiFi).
I implemented a function that work, this is my code:
public class ScanNetwork {
private static final int NB_THREADS = 10;
private ArrayList < String > hosts;
public ArrayList < String > ScanNetwork(String ipAddress) {
hosts = new ArrayList <> ();
String subnet = ipAddress.substring(0, ipAddress.lastIndexOf("."));
ExecutorService executor = Executors.newFixedThreadPool(NB_THREADS);
for (int dest = 0; dest < 255; dest++) {
String host = subnet + "." + dest;
executor.execute(pingRunnable(host));
}
executor.shutdown();
try {
executor.awaitTermination(60 * 1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException ignored) {}
return hosts;
}
private Runnable pingRunnable(final String host) {
return new Runnable() {
public void run() {
try {
InetAddress inet = InetAddress.getByName(host);
boolean reachable = inet.isReachable(1000);
if (reachable) {
hosts.add(host);
}
} catch (UnknownHostException e) {
System.out.println("Log: " + e);
} catch (IOException e) {
System.out.println("Log: " + e);
}
}
};
}
}
This code work on a certain category of IP such as 192.168.1.10, but not for each other like 10.1.25.1.
The question in simple, how I can implement a function that discover all host in a certain network considering all kinds of IP?
I want to write and read from file in the same time without errors.
For example, I will starting new Thread for writing to file from my running service.
In my activity i will starting new Thread for reading from the same file.
I wan't to do this synchronously. Some thing like this :
To wait execution of next thread until previous finished.
Next thread must not start until previous thread stops, irrespective of time consumption.
My code for read and write:
public static final String ROUTE_FILE_NAME = "route.txt";
public static void savePointToFile(Context context, String point) throws IOException {
FileOutputStream fOut = context.openFileOutput(ROUTE_FILE_NAME, Context.MODE_APPEND);
OutputStreamWriter osw = new OutputStreamWriter(fOut);
osw.write(point);
osw.flush();
osw.close();
}
public static String readRouteFromFile(Context context) {
StringBuffer fileContent = new StringBuffer(UIUtils.emptyString());
byte[] buffer = new byte[1024];
try {
FileInputStream fis = context.openFileInput(ROUTE_FILE_NAME);
int length;
while ((length = fis.read(buffer)) != -1) {
fileContent.append(new String(buffer));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return fileContent.toString();
}
Thanks in advance.
If you just want the read method called from a thread to wait for the write method called from another thread to be finished, and vice versa, just synchronize both methods on a common object:
private static final Object fileLock = new Object();
public static String readFile() {
synchronize(fileLock) {
[your current read code here]
}
}
public static void write(String data) {
synchronize(fileLock) {
[your current write code here]
}
}
You can look at a special thread pool executor service.
final ExecutorService threadpool = Executors.newSingleThreadExecutor();
Its fairly easy, just create runnables and put it in the threadpool. It contains a single thread so all your runnables are queued sequentially. Otherwise you could create a normal executorservice and set the threadpool to 1. Effectively its the same. Hope this helps
http://www.concretepage.com/java/newsinglethreadexecutor_java
So its like
WorkerThread.get(context).read()
WorkerThread.get(context).write()
You can even implement future calls instead of defining an explicit callback.
Just a general idea of how it can work. You need to save filepointers so you know where to pause and continue read/write. Other you will always start from the first data position in the file.
class WorkerThread {
interface Callback {
void onCompleteRead(String buffer, int pauseReadPointer);
void onCompleteWrite(int pauseWritePointer);
}
enum Action {
READ,
WRITE
}
private static WorkerThread singleton;
public static synchronized WorkerThread get(final Context context) {
if (instance == null) {
instance = new WorkerThread(context);
}
return instance;
}
private final Context context;
private final ExecutorService threadPool;
private WorkerThread(context) {
threadPool = Executors.newSingleThreadExecutor()
}
// PUBLIC READ CALL
public void read(int resumeReadPointer, Callback callback, "other params") {
queueJob(READ, null, resumeReadPointer, callback);
}
// PUBLIC WRITE CALL
public void write(String in, int resumeWritePointer, Callback callback, "other params") {
queueJob(WRITE, in, resumeWritePointer, callback);
}
private void queueJob(final Action action, String buffer, final int pointer, final Callback callback) {
/* Create handler in UI thread. */
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
ResultPack pack = (ResultPack) msg.obj;
if (Action.READ == action) {
callback.onCompleteRead(pack.result, pack.pointer);
} else {
callback.onCompleteWrite(pack.pointer);
}
}
};
// single threadpool. everything is FIFO
threadPool.submit(new FileRunnable(action, buffer, handler, pointer));
}
private class ResultPack {
private final String result;
private final int pointer;
private ResultPack(String s, int p) {
this.result = s;
this.pointer = p;
}
}
private class FileRunnable implements Runnable {
private int pointer = 0;
private final Handler handler;
private final buffer = buffer;
FileRunnable(final Action action, String buffer, final Handler handler, final int pointer) {
this.pointer = pointer;
this.handler = handler;
this.buffer = buffer;
}
#Override
public void run() {
if (Action.READ == action) {
ResultPack pack = readRouteFromFile(..., pointer);
} else { // write
ResultPack pack = savePointToFile(..., buffer, pointer);
}
Message message = Message.obtain();
message.obj = pack;
handler.sendMessage(message);
}
}
}
i am making an android socket app to communicate with the server for creating accounts, and i noticed i have to do this in AsyncTask sub class, even when i seperate it to another class without UI,but i am terribly confused how can i use AsyncTask on this, is there any one expert here who can help me please?
this is the code:
public class AccountCreator extends Activity {
public AccountCreator(){
super();
}
// for I/O
ObjectInputStream sInput; // to read from the socket
ObjectOutputStream sOutput; // to write on the socket
Socket socket;
public static String LOGTAG="Lifemate";
public String server = "localhost";
public String username = "user";
public String password = "rezapassword" ;
public int port = 1400;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(LOGTAG,"oncreate called");
this.start();
}
AccountCreator(String server, int port, String username,String password) {
this.server = "localhost";
this.port = 1400;
this.username = username;
Log.i(LOGTAG,"first accountcreator called");
}
public boolean start() {
// try to connect to the server
//this method returns a value of true or false when called
try {
socket = new Socket(server, port);
}
// if it failed not much I can so
catch(Exception ec) {
// display("Error connectiong to server:" + ec);
Log.i(LOGTAG,"Error connectiong to server:" + ec);
return false;
}
String msg = "Connection accepted " + socket.getInetAddress() + ":" +
socket.getPort();
// display(msg);
Log.i(LOGTAG, msg);
/* Creating both Data Stream */
try
{
sInput = new ObjectInputStream(socket.getInputStream());
sOutput = new ObjectOutputStream(socket.getOutputStream());
}
catch (IOException eIO) {
// display("Exception creating new Input/output Streams: " + eIO);
Log.i(LOGTAG,"Exception creating new Input/output Streams: " +
eIO);
return false;
}
// creates the Thread to listen from the server
// Send our username to the server this is the only message that we
// will send as a String. All other messages will be ChatMessage objects
try
{
sOutput.writeObject(username);
sOutput.writeObject(password);
}
catch (IOException eIO) {
// display("Exception doing login : " + eIO);
Log.i(LOGTAG,"Exception doing login : " + eIO);
disconnect();
return false;
}
// success we inform the caller that it worked
return true;
}
// private void display(String msg) {
// TextView screenprint = (TextView)findViewById(R.id.systemmessages);
// screenprint.setText(msg);
// }
private void disconnect() {
Log.i(LOGTAG,"reached disconnect");
try {
if(sInput != null) sInput.close();
}
catch(Exception e) {} // not much else I can do
try {
if(sOutput != null) sOutput.close();
}
catch(Exception e) {} // not much else I can do
try{
if(socket != null) socket.close();
}
catch(Exception e) {} // not much else I can do
}
public void Begin() {
Log.i(LOGTAG,"it begun");
int portNumber = 1400;
String serverAddress = server;
String userName = username;
String newpassword = password;
AccountCreator accountcreator = new AccountCreator(serverAddress, portNumber,
userName,password);
if(!accountcreator.start())
return;
}
}
i was trying to put whole code in Async, i dont know if was i right, do i need to do that also or just some parts of it?
In brief, AsyncTask contains a few methods which may be helpful:
onPreExecute:
This method is the first block of code executed when calling asyncTask.execute(); (runs on mainUIThread).
doInBackground:
Here you put all the code which may suspend you main UI (causes hang for your application) like internet requests, or any processing which may take a lot of memory and processing. (runs on background thread), contains one parameter taken from the asyncTask.execute(ParameterType parameter);
onPostExecute
Runs after doInBackground(). Its parameter is the return value of the doInBackground function, and mainly you put the changes in UI need to be done after the connection is finished (runs on mainUIThread)
You have to declare another class within the class you have already created.
class SomeName extends Async<Void, String, Void>{
protected void OnPreExecute(){
// starts the task runs on main UI thread
// Can be used to start a progress dialog to show the user progress
}
#Override
protected Void doInBackground(Void... params){
// does what you want it to do in the background
// Connected to the server to check a log-in
return result;
}
protected void OnPostExecute(Void result){
// finishes the task and can provide information back on the main UI thread
// this would be were you would dismiss the progress dialog
}
}
My Android app should do the following:
The MainActivity launches another thread at the beginning called UdpListener which can receive UDP calls from a remote server. If it receives a packet with a content "UPDATE", the UdpListener should notify the MainActivity to do something.
(In the real app, the use case looks like this that my app listens on the remote server. If there is any new data available on the remote server, it notifies every client (app) by UDP, so the client knows that it can download the new data by using HTTP).
I tried to simulate this in an JUnit test. The test contains an inner class which mocks the MainActivity as well as it sends the UDP call to the UdpListener:
public class UdpListener extends Thread implements Subject {
private DatagramSocket serverSocket;
private DatagramPacket receivedPacket;
private boolean running = false;
private String sentence = "";
private Observer observer;
private static final String TAG = "UdpListener";
public UdpListener(Observer o) throws SocketException {
serverSocket = new DatagramSocket(9800);
setRunning(true);
observer = o;
}
#Override
public void run() {
setName(TAG);
while (isRunning()) {
byte[] receivedData = new byte[1024];
receivedPacket = new DatagramPacket(receivedData, receivedData.length);
try {
serverSocket.receive(receivedPacket);
}
catch (IOException e) {
Log.w(TAG, e.getMessage());
}
try {
sentence = new String(receivedPacket.getData(), 0, receivedPacket.getLength(), "UTF-8");
if ("UPDATE".equals(sentence)) {
notifyObserver();
}
}
catch (UnsupportedEncodingException e) {
Log.w(TAG, e.getMessage());
}
}
}
private boolean isRunning() {
return running;
}
public void setRunning(boolean running) {
this.running = running;
}
#Override
public void notifyObserver() {
observer.update();
}
}
This is the corresponding test:
#RunWith(RobolectricTestRunner.class)
public class UdpListenerTest {
private MainActivityMock mainActivityMock = new MainActivityMock();
#Before
public void setUp() throws Exception {
mainActivityMock.setUpdate(false);
}
#After
public void tearDown() throws Exception {
mainActivityMock.setUpdate(false);
}
#Test
public void canNotifyObserver() throws IOException, InterruptedException {
UdpListener udpListener = new UdpListener(mainActivityMock);
udpListener.setRunning(true);
udpListener.start();
InetAddress ipAddress = InetAddress.getByName("localhost");
DatagramSocket datagramSocket = new DatagramSocket();
DatagramPacket sendPacket = new DatagramPacket("UPDATE".getBytes(), "UPDATE".length(), ipAddress, 9800);
datagramSocket.send(sendPacket);
datagramSocket.close();
assertTrue(mainActivityMock.isUpdate());
udpListener.setRunning(false);
}
private class MainActivityMock implements Observer {
private boolean update = false;
#Override
public void update() {
update = true;
}
public boolean isUpdate() {
return update;
}
public void setUpdate(boolean update) {
this.update = update;
}
}
}
The good thing is that my concept works. But, this test doesn't. That means it only does when I stop with a breakpoint at this line datagramSocket.close(); and wait for about a second. Why this happens is clear. But how can I do that automatically? I thought about using wait() but I have to invoke notify() from the other thread for that. The same problem with CountDownLatch. I'm not sure how to solve that without changing UdpListener.
You could write a simple loop with a specified timeout.
try {
long timeout = 500; // ms
long lastTime = System.currentTimeMillis();
while(timeout > 0 && !mainActivityMock.isUpdate()) {
Thread.sleep(timeout);
timeout -= System.currentTimeMillis() - lastTime;
lastTime = System.currentTimeMillis();
}
} catch(InterruptedException e) {
} finally {
assertTrue(mainActivityMock.isUpdate());
}
By the way - you should declare your running attribute to volatile.
one solution would be to use a blocking queue with size 1 for storing your received results.
The request for isUpdate (which would take an element from the blocking queue) would block until the update package(or any other package) is put into the queue.
is case you want all your calls to be non-blocking you could use a Future for receiving your result. Future.get() would block ontil your result is received.