Handling packets through server causes big CPU increase - java

I have an UDP server which receives audio streams from multiple clients and it must be rerouted to the correct client. The problem which I have is that when 2 clients exchange audio stream with each other then it increases my computer CPU usage by a lot. Even 6 clients that exchange audio between each other makes my CPU usage go as high as 50% and can go all the way up to 100% and a server like this should handle over hundred clients easily.
Because we stream audio it will receive probably thousands of udp packets per second and in order for the packets to receive at their correct client destination I loop through an hashmap for each client so it arrives correctly. Now I suspect that this is probably the cause of the huge CPU usage, is there another better way to know the client destination instead of iterating through an hashmap for each client?
Below is my code where I redistribute my packets:
for (Map.Entry<Session, Integer> entry : sessions.entrySet()) {
Session key = entry.getKey();
int value = entry.getValue(); // session ID
// send packets from client1 to client2
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
if (key.player1.getIp() == ip) {
DatagramPacket dp = new DatagramPacket(buffer, buffer.length,
key.player2.getIp(), key.player2.getPort());
try {
socket1.send(dp);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
thread.start();
// send packets from client2 to client1
if (key.player2.getIp() == ip) {
DatagramPacket dp = new DatagramPacket(buffer, buffer.length,
key.player1.getIp(), key.player1.getPort());
try {
socket1.send(dp);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Session:
class Session {
//two initialized player objects per session
Player1 player1 = new Player1();
Player2 player2 = new Player2();
class Player1 {
private InetAddress ip;
private int port;
public InetAddress getIp() {
return ip;
}
public void setIp(InetAddress ip) {
this.ip = ip;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
class Player2 {
private InetAddress ip;
private int port;
public InetAddress getIp() {
return ip;
}
public void setIp(InetAddress ip) {
this.ip = ip;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
}

Problem 1
You "loop through a hashmap". The sole point of using a hashmap is to be able to look things up by hashing.
Arrange your data structures to fit the requirements of your algorithm. It seems you're looking up by IP. OK, so you need a hash map from IP to something.
Your current hashmap looks on the surface to be designed backwards. The key is a 'session', which I suppose to be a moderately complex structure. The value for that key is a simple integer session id. You don't need a map at all for that: store the id in the session object.
A map from id to session would make some sort of sense, although doesn't seem to quite meet your current needs. But there's no rule that you must have only one map. It's legitimate, and possibly useful, to keep id-to-session and IP-to-session maps. Perhaps even an IP-to-session-partner map.
Data structure design is often more important than code.
Problem 2
You create a thread for every entry in the hashmap. Most of those threads will be 'not the intended IP' and do nothing. The check should be before creating the thread.
Thread creation is expensive and you don't want to be running hundreds of threads to service hundreds of clients. You need a better model, for example with some reasonable number of threads servicing queued requests.
If I were designing this, I think the core of the solution would look like this, in pseudocode:
/**
* Process datagram from 'addr' by sending to partner
*/
void forward(datagram dg, ipaddr from) {
session sess = addr_to_session_map.get(from);
session other = sess.other;
send_datagram(dg, from, other.ipaddr);
}
That is to say, when I receive a datagram, I find its session object from a single map lookup on source address. The session is cross-linked to its partner (it seems from your description that they are paired one-to-one, though that's a simple enough change if I'm wrong).
No loops needed. The overhead is constant for any given client.

Related

Event driven and asynchronous serial port communication simultaneously

I'm completely new to serial port communication and need some help grasping it.
I need to communicate with a control board. This board can sometimes send events that I need to react to, and I need to send events to the board and await a response.
We have established a protocol where each event is always 12 bytes and the first 2 bytes determine the event type.
I know that when I send a specific message, I need to await a message with specific signifying bytes. At the same time I want it to be possible to react to events that are sent from the board. For instance the board might say that it is overheating, and at the same time I'm asking it to perform some command and reply.
My question is, if I write to the port and block for a second while awaiting the expected response, how I do ensure I don't "steal" the data my listener expects? E.g. do a serial ports work like a stream, where once I've read I've advanced past the point where it can be re-read.
I've done some implementation of this using jSerialComm, hopefully this can shed some light on my question.
First a listener that is registered using the addDataListener method. I want this to trigger when an event is present on the port that starts with "T".
private static LockerSerialPort getLockerSerialPort(final DeviceClient client) {
return MySerialPort.create(COM_PORT)
.addListener(EventListener.newBuilder()
.addEventHandler(createLocalEventHandler())
.build());
}
private static EventHandler createLocalEventHandler() {
return new EventHandler() {
#Override
public void execute(final byte[] event) {
System.out.println(new String(event));
}
#Override
public byte[] getEventIdentifier() {
// I want this listener to be executed when events that start with T are sent to the port
return "T".getBytes();
}
#Override
public String getName() {
return "T handler";
}
};
}
Next, I want to be able to write to the port and immediately get the response because it is needed to know if the command was successful or not.
private byte[] waitForResponse(final byte[] bytes) throws LockerException {
write(bytes);
return blockingRead();
}
private void write(final byte[] bytes) throws LockerException {
try (var out = serialPort.getOutputStream()) {
out.write(bytes);
} catch (final IOException e) {
throw Exception.from(e, "Failed to write to serial port %s", getComPort());
}
}
public byte[] blockingRead() {
return blockingRead(DEFAULT_READ_TIMEOUT);
}
private byte[] blockingRead(final int readTimeout) {
serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, readTimeout, 0);
try {
byte[] readBuffer = new byte[PACKET_SIZE];
final int bytesRead = serialPort.readBytes(readBuffer, readBuffer.length);
if (bytesRead != PACKET_SIZE) {
throw RuntimeException.from(null, "Expected %d bytes in packet, got %d", PACKET_SIZE, bytesRead);
}
return readBuffer;
} catch (final Exception e) {
throw RuntimeException.from(e, "Failed to read packet within specified time (%d ms)", readTimeout);
}
}
When I call waitForResponse("command"), how do I know my blocking read doesn't steal data from my listener?
Are these two patterns incompatible? How would one usually handle a scenario like this?

Communication management in client/server application

Let me explain the purpose of my application so you can guide me about the best possible approach.
The idea is building a web application to remotely manage some particular equipments that my company manufactures. These equipments will periodically connect to the remote server to send/receive certain data (through simple socket communication but they don't use Java); this data will be stored in the corresponding data base and will be available through the web application for the different users.
In the same way, when you access through the web interface, each client will be able to see their equipments and perform different changes in the configuration. At this point there are 2 possible options and this is the reason of this post:
The easiest but not the best option: the user performs some changes and I save those changes in the data base. When the equipment later establish communication to the server, then it'll read those changes and update its configuration.
The ideal solution: as soon as the user save the changes through the web interface and push the "send" button, those changes are sent to the corresponding equipment.
As mentioned above, these equipments will periodically open a socket communication (let's say every 5 minutes) to the server to send their configuration. At this moment, in order to implement the "ideal solution", the only option I can think of is not to close that socket so I can use it to immediately send information back to the equipment when a certain user makes any changes.
If this application grows along the time, I'm afraid that too many open sockets/threads can crash my application.
Let me illustrate with some code I was playing around. I know this is far from the final solution, it's just to help you understand what I'm looking for.
First of all, I register the socket server during the start-up of the web server (Tomcat in this case):
package org.listeners;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.sockets.KKMultiServer;
public class ApplicationListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
KKMultiServer kKMultiServer = new KKMultiServer();
Thread serverThread = new Thread(kKMultiServer);
serverThread.start();
event.getServletContext().setAttribute("PlainKKMultiServer", kKMultiServer);
}
public void contextDestroyed(ServletContextEvent event) { }
}
This is the main socket server class that listens for new connections:
public class KKMultiServer implements Runnable {
private Map<Long, KKMultiServerThread_v2> createdThreads = new HashMap<Long, KKMultiServerThread_v2>();
#Override
public void run() {
boolean listening = true;
try (ServerSocket serverSocket = new ServerSocket(5000)) {
while (listening) {
KKMultiServerThread_v2 newServerThread = new KKMultiServerThread_v2(serverSocket.accept(), this);
Thread myThread = new Thread(newServerThread);
myThread.start();
Long threadId = myThread.getId();
System.out.println("THREAD ID: " + threadId);
}
} catch (IOException e) {
System.err.println("Could not listen on port " + 5000);
System.exit(-1);
}
}
public Map<Long, KKMultiServerThread_v2> getCreatedThreads() {
return createdThreads;
}
}
And the thread class created with every single petition from each of the equipments (dispensers) to handle the socket communication:
public class KKMultiServerThread_v2 implements Runnable {
private Socket socket = null;
PrintWriter out = null;
BufferedReader in = null;
private long dispenserCode;
private KKMultiServer kKMultiServer;
public KKMultiServerThread_v2(Socket socket, KKMultiServer kKMultiServer) {
this.socket = socket;
this.kKMultiServer = kKMultiServer;
}
public void run() {
try {
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
readDataFromDispenser();
}
private void readDataFromDispenser() {
String inputLine;
try {
while ((inputLine = in.readLine()) != null) {
if (inputLine.equals("Bye")) {
break;
}
if (dispenserCode == 0) {
dispenserCode = 1111; // this code will be unique per equipment
this.kKMultiServer.getCreatedThreads().put(dispenserCode, this);
}
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendDataToDispenser(String dataToSend) {
if (!socket.isClosed() && socket.isConnected()) {
out.println(dataToSend);
} else {
this.kKMultiServer.getCreatedThreads().remove(this);
}
}
}
Now that the socket is created and alive I can use it directly from the web application to send messages back to the equipment (Struts Action in this case)
public class HelloWorldAction extends ActionSupport {
private static final long serialVersionUID = 1L;
public String sendMessageToDispenser() throws Exception {
ServletContext context = ServletActionContext.getServletContext();
KKMultiServer kKMultiServer = (KKMultiServer) context.getAttribute("PlainKKMultiServer");
Map<Long, KKMultiServerThread_v2> currentThreads = kKMultiServer.getCreatedThreads();
Iterator<Long> it = currentThreads.keySet().iterator();
while (it.hasNext()) {
Long key = (Long) it.next();
KKMultiServerThread_v2 currentThread = currentThreads.get(key);
currentThread.sendDataToDispenser("DATA TO YOU!");
}
return SUCCESS;
}
}
Do you think it's possible to perform this solution? I mean, keeping these connections open so I can access my equipments whenever necessary (without waiting for the periodically connections). What's the best approach? If you have any other suggestions please let me know.
Thank you very much.
To my mind it clearly depends on how many equipment will be connected to your system. Sockets are not always sending data so it can have low effect on the overall performance. Though, Socket are know to be a little slow, if you have a lot of data to send to/from your equipments, you should consider this.
If you want to have send data from your server to your client you have few solutions
Your server knows all your equipment after registering for example. When starting you equipment connect to the server. (be careful about local network redirection)
Your equipment and server use sockets to communicate
I don't think there is another solution but I can be wrong. If your equipment request your server every X seconds, it will never be exactly perfeclty on time.

Using AyncTask to send a UDP packet

I am trying to send a UDP packet to a computer on the same network as my tablet. In order to do this, I began by setting up a class to hold all the appropriate objects that I need in order to create a UDP socket, create a packet, and then send that packet. This class is shown below:
public static class Session
{
public InetAddress address;
public DatagramSocket socket;
public DatagramPacket packet;
public String client;
public int port;
public byte[] receive_buffer;
public byte[] send_buffer;
public String message;
public Session (InetAddress address, DatagramSocket socket, DatagramPacket packet,
String client, int port, byte[] receive_buffer, byte[] send_buffer,
String message)
{
this.address = address;
this.socket = socket;
this.packet = packet;
this.client = client;
this.receive_buffer = receive_buffer;
this.send_buffer = send_buffer;
this.message = message;
this.port = port;
}
}
Whenever I try to send a UDP packet, I begin by creating a Session object that contains a socket, packet, message, and a few other things. I also have a Send class that I use to actually send the UDP packet. This is shown below:
public static Session Send (Session session)
{
// Execute within "try" function to catch exceptions
try
{
/* Create address*/
session.address = InetAddress.getByName(session.client);
/* Create socket */
session.socket = new DatagramSocket(session.port);
/* Create packet */
session.packet = new DatagramPacket(session.message.getBytes(),
session.message.length(), session.address, session.port);
/* Send packet */
session.socket.send(session.packet);
/* Return session */
return session;
}
catch (Exception e)
{
Log.e("MYAPP", "exception: " + e.getMessage());
Log.e("MYAPP", "exception: " + e.toString());
}
return null;
}
However, Send() cannot be called directly, since one cannot perform network operations on the UI thread. In order to remedy this, I created an AsyncTask that calls Send(). Now all I have to do is pass the Session object to the AsyncTask and it will send the packet (in theory). The AsyncTask that I created is shown below:
class sendData extends AsyncTask<UDP.Session, Void, UDP.Session>
{
/* Pre-Execute Function */
#Override
protected void onPreExecute ()
{
super.onPreExecute();
}
/* Main AsyncTask Function */
#Override
protected UDP.Session doInBackground(UDP.Session... arguments)
{
/* Send UDP packet */
UDP.Session session = UDP.Send(arguments[0]);
return session;
}
/* Post-Execute Function */
#Override
protected void onPostExecute (UDP.Session session)
{
super.onPostExecute(session);
}
}
The issue that I am experiencing is that I cannot figure out how to return the session object from my AsyncTask. It is critical that I return the session that I passed to the AsyncTask, because otherwise the socket/port becomes corrupted and I get binding exceptions and a whole bunch of other issues when I try to send another packet. I tried using:
UDP.Session nsession = new sendData().execute(ssession).get();
but I get an error that states "Unhandled exceptions: java.lang.InterruptedException, java.util.concurrent.ExecutionException". So my question is what is the best way for me to return the session object that I pass to the AsyncTask so that I can use that same session object next time I want to send a packet.
I was being silly and not paying attention to the compiler warnings about the unhandled exceptions. The AsyncTask call made above (UDP.Session nsession = new sendData().execute(ssession).get();) is indeed correct, but it just needs to be placed inside a try/catch statement catch any possible exceptions. When I changed my code to the following...
try{
session = new sendData().execute(session).get();}
catch (Exception exception){}
...everything worked. I am able to properly return an object from the AsyncTask, and my socket no longer gets corrupted when the AsyncTask finished, allowing me to send as many packets as I want

Netty 4.0.23 multiple hosts single client

My question is about creating multiple TCP clients to multiple hosts using the same event loop group in Netty 4.0.23 Final, I must admit that I don't quite understand Netty 4's client threading business, especially with the loads of confusing references to Netty 3.X.X implementations I hit through my research on the internet.
with the following code, I establish a connection with a single server, and send random commands using a command queue:
public class TCPsocket {
private static final CircularFifoQueue CommandQueue = new CircularFifoQueue(20);
private final EventLoopGroup workerGroup;
private final TcpClientInitializer tcpHandlerInit; // all handlers shearable
public TCPsocket() {
workerGroup = new NioEventLoopGroup();
tcpHandlerInit = new TcpClientInitializer();
}
public void connect(String host, int port) throws InterruptedException {
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.remoteAddress(host, port);
b.handler(tcpHandlerInit);
Channel ch = b.connect().sync().channel();
ChannelFuture writeCommand = null;
for (;;) {
if (!CommandQueue.isEmpty()) {
writeCommand = ch.writeAndFlush(CommandExecute()); // commandExecute() fetches a command form the commandQueue and encodes it into a byte array
}
if (CommandQueue.isFull()) { // this will never happen ... or should never happen
ch.closeFuture().sync();
break;
}
}
if (writeCommand != null) {
writeCommand.sync();
}
} finally {
workerGroup.shutdownGracefully();
}
}
public static void main(String args[]) throws InterruptedException {
TCPsocket socket = new TCPsocket();
socket.connect("192.168.0.1", 2101);
}
}
in addition to executing commands off of the command queue, this client keeps receiving periodic responses from the serve as a response to an initial command that is sent as soon as the channel becomes active, in one of the registered handlers (in TCPClientInitializer implementation), I have:
#Override
public void channelActive(ChannelHandlerContext ctx) {
ctx.writeAndFlush(firstMessage);
System.out.println("sent first message\n");
}
which activates a feature in the connected-to server, triggering a periodic packet that is returned from the server through the life span of my application.
The problem comes when I try to use this same setup to connect to multiple servers,
by looping through a string array of known server IPs:
public static void main(String args[]) throws InterruptedException {
String[] hosts = new String[]{"192.168.0.2", "192.168.0.4", "192.168.0.5"};
TCPsocket socket = new TCPsocket();
for (String host : hosts) {
socket.connect(host, 2101);
}
}
once the first connection is established, and the server (192.168.0.2) starts sending the designated periodic packets, no other connection is attempted, which (I think) is the result of the main thread waiting on the connection to die, hence never running the second iteration of the for loop, the discussion in this question leads me to think that the connection process is started in a separate thread, allowing the main thread to continue executing, but that's not what I see here, So what is actually happening? And how would I go about implementing multiple hosts connections using the same client in Netty 4.0.23 Final?
Thanks in advance

How can I implement a threaded UDP based server in Java?

How can I implement a threaded UDP based server in Java ?
Basically what I want, is to connect multiple clients to the server, and let each client have his own thread. The only problem is, that I don't know how to check if a client is trying to connect to the server and spawn a new thread for it.
boolean listening = true;
System.out.println("Server started.");
while (listening)
new ServerThread().start();
In this case the server will spawn new threads until it runs out of memory.
Here's the code for the ServerThread ( I think I need here a mechanism that stalls the creation of the ServerThread until a client tries to connect.
public ServerThread(String name) throws IOException
{
super(name);
socket = new DatagramSocket();
}
So fathers of Java programming please help.
The design for this to a certain extent depends on whether each complete UDP "dialog" just requires a single request and immediate response, whether it's a single request or response with retransmissions, or whether there'll be a need to process lots of packets for each client.
The RADIUS server I wrote had the single request + retransmit model and spawned a thread for each incoming packet.
As each DatagramPacket was received it was passed to a new thread, and then that thread was responsible for sending back the response. This was because the computation and database accesses involved in generating each response could take a relatively long time and it's easier to spawn a thread than to have some other mechanism to handle new packets that arrive whilst old packets are still being processed.
public class Server implements Runnable {
public void run() {
while (true) {
DatagramPacket packet = socket.receive();
new Thread(new Responder(socket, packet)).start();
}
}
}
public class Responder implements Runnable {
Socket socket = null;
DatagramPacket packet = null;
public Responder(Socket socket, DatagramPacket packet) {
this.socket = socket;
this.packet = packet;
}
public void run() {
byte[] data = makeResponse(); // code not shown
DatagramPacket response = new DatagramPacket(data, data.length,
packet.getAddress(), packet.getPort());
socket.send(response);
}
}
Since UDP is a connectionless protocol, why do you need to spawn a new thread for each connection? When you receive a UDP packet maybe you should spawn a new thread to take care of dealing with the message received.
UDP connections are not like TCP connections. They do not remain active and such is the design of UDP.
The handlePacket() method of this next code block can do whatever it wants with the data received. And many clients can send multiple packets to the same UDP listener. Maybe it will help you.
public void run() {
DatagramSocket wSocket = null;
DatagramPacket wPacket = null;
byte[] wBuffer = null;
try {
wSocket = new DatagramSocket( listenPort );
wBuffer = new byte[ 2048 ];
wPacket = new DatagramPacket( wBuffer, wBuffer.length );
} catch ( SocketException e ) {
log.fatal( "Could not open the socket: \n" + e.getMessage() );
System.exit( 1 );
}
while ( isRunning ) {
try {
wSocket.receive( wPacket );
handlePacket( wPacket, wBuffer );
} catch ( Exception e ) {
log.error( e.getMessage() );
}
}
}
Have you looked at the Apache Mina project? I believe even one of its examples takes you through how to setup an UDP-based server with it. If this for a real product, I would not recommend trying to come up with your own implementation from scratch. You will want to use a library to accomplish this so you are not using one thread per connection, rather a thread pool.
I don't really see the need.
Its a school thing right?
If you need to keep track of the clients, you should have a local representation of each client (a Client object on your server). It can take care of whatever client-specific things you need to do.
In that case You need to be able to find out from which client the message was sent from. (using information from the message.) You can keep the clients in a map.
The most effective way is probably to do all handling in the main thread, unless whatever that needs to be done can "block" waiting for external events (or if some things that's supposed to happen might take a long time and some a very short.)
public class Client {
public void handleMessage(Message m) {
// do stuff here.
}
}
The client object can perhaps start a new thread in handleMessage() if neccesary.
You shouldn't start multiple server threads.
The server thread can do:
while(running) {
socket.receive(DatagramPacket p);
client = figureOutClient(p);
client.handleMessage(p);
}
If there are no client-specific things to care about, just read the messages and handle them as they arrive, in one thread.

Categories