Java timeout since last received datagram - java

I have the following code in my main application:
package acast;
import java.net.SocketException;
import java.util.concurrent.ConcurrentLinkedQueue;
public class ACast {
private ConcurrentLinkedQueue<String> queue;
public ACast() throws SocketException{
queue = new ConcurrentLinkedQueue<String>();
UDPServer srv = new UDPServer(4321);
srv.addUDPacketListener(new UDPPacketListener() {
#Override
public void onPacketReceived(String packet) {
ACast.this.queue.offer(packet);
}
});
srv.start();
}
public static void main(String[] args) throws SocketException {
try{
new ACast();
}
catch(SocketException e){
//e.printStackTrace();
System.out.println("Socket allready opened. Can't start application");
System.exit(1);
}
}
}
My UDPServer extends Thread and calls onPacketReceived every time it receives an UDP datagram. I want my main app to do something every time a configured timeout passes since the last received datagram. I would like to avoid running a Thread that just checks the timeout from second to second. I would like to start a countdown thread exactly on the moment of the last received datagram and cancel any other ongoing timeout threads if available. Any help ?

A simple solution would be to start a Timer with the timeout task, and every time a new datagram is received, cancel the currently running timer and start a new one.

I would lose the asynchronicity altogether, and use blocking I/O with a read timeout.

Related

RMI garbage collection of callbacks

I need to create a RMI service which can notify events to clients.
Each client register itself on the server, the client can emit an event and the server will broadcast it to all other clients.
The program works, but, the client reference on the server is never garbage collected, an the thread which the server uses to check if the client reference will never terminate.
So each time a client connects to the server, a new thread is created and never terminated.
The Notifier class can register and unregister a listener.
The broadcast method call each registered listener and send the message back.
public class Notifier extends UnicastRemoteObject implements INotifier{
private List<IListener> listeners = Collections.synchronizedList(new ArrayList());
public Notifier() throws RemoteException {
super();
}
#Override
public void register(IListener listener) throws RemoteException{
listeners.add(listener);
}
#Override
public void unregister(IListener listener) throws RemoteException{
boolean remove = listeners.remove(listener);
if(remove) {
System.out.println(listener+" removed");
} else {
System.out.println(listener+" NOT removed");
}
}
#Override
public void broadcast(String msg) throws RemoteException {
for (IListener listener : listeners) {
try {
listener.onMessage(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
The listener is just printing each received message.
public class ListenerImpl extends UnicastRemoteObject implements IListener {
public ListenerImpl() throws RemoteException {
super();
}
#Override
public void onMessage(String msg) throws RemoteException{
System.out.println("Received: "+msg);
}
}
The RunListener client subscribes a listener wait few seconds to receive a message and then terminates.
public class RunListener {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.getRegistry();
INotifier notifier = (INotifier) registry.lookup("Notifier");
ListenerImpl listener = new ListenerImpl();
notifier.register(listener);
Thread.sleep(6000);
notifier.unregister(listener);
UnicastRemoteObject.unexportObject(listener, true);
}
}
The RunNotifier just publish the service and periodically sends a message.
public class RunNotifier {
static AtomicInteger counter = new AtomicInteger();
public static void main(String[] args) throws RemoteException, AlreadyBoundException, NotBoundException {
Registry registry = LocateRegistry.createRegistry(1099);
INotifier notifier = new Notifier();
registry.bind("Notifier", notifier);
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
try {
int n = counter.incrementAndGet();
System.out.println("Broadcasting "+n);
notifier.broadcast("Hello ("+n+ ")");
} catch (RemoteException e) {
e.printStackTrace();
}
}
},5 , 5, TimeUnit.SECONDS);
try {
System.in.read();
} catch (IOException e) {
}
executor.shutdown();
registry.unbind("Notifier");
UnicastRemoteObject.unexportObject(notifier, true);
}
}
I've seen many Q&A on stack overflow about RMI, but none addresses this kind of problem.
I guess I'm doing some very big mistake, but I can't spot it.
As you can see in the picture, a new RMI RenewClean thread is created for each incoming connection, and this thread will never terminate.
Once the client disconnects, and terminates, the RenewClean thread will silently swallow all ConnectionException thrown and will keep polling a client which will never reply.
As a side note, I even tried to keep just weak reference of the IListener in the Notifier class, and still the results are the same.
This may not be very helpful if you are stuck on JDK1.8, but when I test on JDK17 the multiple rmi server threads created for each incoming client RMI RenewClean-[IPADDRESS:PORT] are cleaned up on the server, and not showing "will never terminate" behaviour you may have observed on JDK1.8. It may be a JDK1.8 issue, or simply that you are not waiting long enough for the threads to end.
For quicker cleanup, try adjusting the system property for client thread garbage collection setting from the default (3600000 = 1 hour):
java -Dsun.rmi.dgc.client.gcInterval=3600000 ...
On my server I added this in one of the API callbacks:
Function<Thread,String> toString = t -> t.getName()+(t.isDaemon() ? " DAEMON" :"");
Set<Thread> threads = Thread.getAllStackTraces().keySet();
System.out.println("-".repeat(40)+" Threads x "+threads.size());
threads.stream().map(toString).forEach(System.out::println);
After RMI server startup it printed names of threads and no instances of "RMI RenewClean":
---------------------------------------- Threads x 12
After connecting many times from a client, the server reported corresponding instances of "RMI RenewClean":
---------------------------------------- Threads x 81
Leaving the RMI server for a while, these gradually shrank back - not to 12 threads -, but low enough to suggest that RMI thread handling is not filling up with many unnecessary daemon threads:
---------------------------------------- Threads x 20
After about an hour all the remaining "RMI RenewClean" were removed - probably due to housekeeping performed at the interval defined by the VM setting sun.rmi.dgc.client.gcInterval=3600000:
---------------------------------------- Threads x 13
Note also that RMI server shutdown is instant at any point - the "RMI RenewClean" daemon threads do not hold up rmi server shutdown.

Java: Multithreading with two different input sources and reacting

First question here on StackOverflow, so please excuse me if I ask this incorrectly.
Basically, I'm writing a Multicast Client that indefinitely listens to a multicast address until the user types "quit" into the console. I've found that setting SO_TIMEOUT for the MulticastSocket, checking if "quit" has been typed, and then returning to the receive method call doesn't really work since a packet could be sent right after the timeout and the check of the console blocks. So I believe the best option is to simply have 2 threads going where one listens on the socket and blocks until it receives something, and the other thread listens to the console until told to quit. The only issue I have is that I'm unsure of how to go about having the console listening thread tell the socket thread to close the socket and terminate. System.end() would work but I fear that I'd leave a socket open, etc.
TLDR; Is there a way for the main method of a class to start a thread, and then respond a specific way once that thread ends? I need to listen to the console on one thread and a MulticastSocket on another, or just in the main of the client class.
Thanks everyone.
I would call Socket.close() to close the socket. This will produce an IOException in that thread. so before doing this I would set a flag like closed = true; and have the other thread check this before printing the error i.e. don't print an IOException if you have been closed. Something like this.
public class SocketListener implements Runnable, Closeable {
final MulticastSocket socket;
final Consumer<DatagramPacket> packetConsumer;
volatile boolean closed;
public SocketListener(MulticastSocket socket, Consumer<DatagramPacket> packetConsumer) {
this.socket = socket;
this.packetConsumer = packetConsumer;
}
#Override
public void run() {
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
try {
while(!closed) {
socket.receive(packet);
packetConsumer.accept(packet);
}
} catch (IOException e) {
if (!closed)
e.printStackTrace();
}
}
#Override
public void close() throws IOException {
closed = true;
socket.close();
}
}
for example, in your main thread you can do
MulticastSocket socket = ...
Consumer<DatagramPacket> packetConsumer = ...
try (SocketListener listener = new SocketListener(socket, packetConsumer)) {
boolean finished = false;
do {
// read from the console
if (some condition)
finished = true;
} while(!finished);
} // calls close() for you.

Why are my Java threads not running at the same time?

I have an application that is communicating with a UDP server. My application listens on one port (say 1234) and sends on another (say 5678). The UDP server I am communicating with also requires a "heartbeat" ever 5 seconds, for which I create another thread. When my application first starts up, I create the listen thread, then create the heartbeat thread, then I start sending the UDP server message packets. The only thing, however, is that it seems like all the packets I send out finish before the heartbeat thread starts.
Here is what I have for my listener:
public class MyListener implements Runnable {
private volatile boolean run = true;
private DatagramSocket myDatagramSocket;
private DatagramPacket myDatagramPacket;
private byte[] receiveBuffer;
private int receiveBufferSize;
#Override
public void run(){
while(run){
try {
myDatagramSocket = new DatagramSocket(null);
InetSocketAddress myInetSocketAddress = new InetSocketAddress(1234);
myDatagramSocket.bind(myInetSocketAddress);
receiveBuffer = new byte[2047];
myDatagramPacket = new DatagramPacket(receiveBuffer, 2047);
myDatagramSocket.receive(myDatagramPacket);
byte[] data = myDatagramPacket.getData();
receiveBufferSize = myDatagramPacket.getLength();
switch(messageID){
...
}
} catch (Exception e){
}
}
}
}
Here is what I have for my heartbeat:
public class MyHeartbeat implements Runnable {
private volatile boolean run = true;
private HeartbeatSenderClass heartbeatSender;
#Override
public void run(){
while(run){
try {
TimeUnit.SECONDS.sleep(5);
heartbeatSender.sendHeartbeat();
} catch(Exception e){
}
}
}
}
Here is what I have for my main class:
public class MyApp {
public static void main(String[] args){
MyListener listener = new MyListener();
Thread listenerThread = new Thread(listener);
listenerThread.setName("Listener Thread");
listenerThread.start();
MyHeartbeat heartbeat = new MyHeartbeat();
Thread heartbeatThread = new Thread(heartbeat);
heartbeatThread.setName("Heartbeat Thread");
heartbeatThread.start();
MySender sender = new MySender();
Thread senderThread = new Thread(sender);
senderThread.setName("Sender Thread");
senderThread.start();
}
}
All of my packets are making it to the UDP server, but not smoothly like I would have thought. I would have thought that while I am sending packets to the server, every 5 seconds my heartbeat would be sent out. However, it seems like my heartbeats are going out only after my packets are done sending. Also, I believe I am not getting all of the messages from the UDP server. I say this because I have sniffed the UDP packets on my machine and I see data coming from the server that my receiver is not receiving/processing. Any suggestions?
You have in heartbeat this:
TimeUnit.SECONDS.sleep(5);
heartbeatSender.sendHeartbeat();
So before sending the very first beat, you wait for 5 seconds. No wonder that the other threads do their job meanwhile.
The DatagramSocket you use to send the packets is a shared resource that is contended between threads, and then if a thread consume too much of that resource, another one may starve. See: Thread starvation
Also if you are loosing packets, it happens because you can't read as fast as you should. If udp packets arrive faster then they can be read, the queue will discard the remaining.
Under linux, for example you can control the receive buffer with:
sudo sysctl -w net.core.rmem_default=26214400
sudo sysctl -w net.ipv4.udp_mem='26214400 26214400 26214400'
sudo sysctl -w net.ipv4.udp_rmem_min=26214400
But anyway if we are talking about a sustained loss, you should consider to have a thread for reading the buffer, a queue and a thread to process the readed data.

Java Multiple threads for just 2 computers, how to do it in main

I'm trying to get at least two computers to connect to my server, how would i start a second thread?
public static void main(String[] args) throws InterruptedException {
// Create the server which waits for a client to request a connection.
while(true){
FileSharedServer server = new FileSharedServer();
Thread thread = new Thread(server);
thread.start();
}
}
this refuses my connection
You need to wait on serverSocket.accept() method on incoming connections in your server, and after receiving one start a thread to serve it, but the server socket stay the same, you just do waiting for next connection in a loop.
while (true) {
Socket connection = serverSocket.accept();
new Therad() {
public void run() {
serveConnection(connection);
}
}.start();
}

Socket.close() have no effect during Socket.connect()

Using the default socket implementation on Windows, I was not able to find any effective method to stop Socket.connect(). This answer suggests Thread.interrupt() will not work, but Socket.close() will. However, in my trial, the latter didn't work either.
My goal is to terminate the application quickly and cleanly (i.e. clean up work needs to be done after the socket termination). I do not want to use the timeout in Socket.connect() because the process can be killed before a reasonable timeout has expired.
import java.net.InetSocketAddress;
import java.net.Socket;
public class ComTest {
static Socket s;
static Thread t;
public static void main(String[] args) throws Exception {
s = new Socket();
InetSocketAddress addr = new InetSocketAddress("10.1.1.1", 11);
p(addr);
t = Thread.currentThread();
(new Thread() {
#Override
public void run() {
try {
sleep(4000);
p("Closing...");
s.close();
p("Closed");
t.interrupt();
p("Interrupted");
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
s.connect(addr);
}
static void p(Object o) {
System.out.println(o);
}
}
Output:
/10.1.1.1:11
Closing...
Closed
Interrupted
(A few seconds later)
Exception in thread "main" java.net.SocketException: Socket operation on nonsocket: connect
You fork the thread and then the main thread is trying to make the connection to the remote server. The socket is not yet connected so I suspect s.close() does nothing on a socket that is not connected. It's hard to see what the INET socket implementation does here. t.interrupt(); won't work because the connect(...) is not interruptible.
You could use the NIO SocketChannel.connect(...) which looks to be interruptible. Maybe something like:
SocketChannel sc = SocketChannel.open();
// this can be interrupted
boolean connected = sc.connect(t.address);
Not sure if that would help though.

Categories

Resources