I have a thread whose job is to sit on a DatagramSocket, listen for incoming packets, and place them into a queue for further processing. Its run method is:
public void run() {
while(!disconnected) {
byte[] buffer1 = new byte[FrameSizeBytes];
DatagramPacket RxPacket = new DatagramPacket(buffer1,buffer1.length);
try {
RxSocket.receive(RxPacket);
} catch (IOException e) {
// handle exception
}
buffer1 = RxPacket.getData();
Q.add(buffer1);
}
}
I have another thread whose job it is to decide when to terminate this thread.
It does this by setting the disconnected variable to true, and closing the socket.
The idea was that closing the socket would unblock the thread into an exception; the exception could be handled; and once the exception was handled the loop condition would cause the loop to exit. (Alternatively, the exception handling itself could set disconnected to true.)
Problem: The exception thrown in this condition is a SocketException: socket closed which makes perfect sense. But DatagramSocket.receive() doesn't throw SocketExceptions, and therefore I can't handle it or throw it.
Question: Is there some way to get this idea to work, or do I need to find another approach? (Note: I don't just want to set a timeout on the socket. That's not a good approach for this application.)
Set the flag, send yourself a dummy packet, then close the socket. After receive(), check the flag before processing the packet,
Related
I'm writing a server with Java.net. Now i want to change some variables on socket-timeout.
I cant find a 'onTimeout' interface or something similar.
Now I'm searching for a solution for this problem.
You say you're using java.net so I'm assuming that you're using something like a java.net.ServerSocket. If you call setSoTimeout on your instance of ServerSocket, you will be able to set a timeout for your socket. Then, when you block during calls to accept, your ServerSocket will keep track of the timeout. As you can see in the documentation, accept throws a SocketTimeoutException if a timeout has been defined and the wait time has exceeded the timeout. So, you'll end up with something like this (forgive me for being a bit rusty on Sockets):
try(ServerSocket ssock = new ServerSocket(...))
{
ssock.setSoTimeout(10_000); // 10 second timeout
while(true)
{
Socket csock = ssock.accept();
methodToStartThreadThatHandlesClientSocket(csock);
}
}
catch(SocketTimeoutException ste)
{
//handle socket timeout
}
catch(Exception other)
{
//handle other exceptions
}
I want to try to read from a socket's input stream for a certain time and then do something else if i don't receive any input
i know i can set a timeout for the socket that will do that
mySocket.setSoTimeout(200);
but will it still work (will the InputStream still throw an exception to my catch block) even if i incapsulate it in ObjectInputStream
public void startClient(){
try {
connection = new Socket(InetAddress.getByName(hostName), port);
output = new ObjectOutputStream( connection.getOutputStream());
output.flush();
input = new ObjectInputStream( connection.getInputStream());
}
catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
ExecutorService worker = Executors.newSingleThreadExecutor();
worker.execute( this );
}
and is there any other way of doing it if this doesn't work.
plus if the stream starts reading and it times out will it stop in the middle of it or will it continue until there are no more bytes in the stream
as in: will the stream timeout after it starts reading the object if the 200ms pass?
i want to do something like this
while(!connection.isClosed()){
try{
com = (String) input.readObject();
if(com.equals("TERMINATE CONNECTION")){
closeConnection();
}else if(com.equals("SEND DATA")){
sendData();
}
}catch(timeout exception){
if( timedout and want to do something){ do something else ....}
}
com="";
}
thanks everybody
If I set a timeout on the socket's input stream
You don't 'set a timeout on the socket input stream'. You set the timeout on the socket itself.
will it still work even if I cast that stream to another type?
There is no casting to another type here. You are wrapping the socket input stream in another type. There is no way the socket read timeout can possibly be affected by that, and no way for the socket to even know that you've done it.
In short the question doesn't make sense.
plus if the stream starts reading and it times out will it stop in the middle of it or will it continue until there are no more bytes in the stream
I can't make head or tail of this either, but if you get a timeout it means no data arrived within the timeout periods. It doesn't break the connection. It might however break the ObjectInputStream, if you somehow get a timeout in the middle of reading an object.
NB:
The timeout manifests itself as a SocketTimeoutException, not as something you detect in an if-else chain.
It isn't correct to loop while connection.isClosed() returns false. It doesn't magically become true when the peer closes the connection. In this case the correct technique is to loop until you get an EOFException.
I am developing a program that uses sockets and currently I have a function in my code that checks for a heartbeat from the client every second.
private void userLoop() { // checks for incoming data from client
Timer t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
try {
socketIn.read(); // check for heartbeat from client
String userInput;
while ((userInput = br.readLine()) != null) {
}
} catch (Exception e) {
ControlPanel.model.removeElement(getUsername());
ControlPanel.append(getUsername() + " has disconnected.");
}
}
}, 1000);
}
When a client closes the game via the X button, shutting off their computer, logging out, whatever it may be, I get the message "'username' has disconnected". This is exactly what I want, however, it only works with the while loop in the code. The while loop essentially does nothing and I have no idea why it doesn't work with out.
If I remove the while loop and I disconnect using my client nothing gets printed out server sided.
String userInput;
while ((userInput = br.readLine()) != null) {
}
The above is essentially the dead code that does nothing but without it my program doesn't work the way it should..
Why is the code needed and how can I remove it and still make my program work correctly?
In this case, your while loop is essentially stalling your program until you no longer receive an input string. It's not dead code; it is just your way of installing a wait.
Otherwise, based on my understanding in the Timer class, it only waits one second, which might be too short of a timespan for what you're waiting to capture.
I fixed my problem by changing everything in the try block with
br.readLine();
There's a saying I've heard about exception handling: "Exceptions should only be used for exceptional situations." A client disconnecting from a server is not exceptional.
Now that I have that off my chest, let's move on. According to this other question,
socket.getInputSteam.read() does not throw when I close the socket from the client
it sounds like the read call won't throw if you're closing things properly on the client side.
The problem is that when the remote socket is closed, read() does not throw an Exception, it just returns -1 to signal the end of the stream.
The following should work without needing to call readLine():
try {
int ret = socketIn.read(); // check for heartbeat from client
if (ret == -1) {
// Remote side closed gracefully
clientDisconnected();
}
} catch (SocketTimeoutException e) {
// Timeout -- handle as required
handleTimeout();
} catch (IOException e) {
// Connection lost due to I/O error
clientDisconnected()
}
This is my run method, it opens a socket, and waiting for an accepted connection, if connection is accepted, will have a separate Thread open for execute it:
while (isKeepRun) {
socket = serverSocket.accept();
WorkTask worktask = new WorkTask();
worktask.setSocket(socket);
worktask.setIn(new ObjectInputStream(socket.getInputStream()));
worktask.setOut(new ObjectOutputStream(socket.getOutputStream()));
Thread wt = new Thread(worktask);
wt.start();
}
if (socket != null) {
socket.close();
}
if (serverSocket != null) {
serverSocket.close();
}
When the user call it to stop, they call this method, to change the while loop condition. in order to break the while loop:
public void stopWorking() {
isKeepRun = false;
}
Well, the WorkTask's run method is very simple like that:
try {
do {
objectOutputStream.flush();
receivedObj = objectInputStream.readObject();
if (receivedObj != null){
System.out.println(receivedObj.toString()+" " + receivedObj.hashCode());
}
} while (receivedObj != null
&& !receivedObj.equals(SharedConstant.SOCKET_EOF_STRING));
if (objectInputStream != null) {
objectInputStream.close();
}
if (objectOutputStream != null) {
objectOutputStream.close();
}
} catch (IOException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
The problem is assume that reading one message need 1 second per message, the user may give up to 100 messages, that's mean it requires 100 seconds to run, in the socket. When the isKeepRun is keep running, there is no problem. But when the user wanna to stop , and call stopWorking, the loop will be escaped, can the socket is closed, during the WorkTask is reading the message. How can I delay the execution of stopWorking if the socket is still reading, if the socket is finished reading, and the stopWorking will be call immediately, but if the socket don't have any thing to read, I can call the stopWorking in no delay?
Thanks.
If your worker thread is handling your client request then it should be his responsibility to close the socket connection. You should move the code that closes the accepted socket into your worker thread. Your server socket accept loop will be independent and will close as soon as the close request is made. But, the existing connections will still be valid and the worker thread can continue handling them.
There is a problem in your code:
while (isKeepRun) {
socket = serverSocket.accept();
....
}
....
if (socket != null) {
socket.close();
}
You use only one socket reference for all client socket. So if there are more than one client socket, then you will only close the last socket.
As above said, you can use wt.join() to wait for the worker thread to finish, then the main thread will finish. But you have only one reference for client socket. Even you wait, you can only wait for the last socket to finish. All the previous client socket will be closed if you set it to stop.
Try adding
wt.join()
after the wt.start(). This waits for thread to finish it's execution.
You can check if there are still active worker threads around by calling their isAlive method. To do so, you need to keep track of your workers (using some list or map).
You might also use a call back mechanism for the workers, through which they can report back, when they finished their task. Before stopping, you simply check if every worker is done.
In both cases, if there are still active workers, sleep for some time, and check again, until all threads have finished.
Edit:
Vikas Nalwar made a good point about letting the workers close the socket connection. It still might be a good idea to wait for the worker threads to finish, though.
I've written a tcp server in Java. It spawns worker instances (Runnable) and listens for incoming tcp connection. Upon connection from a client, it will take in data from the client and does its own processing.
Of late, I noticed that upon client disconnection, the entire server will crash with error java.net.SocketException: Connection reset when the client disconnects or quits. This was when I realised I hadn't tested the tcp server thoroughly for all instances of failure.
I looked into the code and noticed that the tcp server will crash at this line while((bytesRead.... -1) in the worker instance
final int BUFFSIZE = 65535;
int bytesRead;
byte[] buffer = new byte[BUFFSIZE];
din = new BufferedInputStream(clientSocket.getInputStream());
while ((bytesRead = din.read(buffer)) != -1) { //tcp server crashes at this line if client quits or disconnects.
// worker does its job.
}
I've been pondering about the best way to close worker instance without causing a crash on the tcp server. I don't have access to the client source code to modify anything on their end.
Any thoughts?
Bregs
Yakult121
Network I/O should be done within a try/catch block if you want to handle exceptions.
This line should throw an IOException if the connection is closed. Just make sure to catch the IOException and return from the run() method of your Runnable when it occurs. This will stop the thread handling this client connection.
You must have done something incorrectly if it craches the whole server, though. This probably means you don't have a thread per client connection, but rather a single thread handling the clients sequentially, one at a time. Post the server code for more information.
figured out the problem. Writing down what i did for any person looking to solve the same problem.
private boolean isStopped = false;
while (!isStopped()) {
try {
while ((bytesRead = din.read(buffer)) != -1) {
// worker does its job.
}
}
catch (IOException ex) {
System.out.println("Exception called! Most likely due to client disconnect!");
stop();
}
}
public boolean isStopped() {
return this.isStopped;
}
public synchronized void stop(){
this.isStopped = true;
}