I'm using a Bluetooth socket to send information from my phone to an Arduino. The problem is that btSocket.getOutputStream().write(bytes); is sending information too fast and the Arduino can't catch up with the emptying up and overflows. The code running on my Arduino slows down the Arduino's ability to receive the info from the phone and the receiving Arduino buffer gets overflowed (the incoming data gets bugged because the buffer is emptied much slower than it is filled). So a solution would be to slow the rate at which the phone sends the info.
This is the function I use to send info from the phone to the Arduino:
public void send_string_to_lim(String s) {
if (btSocket != null) {
try {
byte[] bytes = s.getBytes();
btSocket.getOutputStream().write(bytes);
} catch (IOException e) {
quick_toast("Error: " + e.toString());
}
}
}
And this is how the btSocket is created: (not sure if it's needed for the question)
if (btSocket == null || !isBtConnected) {
myBluetooth = BluetoothAdapter.getDefaultAdapter(); //get the mobile bluetooth device
BluetoothDevice dispositivo = myBluetooth.getRemoteDevice(address); //connects to the device's address and checks if it's available
btSocket = dispositivo.createInsecureRfcommSocketToServiceRecord(myUUID); //create a RFCOMM (SPP) connection
BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
btSocket.connect(); //start connection
}
How can I slow the btSocket.getOutputStream().write(bytes); so it sends information slower? Add some type of delay so the Arduino doesn't overflow.
You send a byte array to OutputStream but you can also send bytes one at a time - simply loop through your byte array, and after sending each byte, delay for a bit.
I've used an AsyncTask for this but since its deprecated you might want to use Threads or something similar to not lock your UI thread.
Once you have an AsyncTask framework or Thread in place, your working code (which is in doInBackground or your worker function) should be something like:
for (int i=0; i<bytes.length();i++)
{
btSocket.getOutputStream().write(bytes[i]);
Thread.sleep(2); //2 ms delay
}
There's a few exceptions that I haven't handled but you can put it in a try-catch block for that if you want.
An example template for AsyncTask (which, again, is your choice) is here: https://stackoverflow.com/a/9671602/3550337. I only bring it up because that's what I've used and it worked for me.
Related
I am building this program where a server sends different order to different clients. One part of the program sends the order to the server, the server processes to which client the message goes to and then it sends it to the particular client it should go.
Here is the code where the message is send:
#Override
public void run() {
boolean active = true;
String oldMsgToDron = "";
String to_print = "";
BufferedWriter bw = new BufferedWriter(osw);
while(active) {
try {
//msgToDron is declared in DronController as: public static volatile String msgToDron;
to_print = DronController.msgToDron;
if(to_print.equals(oldMsgToDron) == false) {
System.out.println("Message we are sending to the dron: " + to_print);
if(to_print.length()>45 && to_print.startsWith("!whisper") && dronId.equals(to_print.substring(9, 45))) {
bw.write("Server whispers:" + to_print.replace("!whisper " + dronId, ""));
bw.newLine();
bw.flush();
System.out.println("Message we sent to the dron: " + to_print);
}
else if (to_print.startsWith("!whisper") == false){
bw.write(to_print);
bw.newLine();
bw.flush();
System.out.println("A message for all drones has been sent.");
}
try{Thread.sleep(5);}catch(InterruptedException ex){ex.printStackTrace();}
oldMsgToDron = "";
to_print = "";
DronController.msgToDronEsclavo = "";
}
}catch(IOException e) {
try {
active = false;
if(bw != null)
bw.close();
}catch(IOException f) {e.printStackTrace();f.printStackTrace();break;}
}
}
}
My problem is that the message is processed inside the thread that controls the connection to the client and at the end of the loop the message is changed to an empty string. This is so I can send the same order twice in a row and the server isn't constantly sending the same messages to the client.
The thing is that by doing it this way if I have 3 or more connections it starts to give me problems because whenever one of the threads reaches the end they turn the variables DronController.msgToDronEsclavo, to_print and oldMsgToDron to empty strings before the other threads had time to check if the message was for the client they have assigned.
How can I avoid that the different threads change the variable before the others have finished? Are there any kind of design pattern for this kind of structures? What are some good practices with this type of programs?
Also, I've thought about making the client check if the message sent is for them or not but I find this solution unsecure.
Usually it is the client who connects to the server via network - to request data or to send data. The server has no reliable way to know when the client would connect the next time, or trigger a connection itself.
If you want to send data from the server to the client there used to be patterns that the client would poll for data, or have always one request waiting for the next packet from the server. You may want to read about AJAX and Websocket
Another pattern would be to install a webhook, which essentially gives the server a URL at which the client can be reached. This in essence swaps the server to acting as client and the client to acting as server for this data transfer.
Well, the above was written related to your question title. Now looking at the content, you are asking how to prevent that threads impact each other.
Learn Java's concepts on thread synchronization. Here is a nice tutorial.
Following scenario that explains my problem.
I've a PLC that acts as a server socket program. I've written a Client Java program to communicate through socket communication with the PLC.
Steps that take place in this process are:
1) For each second my Client program happen to communicate with the PLC, read the data in stream, store the data temporarily in a ByteArrayOutputStream and closing both input stream and socket. Following snippet gives the idea
try {
socket = new Socket(host, port);
is = socket.getInputStream();
outputBuffer = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int read;
if((read = is.read(buffer)) != -1) {
outputBuffer.write(buffer, 0, read);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
System.out.println("Before closing the socket");
try {
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("After closing the socket");
} catch (Exception e) {
e.printStackTrace();
}
}
2) Processing stored data according to my requirement is what I'm trying to do. So for every 1 second, client program connects to Server, read the data(if data is present), store the data, close socket and process it. And it has to happen for a very long run, probably till the Server program is on. And that may happen till for every few weeks.
3) Problem what I'm facing is, I'm able to run the above show for 1-2 hours, but from then, Client Program unable to fetch the data from the Server Program(PLC in this case), though both are connected through socket. I.e 128 bytes of data present, but Client program isn't able to read that data. And this started happening after program run successfully for almost 2hours
4) Please find the brief code which may help for you to look into.
public class LoggingApplication {
public static void main(String[] args) throws NumberFormatException {
if (args.length > 0 && args.length == 2) {
String ipAddress = mappingService.getIpAddress();
int portNo = (int) mappingService.getPortNo();
ScheduledExecutorService execService = Executors.newScheduledThreadPool(1);
execService.schedule(new MyTask(execService, ipAddress, portNo, mappingService), 1000, TimeUnit.MILLISECONDS);
} else {
throw new IllegalArgumentException("Please pass IPAddress and port no as arguments");
}
}
}
Runnable Code:
public class MyTask implements Runnable {
public ScheduledExecutorService execService;
private String ipAddress;
private int portNo;
private ConfigurationMappingService mappingService;
private MySocketSocketUtil mySocketSocketUtil;
public MyTask(ScheduledExecutorService execService, String ipAddress, int portNo, ConfigurationMappingService mappingService) {
this.execService = execService;
this.ipAddress = ipAddress;
this.portNo = portNo;
this.mappingService = mappingService;
}
public void run() {
MySocketSocketUtil mySocketSocketUtil = new MySocketSocketUtil(ipAddress, portNo);
execService.schedule(new MyTask(execService, ipAddress, portNo, mappingService), 1000, TimeUnit.MILLISECONDS);
mySocketSocketUtil.getData(); //It's able to fetch the data for almost 2 hours but from then, it's just getting empty data and it's keep on giving empty data from then. and so on.
/*
*
*Some code
*/
}
}
Here's where, I'm having the problem
mySocketSocketUtil.getData(); is able to fetch the data for almost 2 hours but from then, it's just getting empty data and it's keep on giving empty data from then. and so on. It's a big question I know, And I want to understand what might have gone wrong.
Edit: I'm ignoring the condition to check end of the stream and closing a socket based on it is because, I knew I'm going to read first 1024 bytes of data only always. And So, I'm closing the socket in finally block
socket = new Socket(host, port);
if(socket != null && socket.isConnected())
It is impossible for socket to be null or socket.isConnected() to be false at this point. Don't write pointless code.
if((read = is.read(buffer)) != -1) {
outputBuffer.write(buffer, 0, read);
};
Here you are ignoring a possible end of stream. If read() returns -1 you must close the socket. It will never not return -1 again. This completely explains your 'empty data':
from then, it's just getting empty data and it's keep on giving empty data from then, and so on
And you should not create a new Socket unless you have received -1 or an exception on the previous socket.
} else {
System.err.println("Socket couldn't be connected");
}
Unreachable: see above. Don't write pointless code.
You should never disconnect from the established connection. Connect once in the LoggingApplication. Once the socket is connected keep it open. Reuse the socket on the next read.
I think there are couple of points you need to fix before getting to the solution to your problem. Please try to follow the following suggestions first:
As #EJP said this code block is not needed.
if(socket != null && socket.isConnected()) {
also you are using a byte array of length 1024 and not using while or for loop to read the data stream. Are you expecting only a block of data which will never exceed 1024 bytes?
byte[] buffer = new byte[1024];
int read;
if((read = is.read(buffer)) != -1) {
This is also not needed as it is unreachable.
} else {
System.err.println("Socket couldn't be connected");
}
Can you explain the data stream behavior you are expecting?
Last but not the least is.read(buffer) is a blocking call so if there is no data to read yet, it will hold the thread execution at that point.
Please try to answer the questions I have asked.
#KishoreKumarKorada from your description in the comment section, it seems like you are monitoring the data change on server side. Socket stream works in a read-once fashion. So,
First thing is, you need to request from server every time and the server needs to RESEND the data on every request.
Second, the way you presented is more like you are operating on byte level, which is not very good way to do that unless you have any legitimate reason to do so. The good way is to wrap the data in JSON or XML format and send it over the stream. But to reduce bandwidth consumption, you may need to operate on byte stream sometimes. You need to decide on that.
Third, for monitoring the data change, the better way is to use some timestamp to compare when the data has changed on the server side and what is the timestamp stored on the client side, if they match, data has not changed. Otherwise fetch the data from the server side and update the client side.
Fourth, when there is data available that you are not able to read, can you debug the ins.read(...) statement to see if its getting executed and the execution goes inside the if block or if statement is evaluated to false? if true then examine the read value and let me know what you have found?
Thanks.
I have managed to set up the connection between my arduino and the App with the help of Instructables blog.
The connection is set but i need the sensor output value of the ardunio to be displayed on a TextView. This is the Arduino code.
How do i program my Android studio program to read the output value of the serial monitor in the Arduino?
Okay, in the tutorial shows how send data from the app to arduino, but not how receive data from the arduino to your app for do this, you will need:
Send data from arduino by HC-06.
Receive and decode your data in the app.
show decoded data in the TextView.
a litle example for do this.
In Arduino:
can be the example of the arduino page you must only make sure that HC-06 is properly connected in Serial port.
In the app code you can use this code to receive data, only change the name of SocketBT instance, for the instance that you need.
private class TareaLeer extends Thread
{
#Override
public void run()
{
while(SocketBT.isConnected())
{
InputStream inputStream;
try {
inputStream = SocketBT.getInputStream();
byte[] buffer = new byte[256];
if (inputStream.available() > 0) {
inputStream.read(buffer);
int i = 0;
for (i = 0; i < buffer.length && buffer[i] != 0; i++) {
}
String strInput = new String(buffer, 0, i);
String Recepcion = strInput;
Log.d("Recibi",Recepcion);
//Here you can pass the value of recepcion to any globlal variable and show in TextView
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Parar();
}
}
for show it on TextView you can do this.
MyTextView.setText(Recepcion);
this is a very general explanation, for do it , you need know how android code works basically, but is a good example for start Android and Arduino Programming.
I have a library which I need to improve since it is dropping to many packets. I want to receive a RTP-Stream, but the streamer is sending bursts of 30-40 packets within a millisecond (MJPEG-Stream). I can see the packets being complete when monitoring traffic in Wireshark. But when trying to receive them in Java, I lose a lot of those packets.
I have already been able to improve the libraries behavior by implementing a ring buffer that would constantly get filled whenever a packet is available and a separate reader thread that reads from this buffer. But I'm still not able to get all the packets from my socket that I can see in wireshark. Through RTP sequence numbers I can monitor in the reader thread if the packet processed is the one expected.
The following code is handling packet receiving:
private volatile byte[][] packetBuffer = new byte[1500][BUFFER_SIZE];
private volatile DatagramPacket[] packets = new DatagramPacket[BUFFER_SIZE];
private volatile int writePointer = 0;
public void run() {
Thread reader = new RTPReaderThread();
reader.start();
while (!rtpSession.endSession) {
// Prepare a packet
packetBuffer[writePointer] = new byte[1500];
DatagramPacket packet = new DatagramPacket(packetBuffer[writePointer], packetBuffer[writePointer].length);
// Wait for it to arrive
if (!rtpSession.mcSession) {
// Unicast
try {
rtpSession.rtpSock.receive(packet);
} catch (IOException e) {
if (!rtpSession.endSession) {
e.printStackTrace();
} else {
continue;
}
}
} else {
// Multicast
try {
rtpSession.rtpMCSock.receive(packet);
} catch (IOException e) {
if (!rtpSession.endSession) {
e.printStackTrace();
} else {
continue;
}
}
}
packets[writePointer] = packet;
this.incrementWritePointer();
synchronized (reader) {
reader.notify();
}
}
}
What I already know:
I know that UDP is allowed to lose packets, but I still want to
achieve the best possible result. If wireshark can see the packet, I
want to be able to retrieve it as well, if possible.
I know that the ring buffer is never full while losing packets, so
this doesn't make me lose packets either. I tried with BUFFER_SIZES
of 100 and even 1000, but I already lose the first packets before a
total of 1000 packets has been send.
So the question is: what is best practice to receive as many packets as possible from a DatagramSocket? Can I improve handling of packet bursts?
Try setting the SO_RCVBUF size on the datagram socket with rtpSock.setReceiveBufferSize(size). This is only a suggestion to the OS, and the OS may not honor it, especially if it is too large. But I would try setting it to (SIZE_OF_PACKET * 30 * 100), where 30 is for the number of packets in a burst, and 100 is a guess of the number of milliseconds where you will not be able to keep up with the arrival speed.
Note that if your code cannot keep up with processing at the arrival speed in general, the OS has no choice but to drop packets.
My application uses sockets and threads to send real-time data that is receiving to clients that connect to it. To do so, the steps are:
Connects to the data server and then waits for clients
Launch a thread to discuss incoming data, format them and send them out to customers, if any.
When a client connects, it opens a thread for him through which data will be sent.
Finally, use another thread to test you are receiving and sending data, otherwise it is reconnected to the source.
The data received from the source are stored in an array waiting to be processed by the thread.
In each client thread, the received data is also stored in an array to be sent.
The purpose of this is that no jams in receiving or sending data.
the data is delayed 10 seconds or more to reach customers
What I can do to optimize performance?
This is running on a windows server, can you recommend any profiler?
Thank you very much for your help.
EDIT:
The data are strings of variable length.
A part of code is:
// create source socket in class implements Runnable and then waits client
Socket entrada = new Socket(servidor,Integer.parseInt(puerto));
InputStream sIn = entrada.getInputStream();
while (!error) {
try {
s = salida.accept();
clientes.add(new ClientThread(s));
// run
while (((c = sIn.read()) != -1) && ((clientes.size() > 0))) {
if (c != 13 && c != 10) {
cad += (char) c;
}
if (c == 13) received[i] = cad
// In SendThread, run
// format received[i] and send result
for (i=0; i < clientes.size(); i++) {
clientes.get(i).SendData(result);
}
// In ClientThread:
OutputString s1out = socket.getOutputStream();
// SendData
sending[i] = result;
// run
if cad forsending
for (int j = 0;j<res.length();j++){
try {
s1out.write((int)res.charAt(j));
} catch (Exception e) {
}
}
Thanks.
Depending on how much data you are sending, it could be the way you are handling streams.
c = sIn.read() reads a only a few bytes at a time. Try wrapping it with a BufferedReader and using readLine(). BufferedReader will read a few kb at a time, which is much more efficient. readLine() will also break inputs into lines for you, which will simplify the code somewhat.
On the client connection, PrintWriter may help you to output whole lines in one go.