(Java) Receiving packets from the same socket on multiple threads simultaneously - java

I'm writing a program that:
Sends ping packets to other processes running the same program
The process sends a response to the ping from (1)
If a process does not receive a response in X seconds, then call a method to update states
So I currently only have 1 Datagram socket that handles both sending and receiving the packets. The way I handled the ping timeout was calling setSoTimeout on the socket and blocking on the receive right after I send the ping packet to another process.
public MyProgram {
private DatagramSocket socket;
public MyProgram() {
socket = new DatagramSocket("localhost", 12345);
Thread sendingThread = new Thread(new Runnable() {
public void run() {
// call sendLoop method
}
}
Thread receiveThread = new Thread(new Runnable() {
public void run() {
// call receiveLoop method
}
}
}
public void sendLoop() {
while (true) {
/*
send ping to other process
*/
// now wait until it replies with ACK
try {
socket.receive(...);
} catch (SocketTimeoutException e) {
// call method to update state
}
}
}
// ... more code ...
}
Now the problem is when I write receiveLoop (separate thread to sendLoop) which waits for incoming ping packets from other processes
public void receiveLoop() {
while (true) {
socket.receive(...);
// call methods to reply to the ping
}
}
How can I wait for a response to my own ping, whilst waiting for incoming pings on another thread? I figured this approach would be bad because the ping response could arrive on the other thread?
Can you even simultaneously call receive on the same UDP socket in different threads?
Is there a way to solve this without having to create another UDP socket? Many thanks!

Related

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();
}

Multi Thread Java Server

am currently working on a project where I have to build a multi thread server. I only started to work with threads so please understand me.
So far I have a class that implements the Runnable object, bellow you can see the code I have for the run method provided by the Runnable object.
public void run() {
while(true) {
try {
clientSocket = serversocket.accept();
for (int i = 0; i < 100; i++) {
DataOutputStream respond = new DataOutputStream(clientSocket.getOutputStream());
respond.writeUTF("Hello World! " + i);
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
//
}
}
} catch(IOException e) {
System.out.println(e.getMessage());
}
}
}
Bellow is the main method that creates a new object of the server class and creates a threat. initializing the Thread.
public static void main(String args[]) {
new Thread(new Server(1234, "", false)).start();
}
I know this creates a new thread but it does not serve multiple clients at once. The first client need to close the connection for the second to be served. How can I make a multi threated server that will serve different client sockets at once? Do I create the thread on the clientSocket = serverSocket.accept();
yes.
from the docs:
Supporting Multiple Clients
To keep the KnockKnockServer example simple, we designed it to listen for and handle a single connection request. However, multiple client requests can come into the same port and, consequently, into the same ServerSocket. Client connection requests are queued at the port, so the server must accept the connections sequentially. However, the server can service them simultaneously through the use of threads—one thread per each client connection.
The basic flow of logic in such a server is this:
while (true) {
accept a connection;
create a thread to deal with the client;
}
The thread reads from and writes to the client connection as necessary.
https://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html

Event-Based Networking

I have setup a simple server and client, where the server waits for the client to send something and then sends a response. But the downside is that both have to listen for the socket to receive something. What if I wanted it to be more flexible in the communication? I was thinking something event-based, so every time the socket received something it'd call a method to handle it, instead of pausing the program to wait for socket.nextLine().
Here's what my server code looks like:
try{
ss = new ServerSocket(port);
s = ss.accept();
in = new Scanner(s.getInputStream());
out = new PrintWriter(s.getOutputStream(), true);
while(!s.isClosed()){
String input = in.nextLine();
handleInput(input);
}
} catch (Exception e){}
And in the handleInput() I send a response to the client.
If you want to be event based with the client doing something when the server sends a packet, then multithread.
Thread t = new Thread(new Runnable() {
public void run() {
someMethod(in.nextLine());
}
});
t.start();
You'd have to make in a field in the enclosing class.
This would cause your program to execute, and when a it receives a packet it would call someMethod().
Of course, this opens up a multitude of problems associated with multithreading, but it's really the only way to do what you want to.

Categories

Resources