How to interrupt a blocking call to UDP socket's receive() [duplicate] - java

This question already has answers here:
How to terminate a thread blocking on socket IO operation instantly?
(2 answers)
Closed 6 years ago.
I have a UDP server listening packets from a client.
socket = new DatagramSocket(port);
while (isListen) {
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, 0, data.length);
socket.receive(packet);
}
The receive() method will wait forever before a packet received. Is it possible to stop waiting for receiving? I can set a boolean isListen to stop the loop. On the other hand, if the socket is waiting then it will wait forever if no packet send from the client.

You need to set a socket timeout with the setSoTimeout() method and catch SocketTimeoutException thrown by the socket's receive() method when the timeout's been exceeded. After catching the exception you can keep using the socket for receiving packets. So utilizing the approach in a loop allows you to periodically (according to the timeout set) "interrupt" the receive() method call.
Note that timeout must be enabled prior to entering the blocking operation.
An example (w.r.t your code):
socket = new DatagramSocket(port);
socket.setSoTimeout(TIMEOUT_IN_MILLIS)
while (isListen) {
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, 0, data.length);
while (true) {
try {
socket.receive(packet);
break;
} catch (SocketTimeoutException e) {
if (!isListen) {} // implement your business logic here
}
}
// handle the packet received
}

You can close the socket from another thread. The thread blocked in receive() will then throw an IOException.
while (isListen) {
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, 0, data.length);
try {
socket.receive(packet);
} catch(IOException e) {
continue;
}
}
void stopListening() { // Call me from some other thread
isListen = false;
socket.close();
}

Related

Is JAVA NIO wasting CPU cycles by looping continuously?

Code for an echo server using a single threaded java I/O
public static void main(String[] args) throws Exception {
// create socket
int port = 4444;
ServerSocket serverSocket = new ServerSocket(port);
System.err.println("Started server on port " + port);
try {
// repeatedly wait for connections, and process
while (true) {
// a "blocking" call which waits until a connection is requested
Socket clientSocket = serverSocket.accept();
System.err.println("Accepted connection from client");
// open up IO streams
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintStream out = new PrintStream(clientSocket.getOutputStream());
// waits for data and reads it in until connection dies
// readLine() blocks until the server receives a new line from client
String s;
while ((s = in.readLine()) != null) {
out.print(s);
}
// close IO streams, then socket
System.err.println("Closing connection with client");
out.close();
in.close();
clientSocket.close();
}
} finally {
serverSocket.close();
}
}
code for the same using NIO
public static void main(String[] args) throws IOException {
ServerSocketChannel server = ServerSocketChannel.open();
server.socket().bind(new InetSocketAddress(PORT_NUMBER));
server.socket().setReuseAddress(true);
server.configureBlocking(false);
Selector selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
while (true) {
int channelCount = selector.select();
if (channelCount > 0) {
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iterator = keys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (key.isAcceptable()) {
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ, client.socket().getPort());
} else if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
System.out.println("port: " + key.attachment());
if (client.read(buffer) < 0) {
key.cancel();
client.close();
} else {
buffer.flip(); // read from the buffer
/*
* byte[] received = new byte[buffer.remaining()];
* buffer.get(received); buffer.clear(); // write into the buffer
* buffer.put(received); buffer.flip(); // read from the buffer
*/
client.write(buffer);
buffer.clear(); // write into the buffer
}
}
}
}
}
}
Here using normal I/O the main thread comes and wait at the socket.accept() call. But NIO doesn't do that since socketChannel.accept() is not a blocking call.
So wont the NIO program be continuously running the loop ? And result in waste of CPU cycles ? Can I write the program in a better way. Sorry I am very new to JAVA NIO and asynchronous programming.
In normal IO the thread is blocked on serverSocket.accept().
With NIO the thread is blocked on selector.select().
From the JavaDoc of Selector#select():
This method performs a blocking selection operation.
Why is this called "non blocking IO"?
Actually, your first example (with normal IO) has two blocking calls: server.accept() and in.readLine().
Now consider the case with a badly behaving client: it opens a connection to the server, but never sends any data. With normal IO the server thread waits in in.readLine() for data to arrive and cannot serve any other client until the first client closes its connection.
With NIO the picture is different: if a client opens a connection, the server thread wakes up, server.accept()s the connection and registers the SocketChannel with the same selector. Then the server thread waits on the selector once more through selector.select(). Now there are two possibilities to wake up the server thread: either another client connecting, or the first client sending some data.
So the term "non blocking IO" does not mean that the server thread is never blocked - it means that a non-behaving client cannot block the server thread forever.

OnMessage() functionality for UDP

I was wondering if there is a type of OnMessage() type functionality for UDP messages using DatagramPacket? I want to be able to ensure that I get all messages when they come across so I don't waste resources randomly grabbing on a timer.
The OnMessage I am referring to the one done in WebSocketClient. Or some functionality similar to "Available" in .net.
While (rxUdpClient.Available > 0)
I am monitoring several ports so a thread is called which will do a run() for each port. Problem is I seem to have messages coming in at a massive rate 40+/sec.
This is what I currently have:
public void run()
{
DatagramSocket sock = null;
sock = new DatagramSocket(port);
byte[] buffer = new byte[DataAdapterFB1.HEADER_SIZE + DataAdapterFB1.MAX_DATA_BYTES];
DatagramPacket incoming = new DatagramPacket(buffer, buffer.length);
while (true){
sock.receive(incoming);
byte[] data = incoming.getData();
String s = new String(data, 0, incoming.getLength());
//This is the processing code, but it isn't its own thread...
ScadaMsg newMessage = new ScadaMsg(data);
}
}
DatagramPacket receive() operation is blocking, so what you will normally do is just launch a separate thread, which will listen for the incoming datagrams in a loop and dispatch them for further processing, like that:
void run() {
socket = new DatagramSocket(4445);
while(true) {
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet); //JVM will wait here, until there is an incoming packet
onMessage(packet.getData())
}
}
public abstract void onMessage(final byte[] pkt);

How to set a timeout in a UDP client for when a packet is not sent from server?

I am writing a simple program about UDP socket programming. I am using datagram sockets. I have to send packet from the client to the server. Then the server decides randomly if to send a packet back. The client has to accept the packet if sent or wait 2 seconds and assume the packet is lost. I cannot handle the case of the packet lost.
System.out.println("Receiving message...");
dsock.receive(dpack); // receive the packet
System.out.println("Message received");
It works all fine if the packet is sent but how can I handle a situation when a packet is not sent and I still have this line of code existing?
You can change the timeout of the socket and receive messages until timeout is reached, as seen here:
try {
dsock = new DatagramSocket();
byte[] buf = new byte[1000];
DatagramPacket dpack = new DatagramPacket(buf, buf.length);
//...
dsock.setSoTimeout(1000); // set the timeout in millisecounds.
while(true) { // recieve data until timeout
try {
System.out.println("Receiving message...");
dsock.receive(dpack); // receive the packet
System.out.println("Message received");
}
catch (SocketTimeoutException e) {
// timeout exception.
System.out.println("Timeout reached!!! " + e);
dsock.close();
}
}
catch (SocketException e) {
System.out.println("Socket closed " + e);
}
You are searching for dsock.setSoTimeout(2 * 1000) (2*1000 = 2000 ms = 2s). Here is the doc
Enable/disable SO_TIMEOUT with the specified timeout, in milliseconds. With this option set to a non-zero timeout, a call to receive() for this DatagramSocket will block for only this amount of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the DatagramSocket is still valid. The option must be enabled prior to entering the blocking operation to have effect. The timeout must be > 0. A timeout of zero is interpreted as an infinite timeout.
This will raised a SocketTimeoutException after two seconds, so you have to catch it.

Java UDP receive()

I am trying to implement Go Back N using UDP sockets in Java. I have a sender and receiver thread at the client end. The sender thread has its own UPD socket to send the data packets and the receiver thread has its own port to receive acknowledgements. If a receiver doesn't receive ACK before a timeout period, the packet has to be retransmitted. Both threads are always running with a while(true) loop. I observe that when there are no packet losses(i.e no timeouts), this functionality of sending and receiving works fine, but when the ACK isn't received, that is when there is a timeout, the switching to the sender thread (for retransmission) isn't happening. The execution is stuck in the receiver's for loop, showing timeouts over and over again.
I even tried using Thread.Sleep(), so that it lets the other thread work. but it isn't happening. Any help would be appreciated.
(The slideflag that is set to 0, will initiate retransmission in the other thread ideally)
while(true){
socket.setSoTimeout(10000);
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
try{
socket.receive(packet);
} catch(Exception e) {
System.out.println("Socket timeout!");
ClientMain.setslideFlag(0);
Thread.sleep(10000);
continue;
}
}

Java client/server issue sending objects over sockets [duplicate]

This question already has answers here:
Java socket/serialization, object won't update
(2 answers)
Closed 7 years ago.
I'm creating a standard multi-client/server program in Java. The server accepts connections and spawns a new thread to handle each one. The client also spawns a thread to wait for messages from the server. The client and server communicate by passing Message objects through ObjectInputStream and ObjectOutputStreams.
The initial handshake works fine. When the client starts, it opens a socket connection to the server. The server accepts the socket, sends a Message to the client that the connection was successful. Then the client sends its username back, and both client and server start waiting for messages.
Then I send some text from my client which creates a chat message, and sends it successfully to the server. The server receives this message, and attempts to send it out to all connected clients, which it does (there's only one). The problem is that this message never gets back to the client.
// This is Message.send
public void send(ObjectOutputStream stream) throws IOException{
stream.writeObject(this);
}
// ClientThread.run
public void run(){
try {
out = client.getOutputStream();
out.flush();
ObjectInputStream in = client.getInputStream();
Message msg = null;
int len;
byte[] bytes = null;
int i = 0;
// Continuously read new Messages from the server
while(true){
msg = (Message)in.readObject();
processInput(msg);
}
} catch (Exception e) {
Util.showError(e.getMessage(), "Connection Error");
}
System.out.println("Client exited");
}
// ServerThread.run
public void run() {
try {
out = new ObjectOutputStream(client.getOutputStream());
ObjectInputStream in = new ObjectInputStream(client.getInputStream());
Message msg = null;
while(client.isConnected()){
msg = (Message)in.readObject();
processInput(msg);
}
in.close();
client.close();
} catch (Exception e) {
server.addMessage(e.getMessage());
}
}
I don't see any calls to flush(), without which the data may never make it from point a to point b.
I'd recommend using the ObjectOutputStream atop a ByteArrayOutputStream, and pushing the resulting byte array across the wire, and then reversing the process on the other end.

Categories

Resources