I am a beginner to networking and am working on implementing it in a game i have, it is mostly working but in the client my loop receiving packets is stopping ant a try catch. here is the code:
public void run() {
while(true){
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
try {
socket.receive(packet);
}catch(IOException e){
e.printStackTrace();
}
this.parsePacket(packet.getData(), packet.getAddress(), packet.getPort());
}
}
After debugging i have found that the loop is not getting past the try catch statement.(but the try is being activated once seemingly with no error).
First of all your loop condition that you provided is not a variable, You have directly used a boolean valued true . It might a situation of infinite-loop.
while(true){..... // yourCode ....}
Your loop will continue even if socket.receive(packet); line raise an IOException because this exception is handled by the catch() block.
it means it will execute till any exception raised at this line
this.parsePacket(packet.getData(), packet.getAddress(), packet.getPort());
Now, Your problem is this method public void receive(DatagramPacket p) actually method will work till datagram is received but your loop will continue till exception is raised till this.parsePacket() method raised an Exception.
So, please change your conditional statement such that if datagram is no more present then loop must be terminated.
As per java-docs for the method public void receive(DatagramPacket p)
This method blocks until a datagram is received.
The thread executing the flow gets blocked [waits until the datagram is received]. Your loop is not broken its just in halt state.
Loop will be broken in case of some exception occurs which is not caught and handled in side the body of the loop.
Also there is little suggestion I would like you to implement in your code. You should not run an infinite loop. Instead of using true you can try using Thread.currentThread().isInterrupted() and when your game ends you can call interrupt() on the Thread responsible for executing the code flow of the loop. Also if in case of IOException you wish to retry (may be in retry resources are in order and you do not get the exception) then putting catch inside the loop is O.K. else you can move the catch outside the loop, it depends on your need and flow. You can probably put a counter for number of retries.
Related
I made a simple UDP server/client system for my game now.
This is the code of the method that waits for data to be sent to it:
while (handler.isRunning()) {
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
try {
socket.receive(packet);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Server - " + new String(data).trim());
}
socket.close();
So, the thing is, when the game closes meaning that isRunning() gets set to false, all threads die except the server and client. The reason is because here, socket.receive() method blocks and it needs to receive at least one more packet to then check if isRunning() is true and exit. So after I close the game, I want this thread to die immediately without receiving anymore packets, but i dont know how to do that!
Thanks for help
There's a couple of options. First, the simplest option is to set a timeout: https://docs.oracle.com/javase/7/docs/api/java/net/DatagramSocket.html#setSoTimeout(int).
Next, another option is to use callbacks and Async I/O. Take a look at java.nio.channels.DatagramChannel
Answered here. Similar for your case for DatagramSocket.receive
I wonder how to handle exceptions correctly within a client server application. My client sends an information to the server(thread) which receives it within its run method.
I have already read something about uncaught exception handling when dealing with exceptions in the run method but want to know if this is the correct way to do it in my case.
I want to catch the exception on the client side.
I have in mind to do the following:
//Server
run(){
try{
...
}
catch(Exception e){
clientoutputstream.write(...); //transmitting the error
}
}
Any other suggestions?
You should put a try { } catch (IOException) around your read() call so you know if the other end has closed the connection. The other thing you might want to do is to put a try { } catch(Throwable) { } around the processing code so you can manually close the socket (Be very careful about catching Throwable) But if you just let the thread die the Socket will be closed when the object is garbage collected or when it times out
For years I've been wondering what the correct way to close a listening ServerSocket in Java is. My implementations always work like this, they:
Create a new ServerSocket(int).
Start a thread that calls its accept() method in a while (true) loop.
Start another thread when accept() returns (client connects) that reads from the client until it disconnects. The accept thread then continues with another accept() call.
But when I want to close the ServerSocket because my application is exiting, I've never found another way of doing so other than calling it's close() method (after I've closed all client Sockets), which causes accept() to throw a SocketException, I catch that and break from the while (true) loop in the accept thread, causing all my threads to exit.
I think this is ugly, strictly speaking there is no exception occurring, closing my ServerSocket is part of my programs normal operation.
Is there really no other way of doing this without causing an Exception to be thrown?
Thanks.
I've never found another way of doing so other than calling it's close() method (after I've closed all client Sockets),
You can set a flag closed = true; and open a dummy connection to wake up the accept()ing thread which checks the flag before continuing.
which causes accept() to throw a SocketException,
A SocketClosedException which is expected behaviour here.
I catch that and break from the while (true) loop in the accept thread,
If you catch it outside the loop, you don't need to also break out of the loop. If the exception is thrown and you have set closed = true you can discard the exception.
BTW I would do
while(!serverSocket.isClosed()) {
causing all my threads to exit.
There is no particular reason you need to have this, but you can choose to do this if you want.
I think this is ugly, strictly speaking there is no exception occurring,
An exceptional condition is happening. What is not happening is an Error.
closing my ServerSocket is part of my programs normal operation.
Or you could say it is operating normally when it is running and not shutting down.
Thanks for your comment.
You can set a flag closed = true; and open a dummy connection to wake up the accept()ing thread which checks the flag before continuing.
Opening a new Socket to close an existing one? IMO that is one of the worst sins ever.
A SocketClosedException which is expected behaviour here.
Actually it doesn't throw a SocketClosedException but a SocketException, the following code:
try {
final ServerSocket ss = new ServerSocket(1234);
new Thread(new Runnable() {
#Override
public void run() {
try {
ss.accept();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
ss.close();
} catch (Exception ex) {
ex.printStackTrace();
}
Produced the following output:
java.net.SocketException: Socket is closed
at java.net.ServerSocket.accept(ServerSocket.java:494)
at Main$1.run(Main.java:12)
at java.lang.Thread.run(Thread.java:744)
If you catch it outside the loop, you don't need to also break out of the loop. If the exception is thrown and you have set closed = true you can discard the exception.
BTW I would do
while(!serverSocket.isClosed()) {
That would work, but I think this should work without setting flags and catching Exceptions.
An exceptional condition is happening. What is not happening is an Error.
Or you could say it is operating normally when it is running and not shutting down.
I don't agree. It is normal behaviour for applications to be exiting. They may always do so.
Why doesn't the accept() method just returns null when close() is called? That would be so much easier.
In most Java client/server examles they use ServerSocket.accept() method to receive messages from the client. This method blocks the thread. This looks good becouse server does not do useless work and can answer immediately. But on the client side they use infinite loop like this:
BufferedReader in = new BufferedReader (new InputStreamReader (socket.getInputStream ()));
while (true)
{
String cominginText = "";
try
{
cominginText = in.readLine ();
System.out.println (cominginText);
}
catch (IOException e)
{
//error ("System: " + "Connection to server lost!");
System.exit (1);
break;
}
}
This looks bad because in my mind client does useless work.
Is there some way to receive a message on the client side without doing useless work and immediately like on server side (may be should use listeners?)
"What do you mean by useless work? – Braj 31 mins ago "
for example checking in loop is button pressed (we should use listener)
while (!button.isPressed() ) { } is bad way.
There is no 'useless work' here, as the socket is in blocking mode, but there is:
A pointless initialization of 'comingText'.
A failure to check it for null, so it will spin mindlessly at EOS.
An incorrect handling of IOExceptions: not all of them are fatal, e.g. SocketTimeoutException, and none of them should cause an immediate System.exit().
The line read is thrown away, which is an application protocol error.
So it is definitely wrong.
in.readLine() blocks. The loop wont continue until a String returns
I have a server with many clients.. Every connection arrives to the server
if it's accepted, I send it to a thread:
server= serverSocketcht.accept();
new ThrdConv(server).start();
in the ThrdConv thread I set the input stream and output stream to this new conection
this.OOS=new ObjectOutputStream(server.getOutputStream());
this.OIS=new ObjectInputStream(server.getInputStream());
then I store the arrived connection, (lets call it new client) in a list of clients:
if(isLogged){ // if success login!
thsisUser= new Clientuser(server,OOS,OIS,Omsg.my_gender,Omsg.userID);
boolean IsAdded= EIQserver.OnlineusersList.add(this.thsisUser);
everything works fine and the Clients can send messages and chat with other clients...
The problem is when a client leaves, I get this Exception :
SEVERE: null
java.io.EOFException
at
java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2571)
here is my Leave function:
Iterator<Clientuser> iterator = EIQserver.OnlineusersList.iterator();
if(EIQserver.OnlineusersList.size()>=1)
Omsg.type= MessageType.Leave;
sendMessage(OLeavemsg); // tell the partner that I am leaving...
while (iterator.hasNext()) {
Clientuser next = iterator.next();
if (next.ID.equals(OLeavemsg.userID))
{
next.ClientPort.shutdownInput(); // ClientPort is a socket of this Client
next.ClientPort.shutdownOutput();
iterator.remove();// remove the partner
}
break;
}
// end leave////////////////////////////////////////////////
The connection is removed from the list, but the above exception stops the Server...
help me get rid of this complex problem
You should close this.OOS and this.OIS. They will close inner streams recursively. in you current case outer streams fail because client is closed first. You can examine Object*Stream, their close method close inner stream too.
thank you Mikhail, your answer was the key of the solution.
And for the other readers,I will Describe how did I solve this:
first I closed the OOS,OIS... as you advice..
secondly I stop the thread..
How do I stop the thread? :
I declared new boolean variable named "Running" and set the condition for the main loop of the thread to while(running)
and when I want to stop the main loop of the thread I set running=false
this stop the the use of the closed streams!!
You shutdown the input, you got EOFException when reading the input. That's exactly what's supposed to happen. You have to catch EOFException anyway when reading an ObjectInputStream. There is no 'complex problem' here at all. Just poor exception handling.