I'm trying to make a networking application, for a proof of concept project.
I need to keep the connection open, the joined clients, but the while loop I'm running never gets out of the first loop.
Code:
public class comm implements Runnable {
private Socket socket;
private String line, input;
boolean sending = true;
boolean connected = false;
private int me;
private BufferedReader br;
private PrintWriter pw;
doComms(Socket server) {
socket = server;
me = Main.connected;
}
public void run() {
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
pw = new PrintWriter(socket.getOutputStream(), true);
while (true) {
System.out.println("Waiting");
readCommand();
}
} catch (Exception ex) {
System.out.println(ex);
}
}
private void readCommand() throws Exception {
String str;
while (br.readLine() != null) {
if (!connected) {
pw.println("connect");
}
str = br.readLine();
System.out.println(str);
if (str.startsWith("!START!")) {
System.out.println("User connected");
connected = true;
String[] split = str.split("#");
Main.jTable1.getModel().setValueAt(split[1], me, 2);
Main.jTable1.getModel().setValueAt(split[2], me, 3);
Main.jTable1.getModel().setValueAt("Connected...", me, 4);
}
}
}
}
Starting that code is fine, all it does is makes a new thread for each connected users, and the client software runs fine too. what am I doing wrong?
My best guess. It never gets out of the first readCommand call because readCommand itself is in an infinite loop:
while (br.readLine() != null) {
br.readLine will block until the next line from the socket input arrives. So the only way for the loop to exit is for the remote client to disconnect.
But the while loop I'm running never gets out of the first loop.
The first loop you are referring to is:
while(true) { ... }
This will never exit because true is always true.
Related
In client socket, I wrote a thread to read the socket's inputStream continuously. Here I have used a while loop to read infinitely. However it takes more CPU; hence is it possible to reduce the CPU. Please add your suggestions.
Also is it possible to add listeners for inputStream.
Thread code:
public void run() {
while (!shutdown) {
try {
if(socketClient != null) {
String message = socketClient.getMessage();
logger.info ("Message size:" + message.length ());
if(!message.equals("EmptyString")) {
process(message);
}
}
} catch (Exception exception) {
logger.info("Unable to read the socket message" +exception);
}
}
}
SocketClient.java
public class SocketClient{
private volatile boolean isConnected;
private int port;
private int retryCount;
private long startTime;
private String hostName;
private DataInputStream input;
private DataOutputStream output;
private Socket socket;
public SocketClient(int port, String hostname) throws IOException {
this.port = port;
this.hostName = hostname;
establishConnection();
}
public void shutdown() {
try {
shutdown = true;
input.close();
output.close();
socket.close();
} catch (Exception e) {
logger.debug("Exception in shutdown:" + e.getMessage());
}
}
public String getMessage() {
BufferedReader reader = null;
try {
StringBuilder builder = new StringBuilder();
reader = new BufferedReader(new
InputStreamReader(tcpSocket.getInputStream()));
do {
builder.append(reader.readLine());
} while((reader.ready()));
if (builder.length() == 0)
return "EmptyString";
return builder.toString();
} catch (IOException e) {
return "EmptyString";
} finally {
try {
if(reader != null)
reader.close();
} catch(IOException e) {
logger.error("unable to close reader");
}
}
}
private void establishConnection() {
retryCount = 1;
startTime = System.currentTimeMillis();
while (!shutdown) {
try {
if(!isConnected) {
socket = new Socket(hostName,port);
socket.setKeepAlive(true);
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
isConnected = true;
shutdown = true;
}
} catch (Exception exception) {
isConnected = false;
sleepFewSeconds();
reconnectSocket();
}
}
}
private void reconnectSocket() {
long endTime = startTime + 120000L;
if(!(System.currentTimeMillis() < endTime)) {
shutdown = true;
}
}
private void sleepFewSeconds() {
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException interruptedException) {
shutdown = true;
}
}
}
I am going to critique the entire class here. The answer to your specific question will appear.
public class SocketClient{
private volatile boolean isConnected;
You don't need this. socket == null would do just as well.
private int port;
private int retryCount;
private long startTime;
private String hostName;
private DataInputStream input;
private DataOutputStream output;
private Socket socket;
public SocketClient(int port, String hostname) throws IOException {
this.port = port;
this.hostName = hostname;
establishConnection();
}
public void shutdown() {
try {
shutdown = true;
input.close();
output.close();
socket.close();
You don't need all these closes, and you're doing them in the wrong order anyway. output.close() is sufficient and in any case it should certainly be first.
} catch (Exception e) {
logger.debug("Exception in shutdown:" + e.getMessage());
}
}
public String getMessage() {
BufferedReader reader = null;
The BufferedReader should be an instance variable, not a local variable. It's buffered. If you make it a local variable you will lose data.
try {
StringBuilder builder = new StringBuilder();
reader = new BufferedReader(new
InputStreamReader(tcpSocket.getInputStream()));
do {
builder.append(reader.readLine());
} while((reader.ready()));
You don't need all this. If the message is a single line, all you need is return reader.readLine(), and you need the caller to check whether it was null, and if so close the socket, cease reading, etc. If the message is more than one line, this is a misuse of ready(): it is certainly not an indicator of end of message. It appears from comments under your question that you shouldn't even have the method: just connect the socket input stream directly to your XML parser and let it do the reading.
if (builder.length() == 0)
return "EmptyString";
Don't do this. Return "" or null. Don't make up new magic strings for your application to have to decode.
return builder.toString();
} catch (IOException e) {
return "EmptyString";
Ditto.
} finally {
try {
if(reader != null)
reader.close();
You should not close the reader here. Closing it will close the socket, so you can never get another message.
} catch(IOException e) {
logger.error("unable to close reader");
}
}
}
private void establishConnection() {
retryCount = 1;
startTime = System.currentTimeMillis();
while (!shutdown) {
try {
if(!isConnected) {
socket = new Socket(hostName,port);
socket.setKeepAlive(true);
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
isConnected = true;
shutdown = true;
Why are you setting shutdown to true here? Nothing is shutdown yet. It's a brand new socket.
}
} catch (Exception exception) {
isConnected = false;
sleepFewSeconds();
reconnectSocket();
}
Poor practice. Socket.connect(), which is called internally by new Socket(...), already retries, and also you should distinguish between connection-failure exceptions rather than adopt the same strategy for them all. For example, a 'connection timeout' will already have blocked for a minute or so: you don't need another sleep; and 'connection refused' means there is nothing listening, so retrying is completely pointless.
private void reconnectSocket() {
long endTime = startTime + 120000L;
if(!(System.currentTimeMillis() < endTime)) {
shutdown = true;
}
}
private void sleepFewSeconds() {
try {
TimeUnit.MILLISECONDS.sleep(20);
This is not a 'few seconds'. It is 20 milliseconds, and that is not enough by at least two orders of magnite in network programming, to the extent that there should be any sleep at all of course.
} catch (InterruptedException interruptedException) {
shutdown = true;
shutdown appears to be never false. I doubt that you've thought through what it really means, and I doubt that you really need it at all.
As for your calling code:
public void run() {
while (!shutdown) {
try {
if(socketClient != null) {
If socketClient is null this loop will spin meaninglessly. Surely this method should construct the socket client?
String message = socketClient.getMessage();
logger.info ("Message size:" + message.length ());
Here you are failing to check for null and failing to respond appropriately, which would be to close the socket and exit the loop. Instead you will get an NPE here.
if(!message.equals("EmptyString")) {
process(message);
See above. Don't send yourself special text messages. What happens if the peer needs to send that one day?
}
}
} catch (Exception exception) {
logger.info("Unable to read the socket message" +exception);
Unacceptable. This catch is inside the loop and it essentially ignores the exception. The result is that, again, this loop will spin meaninglessly on any exception. And the methods you're calling should be declared to throw IOException, and that is all you should catch here. At present you will spin even on NullPointerException.
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 am trying to learn some network programming, so I thought a good place to start would be with sockets and how to use them. Although it seems that I have hit a brick wall, but the issue does not have as much to do with sockets as it does with checking a socket for two things at (seemingly)the same time.
package com.redab.server;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class server implements Runnable {
private final int portNumber = 4444;
private ServerSocket serverSocket;
private Socket clientSocket;
private Thread thread;
private PrintWriter out;
private BufferedReader in;
private BufferedReader stdIn;
private String incomingText;
private String outgoingText;
private Boolean isRunning = false;
public server() {
thread = new Thread(this, "serverThread");
try {
serverSocket = new ServerSocket(portNumber);
clientSocket = serverSocket.accept(); // Unless socket connection is made, probram will not proceed beyond this line.
System.out.println("connected");
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
stdIn = new BufferedReader(new InputStreamReader(System.in));
} catch (IOException e) {
System.out.println("Exception caught when trying to listen on port " + portNumber + " or listening for a connection");
System.out.println(e.getMessage());
}
}
private synchronized void start() {
thread.start();
isRunning = true;
}
private synchronized void stop() {
try {
thread.join();
isRunning = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
System.out.println("running...");
while (isRunning) {
incoming();
outgoing();
}
}
private synchronized void incoming() {
System.out.println("Incoming");
try {
if ((incomingText = in.readLine()) != null) {
System.out.println(incomingText);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private synchronized void outgoing() {
System.out.println("outgoing");
try {
if ((outgoingText = stdIn.readLine()) != null) {
out.println("Server: " + outgoingText);
System.out.println("Server: " + outgoingText);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
server server = new server();
server.start();
}
}
My problem is the following:
How do I make it so both the method incoming() and outgoing() is ran constantly when I execute the code?
I did google a bit and threads seems to be the solution, so I tried creating a thread which is supposed to run both methods for me. But I run into the same problem again, the code gets stuck in the incoming() method when I want it to simply check this statement ((incomingText = in.readLine()) != null) and then proceed to the method outgoing(). I suspect I might need two threads, one of which checks for incoming messages through the socket and the other checks for outgoing messages that are typed into the console(System.in).
I suspect I might need two threads, one of which checks for incoming messages through the socket and the other checks for outgoing messages that are typed into the console(System.in)
You are right, you need two threads, one per each task.
You might want to check if there is data available to read by using the in.ready() method first. If available, you can read the data using in.readLine(), else do nothing. Currently, in.readLine() blocks because there is no input available on the socket.
I wrote this simple code :
class main{
public static void main(String []a)throws UnknownHostException,IOException{
Scanner sc = new Scanner(System.in);
int choice;
ServerSocket ss = new ServerSocket(60000,1,InetAddress.getLocalHost());
Thread t = new Thread(new Conversation(ss));
t.start();
while(true){// I think i need to set a better condition here
do{
System.out.println("Hello user choose a number between 0 and 2");
}
while(!sc.hasNextInt());
choice = sc.nextInt();
if(choice >2 || choice < 0)
choice = 0;
switch(choice){
case 0:
//print some stuff
break;
case 1:
//print other stuff
break;
case 2:
//print new stuff
break;
default:
break;
}
}
}
}
And heres the code of the class Conversation :
public class Conversation implements Runnable {
ServerSocket ss;
Socket client;
boolean connected;
Conversation(ServerSocket cli){
this.ss= cli;
client = null;
connected = false;
}
void connected(){
this.connected = true;
}
void disconnected(){
this.connected = false;
}
#Override
public void run() {
// TODO Auto-generated method stub
while(true) {
PrintWriter pw = null;
if(!this.connected){
try {
client = ss.accept();
pw =new PrintWriter(client.getOutputStream(),true);
this.connected();
} catch (IOException e) {
System.err.println("Accept failed.");
System.err.println(e);
System.exit(1);
}
BufferedReader in = null;
PrintWriter out = null;
try {
in = new BufferedReader(new InputStreamReader(
client.getInputStream()));
out = new PrintWriter(client.getOutputStream(), true);
} catch (IOException e) {
System.err.println(e);
return;
}
String msg;
try {
while ((msg = in.readLine()) != null) {
if(msg.equals("CLO") || msg.equals("clo")){// if a CLO message is sent the conversation ends
client.close();
in.close();
out.close();
pw.close();
this.disconnected();
break;
}
else{
System.out.println("Client says: " + msg.substring(7));
}
}
} catch (IOException e) {
System.err.println(e);
}
}
}
}
}
Basically all it does is to wait for a user input and then prints something according to what he typed.
The problem I'm facing is:
I want that when someone connects to the ServerSocket ss in the thread t(so the value of connected is true)I want the main function to stop whatever it is doing and to just send the user input into the OutputStream of the socket client(so in other words starting a chat when someone connects to the ServerSocket).
But i don't know how to do so I'm new in Threading and networks in Java , is there a way for the thread T to send a signal to the main function of the main class or does anybody have an idea of how to achieve this ?
I have already posted some samples code in the same context. Please have a look at below samples and try to follow each and every step to understand it. Read inline comments carefully.
Multiple clients access the server concurrently
Java Server with Multiclient communication.
Server-Client chat program
please let me know if there is any confusion.
I have a thread that uses network port for communication. I added
cancel() method to stop the execution and close network resources (How to properly stop the Thread in Java?)
private class ServerThread extends Thread {
int portNumber;
String serverAddress = null;
public ServerThread(String serverAddress, int portNumber) {
super();
this.serverAddress = "localhost";
this.portNumber = portNumber;
}
#Override
public void run() {
ServerSocket listener;
Socket socket;
try {
listener = new ServerSocket(this.portNumber);
socket = listener.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(),
true);
while (!isInterrupted()) {
String input = in.readLine();
if (input != null) {
out.println(input);
System.out.println("Hi:" + input);
}
} // end of while loop
System.out.println("OUT"); <-- ???
socket.close(); <-- ???
listener.close(); <-- ???
} catch (IOException e) {
e.printStackTrace();
}
}
public void cancel() {
System.out.println("cancel called");
interrupt();
}
}
The issue is that when I execute the ServerThread, and send cancel() message to finish the execution, it seems like that the three lines of code never executed: System.out.println("OUT"); socket.close(); listener.close();.
It also seems like that I don't need to send cancel() message to finish the thread.
ServerThread s = new ServerThread(serverAddress, serverPortNumber);
s.start();
...
s.cancel(); // ???
What's the recommended way of closing resources used by threads?
Don't I have to close resources when thread is not used anymore? Or everything is just automatically processed?
ADDED
It seems like that the thread is killed automatically as this code just works.
while(true) {
String input = in.readLine();
if (input != null) {
System.out.println("Received:" + input);
out.println(input);
}
} // end of while loop
/* System.out.println("OUT");
socket.close();
listener.close(); */
Thread#interrupt() will not interrupt the blocking I/O call on the socket. Try setting a "stop" flag and closing the socket in the cancel() method instead, and deal with the exception and check the flag in the while loop.
InterruptibleChannels reacts on the interrupt call, but not "old fashioned" socket streams.
In Java 7 you can use the try (resource) {} catch idiom like this:
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
while ((line = reader.readLine()) != null) {
process(line);
}
} catch (IOException e) {
e.printStackTrace();
}
This will guarantee that the stream is closed properly once the try block is left. No matter what happens inside or how the try/catch terminates.