I am writing a Java client application(Basic Java Net package with TCP/IP). The client must take input from the system.in and at the same time must listen to any messages coming from server through socket inputstream.
Once an input from the system.in is received, the client will get that input, do some processing and send it to the server as a request.
So basically 2 processes run,
-listening to client request
-listning to server responses.
I implemented 2 threads for this and ran the processing of messages in the main thread.
Is this good enough design.?
And is there a way to return the message received from the system.in to the main thread. The threads run() method returns void. I used a volatile variable to return the string received but its said that volatile is very costly since it doesn't use cpu cache to store the variable.
You can review these two projects I've written for an example of java sockets and multithreading.
Client
Server
I guess the ClientExample is the one you are searcing for but you can take a look at the server part too.
Basically the idea is to start two separate threads that listen for the different inputs - socket and console.
final Thread outThread = new Thread() {
#Override
public void run() {
System.out.println("Started...");
PrintWriter out = null;
Scanner sysIn = new Scanner(System.in);
try {
out = new PrintWriter(socket.getOutputStream());
out.println(name);
out.flush();
while (sysIn.hasNext() && !isFinished.get()) {
String line = sysIn.nextLine();
if ("exit".equals(line)) {
synchronized (isFinished) {
isFinished.set(true);
}
}
out.println(line);
out.flush();
disconnect();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
}
};
};
outThread.start();
and another thread for the socket input:
final Thread inThread = new Thread() {
#Override
public void run() {
// Use a Scanner to read from the remote server
Scanner in = null;
try {
in = new Scanner(socket.getInputStream());
String line = in.nextLine();
while (!isFinished.get()) {
System.out.println(line);
line = in.nextLine();
}
} catch (Exception e) {
// e.printStackTrace();
} finally {
if (in != null) {
in.close();
}
}
};
};
inThread.start();
I hope this will help you :)
Related
The situation is as following:
There is a server and a client, which both can initiate a command/message to each other.
Because the server can send a message at any time, the listening on the socket is done in a separate thread (a ListenerThread). This is all fine. The client can send messages and receive at the same time, however, how would you know if a certain response belongs to the command you sent when the server can also initiate a new command/message to notify that something happened?
If I send a message to the server, and the server responds with "OK" in the listening thread. How would you know this is the actual response of the message/command you sent (keeping in mind this is another thread). What if the server received an update from another client and sends that update first.
This like a chat application, though with an actual response for every sent command.
example case:
Let us say that the protocol only consists of a move <playernum> [<x>,<y>] command which indicates that a player has done a move (server notifies client) or that a player wants to do a move (client notifies server). Also, the server responds with "OK" if the move was okay or with "ERR" if not.
Safe state:
move 1 [3,4]
client ---> server
OK
client <--- server
Unsafe state:
move 1 [3,4]
client ---> server
move 2 [1,2]
client <--- server
OK
client <--- server
The client did not expect this response... should responded with OK.
You have a protocol where the client can read one of three possible messages:
OK (The move you made was accepted)
ERR (The move you made was rejected)
move PLAYERID <co-ord1,co-ord2>
It is a reasonable assumption that the messages OK and ERR will only be sent back to the socket which requested a move. However a legal move is broadcast to all other players (perhaps excluding the player who moved).
Since you can receive unsolicited responses (the moves that other players make), you have correctly created a listener thread. You have not described the action your application takes when it receives a move message from another client, but I will assume that your listener thread handles that case. What remains is how to co-ordinate your move commands, and the response to that which will appear in the listener thread.
To synchronize the submission of your move command, and the response, a BlockingQueue (called queue) will be used , and shared between the client and listener. The form of this will be:
Client:
out.println(command); // Where out is the socket PrintWriter stream
String response = queue.take(); // Where queue is the BlockingQueue
// Process either `OK` or `ERR`
Listener Thread:
while ((command = in.readLine()) != null) {
if (command.equalsIgnoreCase("OK") || command.equalsIgnoreCase("ERR"))
queue.put(command);
else if (command.startsWith("move")) {
// Process a move
}
else
System.out.println("Unrecognized command="+command);
}
As you can see, the client simply submits a command, and blocks for the response of "OK" or "ERR". The requirement for processing other player moves has moved into the listener thread.
The listener processes all three conditions (Another player move, an "OK" or an "ERR"). The messages responses "OK" and "ERR" are sent back to the client. A move command is processed separately, and as such is not the responsibility of the client making the moves.
Below I have mocked working code which demonstrates these concepts. The server will randomly (with equal probability) respond with:
OK
ERR
A multiline response which includes OK and another player's move
Code:
public class MoveGame {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String command = "";
new Thread(new MoveServer()).start();
Socket socket = null;
PrintWriter out = null;
BlockingQueue<String> queue = new ArrayBlockingQueue<String>(10);
try {
socket = new Socket("localhost", 5001);
out = new PrintWriter(socket.getOutputStream(), true);
new Thread(new ClientReader(socket, queue)).start();
while (!command.equals("quit")) {
command = scanner.nextLine();
if (command.startsWith("move")) {
out.println(command);
String response = queue.take();
System.out.println("Client got response="+response);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
scanner.close();
out.close();
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
static class ClientReader implements Runnable {
private final Socket socket;
private final BlockingQueue<String> queue;
public ClientReader(Socket socket, BlockingQueue<String> queue) {
super();
this.socket = socket;
this.queue = queue;
}
#Override
public void run() {
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String command;
while ((command = in.readLine()) != null) {
if (command.equalsIgnoreCase("OK") || command.equalsIgnoreCase("ERR"))
queue.put(command);
else if (command.startsWith("move")) {
System.out.println("A player made a move: command="+command);
}
else
System.out.println("Unrecognized command="+command);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
static class MoveServer implements Runnable {
#Override
public void run() {
Random random = new Random();
Socket socket = null;
try {
ServerSocket ss = new ServerSocket(5001);
while (true) {
System.out.println("Listening for new connections");
socket = ss.accept();
System.out.println("New session has started");
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String command;
while ((command = in.readLine()) != null) {
System.out.println("Got command="+command);
int responseType = random.nextInt(3);
if (responseType == 0)
out.println("OK");
else if (responseType == 1)
out.println("ERR");
else {
out.println("move 1 [3,4]");
out.println("OK");
}
}
in.close();
out.close();
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
I had to implement a Client-Server application in Java that automatically updates txt files in a Server directory depending on changes in the files in the Client side, for a homework assignment (had to, because I'm past the deadline).
I have a package that handles the changes in the files correctly, but I'm stumped about how to handle the changes in multiple files. My approach was using separate threads for each file in the client directory and using corresponding threads in the server directory for the same cause. This approach works for a single file, but not for multiples.
The code below is on the client side and calls a file's thread's checkfilestate method to handle the updates.
while(true){
for (Map.Entry<String, SynchronisedFile> entry : fileList.entrySet()) {
try {
System.err.println("SyncTest: calling fromFile.CheckFileState()");
sstt.start();
entry.getValue().CheckFileState();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
} catch (InterruptedException e) {
e.printStackTrace();
System.exit(-1);
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
System.exit(-1);
}
}
And on the server side, if I start a single thread using:
Thread sstt = new Thread(new SyncThreadServer(sfileList.entrySet().iterator().next().getValue(),clientSocket));
sstt.start();
It works as expected. But if I start the serverside threads at the same time (which contains methods for decoding the Json messages from the input stream) using:
for (Map.Entry<String, SynchronisedFile> entry : sfileList.entrySet())
{
Thread sstt = new Thread(new SyncThreadServer(entry.getValue(),clientSocket));
sstt.setName(entry.getKey());
}
Threads of other files start reading JSON messages intended for other threads from the input stream. I'd like to be able to stop the serverside loop from starting the next thread, at least until the checkFile method is complete for one file/thread. But I still might run into problems after the initial stage, when all the treads are running at the same time. Any solutions on how to handle multiple threads in this case? (All threads use a single socket).
Edit: As I understand, this has to do with synchronization. Threads of other files on the server are accessing the Input stream before the first thread has even finished processing the inputs meant for it. This is the code of the server thread below. I need to somehow block the other threads from accessing the input stream before the first one has finished using it. Any help would be much appreciated. Thanks.
public class SyncThreadServer implements Runnable {
SynchronisedFile toFile; // this would be on the Server //Is an instance of the syncfile class, should be able to proc insts
Socket clientSocket;
public SyncThreadServer(SynchronisedFile tf, Socket aClientSocket){
toFile=tf;
clientSocket = aClientSocket;
}
#Override
public void run() {
Instruction inst = null;
InstructionFactory instFact=new InstructionFactory();
while(true){
{
try{
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream());
String smsg = in.readUTF();
Instruction receivedInst = instFact.FromJSON(smsg);
System.err.println(smsg);
// The Server processes the instruction
toFile.ProcessInstruction(receivedInst);
//if(receivedInst.Type().equals("EndUpdate")){
// out.writeUTF("NEXT"); //TODO: Change to Json
// out.flush();}
//else
//{
out.writeUTF("GO"); //TODO: Change to Json
out.flush();
}
//}
catch (IOException e) {
e.printStackTrace();
System.exit(-1); // just die at the first sign of trouble
} catch (BlockUnavailableException e) {
// The server does not have the bytes referred to by the block hash.
try {
DataOutputStream out2 = new DataOutputStream(clientSocket.getOutputStream());
DataInputStream in2 = new DataInputStream(clientSocket.getInputStream());
out2.writeUTF("NGO"); //TODO: Change to Json
out2.flush();
String msg2 = in2.readUTF();
Instruction receivedInst2 = instFact.FromJSON(msg2);
toFile.ProcessInstruction(receivedInst2);
if(receivedInst2.Type().equals("EndUpdate")){
out2.writeUTF("NEXT"); //TODO: Change to Json
out2.flush();}
else
{
out2.writeUTF("GO"); //TODO: Change to Json
out2.flush();
}
} catch (IOException e1) {
e1.printStackTrace();
System.exit(-1);
} catch (BlockUnavailableException e1) {
assert(false); // a NewBlockInstruction can never throw this exception
}
}
// } //And here
}
}
}
I tried everything stack overflow has to offer on this common readLine problem. (sending \n, flushing out, changing to byte array style, becoming hermit, wrists )
I suspect in this case its a concurrency thing as Ispent well over 15 hours yesterday confirming that the only thing that isnt working is readline()!
I used loads of other versions like datareader with a byte array and making sure a \n got sent I even sent /ns just in case!
still my issue is the same, and I have ran out of ideas myself to solve the issue and have decided that somewhere, my problem is outside my understanding, just where? its got to be threading right?
I managed to get to read the socket to string that seemed to work so it IS blocking because reading the connection isnt working at all, the readline function is not the only way Ive had it as I said so in my snippets its not as developed as it has been but still the basic issue remains.
Please help, i dont know what the issue is
// So the main class initialises the socket objects and starts them in a thread, these work I get all sorts of flags letting me know that they are
void start_sockets() {
//if this is initiialised as a server and not a client
if (is_server) {
while (is_server) {
try {
System.out.println("listening for connection");
Sockject sj = new Sockject(server.accept());
sock_arr.add(sj);
System.out.println("server made connection ");
// once the connection is made the objects is started in a
// separate thread
new Thread(sock_arr.get(sock_arr.size() - 1)).start();
} catch (IOException e) {
}
}
} else { //else im running a client version of this class
// if the client socket isnt running in a thread, make it run
if (!running) {
new Thread(sj_client).start();
if (sj_client.sock.isConnected()) {
System.out.println("client thread connected to "
+ sj_client.sock.getLocalSocketAddress());
running = true;
}
}
}
}
//the inner class creates a socket object and puts it on an array or an object depending if the parent class is initialised to be a server or a client
class Sockject implements Runnable {
PrintWriter out;
BufferedReader in;
// a socket for processing
Socket sock;
// the constructor in this case initialises the input and output streams
Sockject(Socket s) {
sock = s;
try {
out = new PrintWriter(sock.getOutputStream());
in = new BufferedReader(new InputStreamReader(
this.sock.getInputStream()));
} catch (IOException e) {
close sockets
}
}
//tried variasions of this and similar, used data objects and been sennding /ns all over the shop
void recieve_data() throws IOException {
if (sock.isConnected()) {
if ((recieve = in.readLine()) != null) {
System.out.println("recieve says " + recieve);
}
}
}
// sends data to connection if it is cleared to send data
void send_data(String data) {
// send data called
if (clear_to_send == true) {
out.print(data);
out.flush();
clear_to_send = false;
}
}
#Override
public void run() {
while (threadloop ) {
try {
//code defo gets this far and with just send it keeps running forever so its defo recieve data thats the issue
send_data(send);
recieve_data();// <---I HATE YOU
} catch (IOException e) {
}
}
}
}
}
Now all of the above is ran in an instance of this class, in a thread of this class here these temporary functions are ran and are neversuccesfull
void servrecievex(){
System.out.println("NEVER GETS THIS FA THOUGH DOES IT");
for(int a = 0; a < net_flow.sock_arr.size(); a++){
if(net_flow.sock_arr.get(a).sock.isConnected()){
System.out.println("server recieve function");
net_flow.sj_client.clear_to_send = true;
net_flow.sock_arr.get(a).send_data("www /n \n");
System.out.println("RECIVEIFY!!!");
}
}
}
void clientsendx() {
net_flow.sj_client.clear_to_send = true;
net_flow.sj_client.send_data(Integer.toString(player1.posx) + "\n");
System.out.println("client sent stuff");
}
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.
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();
}