Detecting when a client has disconnected from my server [duplicate] - java

This question already has answers here:
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 5 years ago.
I'm trying to find a way to see when a client that is connected to my server has disconnected. The general structure of my code is like this, I have omitted irrelevant sections of my code:
public class Server {
public static void main(String[] args) {
...
try {
ServerSocket socket = new ServerSocket(port);
while (true) {
// wait for connection
Socket connection = socket.accept();
// create client socket and start
Clients c = new Server().new Clients(connection);
c.start();
System.out.printf("A client with IP %s has connected.\n",c.ip.substring(1) );
}
} catch (IOException exception) {
System.out.println("Error: " + exception);
}
}
class Clients extends Thread {
...
public Clients(Socket socket) {
clientSocket = socket;
ip=clientSocket.getRemoteSocketAddress().toString();
try {
client_in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
client_out = new PrintWriter(clientSocket.getOutputStream(), true);
} catch (IOException e) {
//error
}
}
public void run() {
...
try {
while (true) {
while ((message = client_in.readLine()) != null) {
...
}
}
} catch (IOException exception) {
System.out.printf("Client with IP %s has disconnected.\n" , ip.substring(1));
}
}
}
}
Basically what I'm trying at the moment is detecting the disconnection through the catch statement in run(), but the issue with this is it doesn't display the message until I terminate my server.
I have also tried to put my print statement after the while(true) loop but my IDE tells me that code is unreachable.
Is there a way to get my "Client with IP %s has disconnected." to display as soon as the client connection is disconnected? What and where should I be checking?

what I'm trying to do is detecting the disconnection through the catch statement.
Bzzt. readLine() doesn't throw an exception at end of stream. It returns null. Any exception you catch here is an error, and should be reported as such.
while (true) {
while ((message = client_in.readLine()) != null) {
...
}
The problem is here. You are detecting when the peer disconnects: readLine() returns null and terminates the inner loop. However you have pointlessly enclosed the correct inner read loop in an outer while (true) loop, which by definition can never exit.
Remove the outer loop.

Related

HTTP1.1 Connection:keepalive implement with java occurs withjava.net.SocketTimeoutException: Read timed out

I'm implement a http server with version1.1 using java socket programming. I use a version 1.0 sample code and I want add the persistent connection feature by not closing socket utilt a "Connection : close" send to the server. However, I came accross with "java.net.SocketTimeoutException: Read timed out" info after an input like"localhost:8080/xxxx" on my browser and not receiving anything when tested with a client program. Code is too long, and I mention the matter parts bellow! Can you find the problems for me, thanks!!!
////////here is the server part using thread pool techs
//Webserver class
protected static Properties props = new Properties();
/* Where worker threads stand idle */
static Vector threads = new Vector();
public static void main(String[] a) throws Exception {
int port = 8080;
if (a.length > 0) {
port = Integer.parseInt(a[0]);
}
loadProps();
printProps();
/* start worker threads */
for (int i = 0; i < workers; ++i) {
Worker w = new Worker();
(new Thread(w, "worker #"+i)).start();
threads.addElement(w);
}
ServerSocket ss = new ServerSocket(port);
while (true) {
Socket s = ss.accept();
Worker w = null;
synchronized (threads) {
if (threads.isEmpty()) {
Worker ws = new Worker();
ws.setSocket(s);
(new Thread(ws, "additional worker")).start();
} else {
w = (Worker) threads.elementAt(0);
threads.removeElementAt(0);
w.setSocket(s);
}
}
}
}
//Worker class inherit from Webserver class
byte[] buf;
Worker() {
buf = new byte[BUF_SIZE];
s = null;
}
synchronized void setSocket(Socket s) {
this.s = s;
notify();
}
public synchronized void run() {
while(true) {
if (s == null) {
/* nothing to do */
try {
wait();
} catch (InterruptedException e) {
/* should not happen */
continue;
}
}
try {
handleClient();
} catch (Exception e) {
e.printStackTrace();
}
/* go back in wait queue if there's fewer
* than numHandler connections.
*/
if(!headAttri.getPersistConnec())
s = null;
//
Vector pool = WebServer.threads;
synchronized (pool) {
if (pool.size() >= WebServer.workers) {
/* too many threads, exit this one */
try{
if(s != null)
s.close();
}catch (IOException e) {
e.printStackTrace();
}
return;
} else {
if(!headAttri.getPersistConnec())
pool.addElement(this);
}
}
}
}
//in handle client I mention the socket handles here(s is the socket)
void handleClient() throws IOException {
//...
s.setSoTimeout(WebServer.timeout);
s.setTcpNoDelay(true);
//...
try{
//...handle request and response the client
//...
}finally{
//close socket if head info "Connection: close" is found
if(headAttri.getPersistConnec()){
s.setKeepAlive(true);
}
else{
s.close();
}
}
}
//////////end server part
//////here is the client part
public SimpleSocketClient()
{
String testServerName = "localhost";
int port = 8080;
try
{
// open a socket
Socket socket = openSocket(testServerName, port);
// write-to, and read-from the socket.
// in this case just write a simple command to a web server.
String result = writeToAndReadFromSocket(socket, request_str[1]);
// print out the result we got back from the server
System.out.println(result);
// close the socket, and we're done
socket.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
private Socket openSocket(String server, int port) throws Exception
{
Socket socket;
// create a socket with a timeout
try
{
InetAddress inteAddress = InetAddress.getByName(server);
SocketAddress socketAddress = new InetSocketAddress(inteAddress, port);
// create a socket
socket = new Socket();
// this method will block no more than timeout ms.
int timeoutInMs = 10*1000; // 10 seconds
socket.connect(socketAddress, timeoutInMs);
return socket;
}
catch (SocketTimeoutException ste)
{
System.err.println("Timed out waiting for the socket.");
ste.printStackTrace();
throw ste;
}
}
private String writeToAndReadFromSocket(Socket socket, String writeTo) throws Exception
{
try
{
// write text to the socket
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter.write(writeTo);
bufferedWriter.flush();
//test
//bufferedWriter.write("GET src/WebServer.java HTTP/1.1\r\nHost: localhost\r\nConnection: close");
//bufferedWriter.flush();
// read text from the socket
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
StringBuilder sb = new StringBuilder();
//string handling code
String str;
while ((str = bufferedReader.readLine()) != null)
{
sb.append(str + "\n");
}
// close the reader, and return the results as a String
bufferedReader.close();
return sb.toString();
}
catch (IOException e)
{
e.printStackTrace();
throw e;
}
}
////end client part
//close socket if head info "Connection: close" is found
if(headAttri.getPersistConnec()){
s.setKeepAlive(true);
It is hard to tell from your code what you are really doing but based on this code fragment it looks like you are mixing up HTTP keep alive (i.e. Connection: keep-alive handling, multiple requests in a single TCP connection) with TCP keep alive (detect broken TCP connection). See Relation between HTTP Keep Alive duration and TCP timeout duration and HTTP Keep Alive and TCP keep alive for explanations about the difference.
I want add the persistent connection feature by not closing socket utilt a "Connection : close" send to the server
That's not how you do it. You have to close the connection yourself, either
after a request with a Connection: close header is received and you've sent the response, or
when you get a read timeout on the socket reading the next request.
The length of the read timeout is entirely up to you, because it is up to you to protect yourself from DOS attacks among other things.
NB calling Socket.setKeepAlive(true) has absolutely nothing whatsoever to do with it.
NB 2 You should look into java.util.concurrent.Executor rather than implement your own thread pool.

Why is this message getting sent to the wrong client? (Deduping)

I have a chat program. The problem is that I am trying to disallow dupe names. Essentially, whenever a name change request is sent to the server, it is checked against the list of names currently in use and if it is already taken, the person is added to my shitlist (not allowed to post) and they are sent a message that they need to change their name.
I commented the crap out of the code since there is a lot so you can understand it easily.
The problem is that the wrong person is being sent the message that the name is already in use! I have spent the last 8 hours trying to find it and It's bloody driving me mad!
The server side code is long; I'll post the relevant bits and any further will be provided on request. I'll also link to the complete program. (Not the source, the JAR.)
JAR: https://www.mediafire.com/?4t2shjdjf7blpg2
//...Irrelevant bits ommitted...//
public class Server
{
// The server object reference
static Server server;
// Declarations:
private ArrayList<ObjectOutputStream> clientOutputStreams; // out streams
private ArrayList<String> takenNames = new ArrayList<>(); // taken names
private InetAddress ip;
private final int serverPort; // the port the server is running on
private static ObjectOutputStream changer; // the last person to change names
private ArrayList<ObjectOutputStream> shitList = new ArrayList<>();
private HashMap <InetAddress, ObjectOutputStream> ipMap =
new HashMap<>(); // <ip, outputstream>
//...Irrelevant bits ommited...//
// Don't mind this non-indentation, it is supposed to be.
public void tellEveryone(Message message, InetAddress senderIP)
{
// First check some special conditions..
if(message.getType() == Message.TYPE.IN_USE)
{
try
{
changer.writeObject(message);
}
catch (IOException e)
{
e.printStackTrace();
}
}
// If someone is on my shitlist,
if(shitList.contains(ipMap.get(senderIP)))
{
// Warn them of their sins...
Message nopeMessage = new Message(Message.TYPE.SERVER,
"You may not send any messages until you change your name!",
"Server");
try
{
ipMap.get(senderIP).writeObject(nopeMessage);
}
catch(IOException e)
{
e.printStackTrace();
}
}
else
{
// Send message normally to everyone...
// Sync, just to be safe
synchronized(clientOutputStreams)
{
for(ObjectOutputStream oo : clientOutputStreams) // while more clients...
{
try
{
oo.writeObject(message);
oo.flush();
}
catch(IOException e)
{
System.out.println("IOException caught during tellEveryone()");
e.printStackTrace();
}
}
}
System.out.println(getTimeStamp() + ": Message Sent by:".
concat(" " + senderIP + "/ " + message.getSenderName()));
}
}
The server handler inner class...
public class ServerHandler implements Runnable
{
#Override
public void run()
{
// Create a list of client out streams to send stuff...
clientOutputStreams = new ArrayList<>();
try // To establish a connection with clients
{
// Create server socket...
ServerSocket serverSocket = new ServerSocket(serverPort);
while(true) // Will always run! Blocks!
{
// Assign a client socket to any new socket connections...
// (The var used here is temp, but will be passed off soon.)
Socket clientSocket = serverSocket.accept();
// Get's the ip of the client that connected...
ip = clientSocket.getInetAddress();
System.out.println(ip + " " + "connected.");
// Create ooStream to send messages to client...
ObjectOutputStream ooStream =
new ObjectOutputStream(
clientSocket.getOutputStream());
// Add the client oo stream to the list of outputs...
clientOutputStreams.add(ooStream);
// Add user IP data to map of ip's
ipMap.putIfAbsent(ip, ooStream);
// Create new thread to run inner class ClientHandler...
Thread t = new Thread(new ClientHandler(clientSocket));
// Running the thread makes it safe to overwrite the...
// ...clientsocket variable.
t.start();
}
}
catch (IOException e)
{
System.out.println("Exception in server.run()");
// TODO: Revise
e.printStackTrace();
}
}
}
The client handler inner class
public class ClientHandler implements Runnable
{
private ObjectInputStream oInStream; // The client's input stream.
private Socket socket; // Socket to the client
public ClientHandler(Socket clientSocket)
{
try // to create an input stream...
{
socket = clientSocket; // <-- The one passed in to the method
// Potential error from previous version... REMOVE WHEN TESTED
oInStream = new ObjectInputStream(socket.getInputStream());
}
catch(IOException e)
{
System.out.println("Error establishing input stream");
}
}
#Override
public void run()
{
Message message;
try // To process incoming messages...
{
while(socket.isClosed() == false) // If the socket is open...
{
// While there are more messages...
// Also assigns to the message var.
while((message = (Message)oInStream.readObject()) != null)
{
// Passes on the message and sender info.
if(message.getType() == Message.TYPE.NAME_REQUEST)
{
changer = ipMap.get(socket.getInetAddress());
System.out.println(socket.getInetAddress());
System.out.println(changer.toString());
handleNameRequests(message);
}
else
{
tellEveryone(message, ip); // TEST CHANGE- DELETED IF TEST
}
}
// TEST TEST TEST
synchronized(clientOutputStreams)
{
int index =
clientOutputStreams.indexOf(
socket.getOutputStream());
clientOutputStreams.remove(index);
System.out.println("Removed the client in sync");
}
}
// TEST TEST TEST
socket.close(); // TEST CLOSING SOCKET WHEN DONE.
System.out.println("Sock closed after while loop in ch run()");
}
catch(IOException e)
{
System.out.println("IOException caught when "
+ "reading message.");
}
catch (ClassNotFoundException e)
{
System.out.println("Some poor sap is going to have to debug"
+ "this!");
}
finally
{
// THIS WHOLE BLOCK: TEST TEST TEST
try
{
oInStream.close();
System.out.println("just closed oinStream");
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
I FINALLY FOUND IT!
For any future people encountering a similar problem, the problem was that I was assigning the ip variable in the wrong place! This essentially resulted in the list of ip's being all the same! Another bug confounded that problem, in that when I disabled the sending ability of messages when on my shitlist (aren't programmers the darndest?), I disabled ALL types of messages, including those from the server, ect! Oops!
The lesson? Bugs hide in the darndest places. Walk through everything, and doubt what you know to be true. Assume nothing, verify everything. There are never enough print statements when debugging!

Handling sockets in java

I am creating a socket to a server in java and after the socket is connected it creates a new thread which can access the socket input and output stream and this thread then blocks and processes the input lines when they come in.
I understand that the readln method on the BufferedReader will return null when the input stream ends. This doesn't necessarily mean that the socket is closed though does it? What does this mean? So I would then want to run the close method on the socket to close it nicely.
I also understand that the readln method can throw an IOException and that this is thrown after the close method is called on a socket if it is currently blocking. When else can this be thrown? Could the socket still be open after this is thrown or would it always be closed and ready for garbage collection etc.
This is the code I have at the moment and I don't really know how to handle disconnects properly. At the moment I think this could end up in a deadlock if the disconnect method is called whilst the socket is waiting for a line because disconnect will call close on the socket. This will then throw the IOException on readLine and this will then result in that catch block calling disconnect again.
public class SocketManager {
private Socket socket = null;
private PrintWriter out = null;
private BufferedReader in = null;
private String ip;
private int port;
private Object socketLock = new Object();
public SocketManager(String ip, int port) {
this.ip = ip;
this.port = port;
}
public void connect() throws UnableToConnectException, AlreadyConnectedException {
synchronized(socketLock) {
if (socket == null || socket.isClosed()) {
throw (new AlreadyConnectedException());
}
try {
socket = new Socket(ip, port);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
throw (new UnableToConnectException());
}
new Thread(new SocketThread()).start();
}
}
public void disconnect() throws NotConnectedException {
synchronized(socketLock) {
if (isConnected()) {
throw (new NotConnectedException());
}
try {
socket.close();
} catch (IOException e) {}
}
}
public boolean isConnected() {
synchronized(socketLock) {
return (socket != null && !socket.isClosed());
}
}
private class SocketThread implements Runnable {
#Override
public void run() {
String inputLine = null;
try {
while((inputLine = in.readLine()) != null) {
// do stuff
}
if (isConnected()) {
try {
disconnect();
} catch (NotConnectedException e) {}
}
} catch (IOException e) {
// try and disconnect (if not already disconnected) and end thread
if (isConnected()) {
try {
disconnect();
} catch (NotConnectedException e1) {}
}
}
}
}
}
I basically want to know the best way of achieving the following:
Writing a connect method that connects to a socket and starts a separate thread listening for input.
Writing a disconnect method that disconnects from the socket and terminates the thread that's listening for input.
Handling the scenario of the connection to the remote socket being broken.
I have read through the java tutorial on sockets but in my opinion it doesn't really cover these in much detail.
Thanks!
When I said that it could end up as a deadlock I think I was wrong.
What would happen is:
disconnect() called whilst in.readLine() blocking
socket.close() executed.
in.readline() throws IOException.
I was then thinking that the exception handler in the SocketThread would call disconnect whilst disconnect is waiting for that exception to finish. It wouldn't matter through because they are both different threads so the code in disconnect() would continue whilst the exception is being caught in the SocketThread. The SocketThread would then call disconnect() but would then have to wait until the first instance of disconnect() finished. Then disconnect() would execute again but would get the NotConnectedException thrown which would be caught in the SocketThread and nothing would happen. The SocketThread would exit and that's the wanted result.
However I have looked into the socket class and it also contains these methods:
shutdownInput()
shutdownOutput()
shutdownInput() sends the end EOF symbol into the input stream meaning in.readline() returns null and the loop exits cleanly. shutdownOutput() sends the TCP termination sequence informing the server that it's disconnecting.
Calling both of these before socket.close() makes more sense because it means the thread will exit nicely instead of exiting as a result of an exception being thrown which has more overhead.
So this is the modified code:
public class SocketManager {
private Socket socket = null;
private PrintWriter out = null;
private BufferedReader in = null;
private String ip;
private int port;
private Object socketLock = new Object();
public SocketManager(String ip, int port) {
this.ip = ip;
this.port = port;
}
public void connect() throws UnableToConnectException, AlreadyConnectedException {
synchronized(socketLock) {
if (socket == null || socket.isClosed()) {
throw (new AlreadyConnectedException());
}
try {
socket = new Socket(ip, port);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
throw (new UnableToConnectException());
}
new Thread(new SocketThread()).start();
}
}
public void disconnect() throws NotConnectedException {
synchronized(socketLock) {
if (isConnected()) {
throw (new NotConnectedException());
}
try {
socket.shutdownInput();
} catch (IOException e) {}
try {
socket.shutdownOutput();
} catch (IOException e) {}
try {
socket.close();
} catch (IOException e) {}
}
}
public boolean isConnected() {
synchronized(socketLock) {
return (socket != null && !socket.isClosed());
}
}
private class SocketThread implements Runnable {
#Override
public void run() {
String inputLine = null;
try {
while((inputLine = in.readLine()) != null) {
// do stuff (probably in another thread)
}
// it will get here if socket.shutdownInput() has been called (in disconnect)
// or possibly when the server disconnects the clients
// if it is here as a result of socket.shutdownInput() in disconnect()
// then isConnected() will block until disconnect() finishes.
// then isConnected() will return false and the thread will terminate.
// if it ended up here because the server disconnected the client then
// isConnected() won't block and return true meaning that disconnect()
// will be called and the socket will be completely closed
if (isConnected()) {
try {
disconnect();
} catch (NotConnectedException e) {}
}
} catch (IOException e) {
// try and disconnect (if not already disconnected) and end thread
if (isConnected()) {
try {
disconnect();
} catch (NotConnectedException e1) {}
}
}
}
}
}
In order to be sure that all resources associated with the socket are relased you have to call close() method when you finish work with that socket.
Typical IO exception handling pattern is that you catch it and then perform best efforts to clean everything calling close() method.
So the only thing you have to do is to ensure that you call close() on every socket during it's lifetime.
You're on the right track. I wouldn't use "readline", only raw read, and "do stuff"
should be limited to constructing a queue of received data. Likewise writing replies
ought to be a separate thread that empties a queue of data to be sent.
Despite socket's guarantees of integrity, stuff will go wrong and you'll sometimes receive data that doesn't make sense. There's a crapload of stuff below "read" and "write" and no system is perfect or bug free. Add your own wrapper with checksums at the level of YOUR read and write so you can be sure you're receiving what was intended to be sent.

ServerSocket java-server reads input only once?

I have written a java server and here is the code:
try
{
ss = new ServerSocket(8080);
while (true)
{
socket = ss.accept();
System.out.println("Acess given");
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//out = new PrintWriter(socket.getOutputStream(),true);
line = in.readLine();
System.out.println("you input is :" + in.readLine());
}
}
And an iphone application is the client and there is the code for it:
- (void)viewDidLoad {
[super viewDidLoad];
socket = [[LXSocket alloc]init];
if ([socket connect:#"10.211.55.2" port:8080]) {
NSLog(#"socket has been created");
}
else {
NSLog(#"socket couldn't be created created");
}
#try {
}#catch (NSException * e) {
NSLog(#"Unable to send data");
}
[super viewDidLoad];
}
-(IBAction)sendData{
[socket sendString:#"A\n"];
}
I am having 2 problems here: first is that the server is only reading the input once. The second is that when ever I try to output the data it doesn't output until I have called the method twice (clicked on the uibutton twice). Not sure what is happening here. What am I doing wrong?
You are creating a new reader everytime in your while loop. Instead move the code outside the while loop and block on the readLine() call.
socket = ss.accept();
in = new BufferedReader(new InputStreamReader(socket.getInputStream());
String line = "";
while ( true) {
line = in.readLine();
System.out.println("you input is :" + line);
if ( "Bye".equals(line) )
break;
}
Here is an example server side program.
Since alphazero posted the pattern, I will post a brief stripped down implementation:
This is the Server:
try {
ServerSocket ss = new ServerSocket(portNumber);
logger.info("Server successfully started on port " + portNumber);
// infinite loop that waits for connections
while (true) {
SocketThread rst = new SocketThread(ss.accept());
rst.start();
}
} catch (IOException e) {
logger.info("Error: unable to bind to port " + portNumber);
System.exit(-1);
}
The SocketThread is something like:
public class SocketThread extends Thread {
private Socket communicationSocket = null;
public SocketThread(Socket clientSocket) {
communicationSocket = clientSocket;
try {
input = new ObjectInputStream(communicationSocket.getInputStream());
} catch (IOException e) {
logger.info("Error getting communication streams to transfer data.");
try {
communicationSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
public void run() {
boolean listening=true;
DataObject command = null;
while (listening) {
try {
Object currentObject = input.readObject();
if (currentObject != null
&& currentObject instanceof DataObject) {
command = (DataObject) currentObject;
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
// If we got to this point is because we received a request from
// the client
// we can exit the loop
listening = false;
}
}
}
}
Note: "DataObject" is just a custom class which could be more practical since you can read the Dataobject itself from the socket without worrying about how many bytes you are reading, etc. Only condition is that DataObject is flagged as Serializable.
Hope it helps.
Tushar,
The general pattern is this (almost java but pseudo-code):
while (server-socket is accepting new connections)
{
// The server-socket's job is to listen for connection requests
// It does this typically in a loop (until you issue server-shutdown)
// on accept the server-socket returns a Socket to the newly connected client
//
socket s = server-socket.accept-connection();
// various options here:
//
// typically fire off a dedicated thread to servie this client
// but also review NIO or (home-grown) connection-map/handler patterns
// the general pattern:
// create a dedicated thread per connection accepted.
// pass Socket (s) to the handler method (a Runnable) and start it off
// and that is it.
// Here we use the general pattern and create a dedicated
// handler thread and pass of the new connections' socket reference
//
Thread handler-thread = new Thread (handler-routine-as-runnable, s);
handler-thread.start();
}

java socket server, client detect server has died

If I kill the Socket Server process, my Socket client process does not receive any errors, it continues to loop forever on the following code:
public void run() {
while(readData) {
String inputLine = null;
try {
while((inputLine = m_inputStream.readLine()) != null) {
//do stuff
}
} catch (IOException e) {
readData = false;
}
}
}
How can I detect that the socket server is gone and terminate the loop?
Terminate the outer loop when the call to readLine() returns null.
No exception is thrown when the server closes the connection normally. The stream should return null to signal the end of data.
This can be done with a loop like this:
public void run() {
try {
while (true) {
String line = input.readLine();
if (line == null)
break;
/* Process line. */
...
}
} catch (IOException ex) {
/* Handle the exception as desired. */
ex.printStackTrace();
}
}
Whilst the answer from erickson is correct, have you tried setting the socket read time-out properties? (e.g. sun.net.client.defaultReadTimeout). If it is possible that the server may take a long time responding, then this might be less useful as a solution to your problem but is a good idea nevertheless in many scenarios.

Categories