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.
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 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.
I have run into an interesting issue trying to upgrade one of my applications from the Java 6 to Java 7. It is a simple Java socket program. It sends a command to a COM socket and receives a response. It works perfectly in a Java 6 environment, but when I try to run the same code in a Java 7 environment, the socket appears to receive nothing in the InputStream.
I can confirm that the COM socket it's connecting to does receive the command and sends the response. This is run on the exact same machine in both cases with the firewall disabled, and it's the exact same code ran both times.
Has something changed in Java 7, do I have some deeper flaw, or is this simply a Java bug?
Here is a slightly stripped version of the code.
public static void main(String[] arguments) throws Exception {
InetAddress server = InetAddress.getByName(serverAddress);
Socket sock = SSLSocketFactory.getDefault().createSocket(server.getHostAddress(), port);
InputStream in = sock.getInputStream();
OutputStream out = sock.getOutputStream();
out.write(command.getBytes()); //Is valid command
String token = "";
responseReader: while (true) {
try {
Thread.sleep(1);
}
catch (InterruptedException exception) {}
byte[] d = new byte[in.available()];
int avail = in.read(d);
for (int i = 0; i < avail; i++) {
if (d[i] == fieldSeperator) {
token = "";
}
else if (d[i] == commandSeperator) {
break responseReader;
}
else {
token += (char) d[i];
}
}
}
}
I've tried as much as I can think of, most of the time knowing it shouldn't matter. Using different methods of reading the stream, casting to SSLSocket and making different calls, adding some sleeps.
The code is wrong. You shouldn't use available() like that. If there is no data available you will allocate a zero length buffer and execute a zero length read, which will retun zero without blocking. Use a constant like 8192 for the buffer size, and allocate the buffer outside the loop. And get rid of the sleep() too.
There are few if any correct uses of available(), and this isn't one of them.
And note that available() always returns zero for an SSLSocket, and has always done so right back to Java 1.3 and the separate JSSE download. So I am unable to accept that the same code worked in Java 6.
I want to write a simple web proxy, for exercise. Here's the code I have so far:
def g = new Proxy()
g.serverPort = 9000
println "starting"
g.eachClient { Socket client ->
println "got a client"
try {
client.withStreams { input,output ->
String text = input.text
println "received $text from client"
client.close()
}
} catch(IOException io) {
println "IO error. Probably client disconnected"
//io.printStackTrace()
}
}
the thing is, the line :
String text = input.text
consumes all the available data in the Socket's InputStream. If the client isn't closing the connection, that method will just wait until it can read a end of file character ( if I remember correctly ). What do I have to prevent this from happening, and have the client's string available ASAP?
I think you'll want to check the documentation on ObjectInputStream. Do length = input.available to get the number of available bytes at the present time, then use input.read(buffer, offset, length) to read in exactly as many bytes are available. You'll probably want to launch a new thread for every new connection which transparently manages this buffer in the background, unless you're making a single-threaded proxy to begin with.