I want to create a Java Server program that stops after 10 seconds.Right now, I am using setSoTimeout method. Once the time expires, I catch the exception and generate a Server Closing Message.
But that seems to be a workaround. Is there a better way to do it?
public class DailyAdviceServer
{
String[] adviceList = {"Take smaller bites", "Go for the tight jeans. No they do NOT make you look fat",
"One word: inappropriate", "Just for today, be honest. Tell your boss what you *really* think",
"You might want to rethink that haircut"};
public void startserver() {
try {
#SuppressWarnings("resource")
ServerSocket serverSock = new ServerSocket(2727);
serverSock.setSoTimeout(10000);
while (true)
{
Socket sock = serverSock.accept();
OutputStreamWriter streamwriter = new OutputStreamWriter(sock.getOutputStream());
BufferedWriter writer=new BufferedWriter(streamwriter);
String advice = getAdvice();
writer.write(advice);
writer.close();
}
} catch (SocketTimeoutException ex)
{
System.out.println("The Server has now shut down.");
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
private String getAdvice() {
int random = (int) (Math.random() * adviceList.length);
return adviceList[random];
}
public static void main(String[] args)
{
DailyAdviceServer server = new DailyAdviceServer();
server.startserver();
}
}
You can start a timer after the creation of the ServerSocket and when the timer expires you can close it
Related
I have created a server-client project where the server keeps listening and prints the information. However, when i shutdown the client, the server remains open. The problem is that I need to insert this into another application, and, if the server does not close at first, the application will not open unless i kill the process in that port (but this is not an option to me). What should I do to properly close the server once the client disconnects?
Here is the code:
Server:
public class Server {
public static void main(String[] args) {
Connection conn = new Connection();
new Thread(conn).start();
}
private static class Connection implements Runnable {
#Override
public void run() {
try (ServerSocket serverSocket = new ServerSocket(5005)) {
Socket socket = serverSocket.accept();
listener(socket);
} catch (IOException ex) {
ex.printStackTrace();
}
}
private void listener(Socket socket) throws IOException {
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
boolean alive = true;
while (alive) {
try {
outputStream.writeUTF(new Scanner(System.in).nextLine());
System.out.println(inputStream.readUTF());
} catch (IOException ex) {
ex.printStackTrace();
alive = false;
}
}
}
}
}
Client:
public class Client {
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 5005)) {
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
while (socket.isConnected()) {
System.out.println("Incoming data: " + inputStream.readUTF());
outputStream.writeUTF(new Scanner(System.in).nextLine());
outputStream.flush();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Since now, thank you very much!
The thing that force the system wait and not close is this line at your Server.java :
outputStream.writeUTF(new Scanner(System.in).nextLine());
Once it starts waiting the user input, it waits forever along the life time of the instance although your client is disconnected.
So what you can do ? You can create another thread that makes periodic "ENTER" inputs (if you insist using new Scanner(System.in)) for example input per 5 seconds. After the enter, or any other meaningful input, if you decide this is not from your client, don't write it to the client and wait user input again (if your client still connected !). If your client is not connected, just finish your loop.
Please check Java Robot class and this example
(Disclaimer that some of this code will be similar to online tutorials)
I think I've made it so that my server can handle multiple requests at once using threads, but I'm not entirely sure. And on top of that I don't know how I would actually send multiple requests at once.
My goal is to run my client code multiple times in parallel to see what happens if multiple clients connect to the server at the same time.
Client code (in separate project package):
Client clientSocket = new Client(9990,"localhost");
Socket socket = new Socket(clientSocket.host,clientSocket.portNumber);
clientSocket.performTask(socket);
("performTask(socket)" sends data to the server to perform a task)
Server code (separate project package from client code):
Server server = new Server(9990);
int clientNumber = 0;
ServerSocket socket = new ServerSocket(server.portNumber);
try {
while (true) {
new ServerHandler(socket.accept(),clientNumber).go();
clientNumber++;
}
}
finally {
socket.close();
}
}
ServerHandler class (same project package as server code):
public class ServerHandler extends Thread {
private static Socket socket;
private static int clientNumber;
public ServerHandler(Socket socket, int clientNumber) {
ServerHandler.socket = socket;
ServerHandler.clientNumber = clientNumber;
}
public void go() {
while(true) {
try {
//do calculation, do server tasks, etc.
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
So when the client connects to the server, the server implements the ServerHandler class to do the necessary calculations: the idea in doing that was so that multiple clients could connect all at the same time.
So my question is then in two parts:
(1) Have I set up my programs to allow for multi-threading, or have I made a mistake somewhere along the way? (e.g. someone told me I needed to use "Runnable" somewhere to use multi-threading, and I notice I haven't)
(2) After fixing my code to allow for multi-threading, how would I actually use it to let me run my client code in parallel?
Ok for starters, your ServerHandler extends the Thread class. Therefore to make it run as a seperate thread, always invoke by calling the start() method. You are calling you custom go method which will make the ServerHandler execute in the same thread as your infinite while loop. So it should be something like this ServerHandler(socket.accept(),clientNumber).start(). Also it is always better to implement Runnable because java does not support multiple inheritance via the "extends" concept. Therefore in the future if your ServerHandler needs to actually extend a custom class, it wont be able to since it already extends the Thread class. Its better to implement interfaces since there is no limit as to how many you can implement.
Hence implementing the Runnable interface is a good design choice. You can run your client code in parallel by making the client into a threaded model. Here is one such example of multiple client sockets connecting to the server in parallel
Server Code
public class WebServer {
static int hitCount = 0;
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(7777, 10000);
while (true) {
Socket defaultSocket = serverSocket.accept();
new Thread(new ServerSlave(defaultSocket)).start();
System.out.println("Size is :" + hitCount);
}
}
}
class ServerSlave implements Runnable {
Socket clientSocket;
public ServerSlave(Socket socket) {
clientSocket = socket;
WebServer.hitCount++;
}
public void run() {
try {
DataInputStream inputStream = new DataInputStream(clientSocket.getInputStream());
DataOutputStream outputStream = new DataOutputStream(clientSocket.getOutputStream());
System.out.println(inputStream.readUTF());
outputStream.writeUTF("Thank you for contacting the web server");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Client Code :
public class Client {
static int excepCount=0;
public static void main(String[] args) throws Exception {
for (int i = 0; i < 100; i++) {
new Thread(new Worker("" + i)).start();
}
Thread.sleep(10000);
System.out.println( Client.excepCount);
}
}
class Worker implements Runnable {
String clientName;
public Worker(String name) {
clientName = name;
}
public void run() {
System.out.println("Process started for : " + clientName);
Socket socket = null;
try {
socket = new Socket("127.0.0.1", 7777);
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
outputStream.writeUTF("Hello socket. Client number " + clientName + "here");
InputStream inFromServer = socket.getInputStream();
DataInputStream in =
new DataInputStream(inFromServer);
System.out.println("Server says " + in.readUTF());
System.out.println("Closing socket");
} catch (IOException e) {
Client.excepCount++;
e.printStackTrace();
}finally{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
You should use multithreading .
You have to rename method to "run"/ and call that method using "start".Please change Server side code to
try {
while (true) {
new ServerHandler(socket.accept(),clientNumber).start();
clientNumber++;
}
}
finally {
socket.close();
}
and client side
public class ServerHandler extends Thread {
private static Socket socket;
private static int clientNumber;
public ServerHandler(Socket socket, int clientNumber) {
ServerHandler.socket = socket;
ServerHandler.clientNumber = clientNumber;
}
public void run() {
while(true) {
try {
//do calculation, do server tasks, etc.
}
} catch (IOException e) {
e.printStackTrace();
}
}
Here's the code for server side :
public class EchoServer {
public static void main(String[] args) {
int port = 8080;
try {
ServerSocket server = new ServerSocket(port);
Socket cliSocket = server.accept();
Scanner in = new Scanner(cliSocket.getInputStream());
PrintWriter write = new PrintWriter(cliSocket.getOutputStream(),true);
String message;
while((message=in.nextLine()) != null){
write.println(message+" added");
}
write.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
and here's the client side :
public class EchoClient {
public static void main(String[] args) {
String ip = "localhost";
int port = 8080;
try {
Socket client = new Socket(ip, port);
PrintWriter write = new PrintWriter(client.getOutputStream(), true);
Scanner in = new Scanner(client.getInputStream());
Scanner read = new Scanner(System.in);
String input;
while((input=read.nextLine()) != null){
write.println(input);
System.out.println("sent by server:" + in.nextLine());
}
write.close();
in.close();
read.close();
client.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Now when I run the server and then the client, it works. But if close the client app, and i run it once again, the server won't allow connection.
What is the solution in situations like this?
Your server program only accepts one client connection and exits after handling the connection.
If you want it to repeatedly accept client connections, you need to use a loop around the code you have in main()
The easiest solution is that every time you accept a connection, you launch a new thread to handle the client. That would allow you to handle any number of clients, and also deal with general TCP issues like sockets that are stuck open when clients are killed.
Something like this:
public class EchoServer {
public static void main(String[] args) {
int port = 8080;
ServerSocket server = new ServerSocket(port);
while (true) {
//wait for next client to connect
Socket cliSocket = server.accept();
//hand off socket to another thread
MyHandler handler = new MyHandler(cliSocket);
Thread clientHandler = new Thread(handler);
clientHandler.start();
}
}
}
public class MyHandler implements Runnable {
public MyHandler(Socket cliSocket)
{
//store socket
}
#override
public void run()
{
while(true) {
//handle client comms
}
}
}
I have written a Java Chat Server program.
This is a simple standalone program for Server.
I have to run this then run Client to get Chat working.
What are some possible Unit Test scenarios for the server program? Can anyone show me some example of unit test based on this code?
I have never written a unit test code before and I can't really think of what needs to be tested here.. I think testing Connection can be one but what else? (and how to?)
public class SimpleChatServer {
static final Logger logger = LogManager.getLogger(SimpleChatServer.class);
ArrayList<PrintWriter> clientOutputStreams;
private BufferedReader reader;
private Socket sock;
private ServerSocket serverSock;
public class ClientHandler implements Runnable{
public ClientHandler(Socket clientSocket){ // Socket Connection
try {
sock = clientSocket;
InputStreamReader isReader = new InputStreamReader(sock.getInputStream());
reader = new BufferedReader(isReader);
} catch(Exception ex) {
logger.trace(ex);
}
}
public void run() {
String message;
try {
while ((message = reader.readLine()) != null) {
System.out.println("read " + message);
tellEveryone(message);
}
} catch(Exception ex) {
logger.trace(ex);
}
} //close run
} //close ClientHandler
public static void main (String[] args) throws Exception
{
new SimpleChatServer().listen();
}
#SuppressWarnings("resource")
public void listen()
{
clientOutputStreams = new ArrayList<PrintWriter>();
try {
ServerSocket serverSock = new ServerSocket(8000); //port number 8000 was used
while(true) {
Socket clientSocket = serverSock.accept();
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream());
clientOutputStreams.add(writer);
Thread t = new Thread(new ClientHandler(clientSocket));
t.start();
}
} catch (Exception ex) {
logger.trace("Server Error", ex);
} finally {
try
{
serverSock.close();
}
catch(Exception e){}
}
} // close go
public void tellEveryone(String message)
{
Iterator<PrintWriter> it = clientOutputStreams.iterator();
while(it.hasNext()) {
try {
PrintWriter writer = (PrintWriter) it.next();
writer.println(message);
writer.flush();
} catch (Exception ex) {
logger.trace(ex);
}
} // end while
} // close tellEveryone
}
I was going to crib an answer from Pragmatic Unit Testing, but suggest you just find a copy. At the very least you should consider whether results are right, whether your boundary conditions are correct, and if you can force error conditions.
Testing results often means making sure combinations of input get the expected results. Boundaries are reflected in the related "0, 1, many" rule, where you do silly stuff to see if your code has implicit boundaries that can be reached with bad, null or unexpected values.
For example, what happens if you pass huge Strings to your methods that take them? What about strings with weird Unicode chars in them? No line breaks?
Forcing error conditions means making sure things degrade gracefully and/or throw under the expected situation.
Think about your code as a brittle little appliance and then pretend a poo-flinging monkey, a 14-yr old hacker and your non-hacker grandmother (I know some exist) are all taking turns on it.
I implemented simple server-client chat in Java. Here the source for the server:
public class Server {
final private static int PORT = 50000;
private static class Read extends Thread {
private static Socket socket;
private static String address;
public Read(Socket socket) {
this.socket = socket;
address = socket.getInetAddress().toString().substring(1);
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg;
while (true) {
msg = in.readLine();
if (msg == null) {
in.close();
return;
}
System.out.println(address + ": " + msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static class Write extends Thread {
private static Socket socket;
public Write(Socket socket) {
this.socket = socket;
}
public void run() {
try {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
String msg;
while (true) {
if (socket.isClosed()) {
out.close();
return;
}
if (stdin.ready()) {
msg = stdin.readLine();
out.println(msg);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
ServerSocket serverSocket;
boolean listening = true;
serverSocket = new ServerSocket(PORT);
while (listening) {
Socket socket = serverSocket.accept();
String address = socket.getInetAddress().toString().substring(1);
System.out.println("Connection Established " + address);
Thread read = new Read(socket);
Thread write = new Write(socket);
read.start();
write.start();
try {
read.join();
write.join();
} catch(InterruptedException e) {
}
socket.close();
System.out.println("Connection Closed " + address);
}
serverSocket.close();
}
}
It works fine but there is a problem. For every established connection the memory continuously grows. I presume the problem is that the memory allocated for the threads is not released afterwards but I'm not quite sure. How can I fix that?
EDIT: The client program:
class Client {
final private static int PORT = 50000;
private static class Read extends Thread {
private Socket socket;
private String address;
public Read(Socket socket) {
this.socket = socket;
address = socket.getInetAddress().toString().substring(1);
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg;
while (true) {
msg = in.readLine();
if (msg == null) {
System.out.println("Connection closed " + address);
System.exit(0);
}
System.out.println(address + ": " + msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static class Write extends Thread {
private Socket socket;
public Write(Socket socket) {
this.socket = socket;
}
public void run() {
try {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
Scanner sc = new Scanner(System.in);
String msg;
while (true) {
msg = sc.nextLine();
out.println(msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
PrintWriter out;
BufferedReader in;
Scanner sc = new Scanner(System.in);
while (true) { //for the test only
Socket socket = null;
try {
socket = new Socket("78.90.68.125", PORT);
} catch(java.net.ConnectException e) {
System.out.println("Connection error: host unreachable");
System.exit(1);
}
/*
String address = socket.getInetAddress().toString().substring(1);
System.out.println("Connection established " + address);
Thread read = new Read(socket);
Thread write = new Write(socket);
read.start();
write.start();
try {
read.join();
write.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
finally {
*/
socket.close();
// }
//System.out.println("Connection closed " + address);
}
}
}
Try making
private static class Read extends Thread {
private static Socket socket;
private static String address;
and
private static class Write extends Thread {
private static Socket socket;
to non-static.
Also, I dont know how you checking for memory, but do remember that Java is garbage collected and you will see increase in memory usage initially till the time garbage collector (GC) collects it and will increase again till next GC run. So it consistently increasing without any dip for long time only then there is a memory leak else you are good to go.
I ran the above code as is and ran for around 1-2 hours and it is steady memory usage of around 54MB on Mac machine using JDK 6. I am not using JConsole that comes with jdk to see mem usage. I found NO issues.
Below is the graph as I mentioned in my ans also, you have peak and dip ..in the end when I stopped client it is flat.
Ivan,
a few things to work with Threading.
Never do this:
try {
read.join();
write.join();
} catch(InterruptedException e) {
}
Always put something into the catch clause, and be it a log.error. You have no chance to know it occurs.
Then, all streams/closings etc must go into a finally block. Otherwise you cannever be sure to close everything necessary.
YOu might want to reuse connections. Try this:
http://commons.apache.org/pool/
Can you tell us if you reach the sysout for closing connections regulary?
Basically try to create log statements every time you open a connection and every time you close it. Probably you see what you are missing.
Try putting your socket.close() inside a finally block to ensure that it runs.
But I think your code may have bigger problems in that since you are not using a connection pool, you are needlessly opening new connections.