I am doing client server Java program using Java NIO. Basically for the server codes, I took from here. And for the client side, I took from here. Now it seems good. What I want to achieve now is send data from client to server,and server will send back to the client.
But I am having a problem with the logic. Lets say I put "AMessage", then I have to put "BMessage" in order to retrieve "AMessage" from the server. I did the debugging, and seems like my key.isConnectable() is always return true. I try to set the key interest, reregister it, but I didn't found any solution yet.
I have tried this one key.interestOps(0);, myChannel.register(selector, SelectionKey.OP_READ);, but seems nothing happen. isConnectable still returned true. I found some issues informed by other people saying that it is localhost issue. I have no idea. But now I am running the server and client on localhost. Anyone has any idea?
Thanks :)
Edited: This is part of my codes:-
if (key.isConnectable()) {
if (myChannel.isConnectionPending()) {
try{
myChannel.finishConnect();
}
catch(IOException e){
System.out.println(e);
}
System.out.println("Status of finishCOnnect(): " + myChannel.finishConnect() );
System.out.println("Connection was pending but now is finished connecting.");
}
ByteBuffer bb = null;
ByteBuffer incomingBuffer = null;
Scanner input = new Scanner(System.in); // Declare and Initialize the Scanner
while (true) {
System.out.println("Status isReadable is " + key.isReadable() + " and isWritable is " + key.isWritable() +
" and isConnectable is " + key.isConnectable());
readMessage(key); //read if server send data
//send data to server here
String inputFromClient = input.nextLine(); //Get the input from client
System.out.println("debugging after get input...");
bb = ByteBuffer.allocate(inputFromClient.length()); //Allocate buffer size according to input size
byte[] data = inputFromClient.getBytes("UTF-8"); //convert the input to form of byte
bb = ByteBuffer.wrap(data); //wrap string inside a buffer
myChannel.write(bb); //Write the buffer on the channel to send to the server
bb.clear();
}
}
if (key.isConnectable()) {
if (myChannel.isConnectionPending()) {
try{
myChannel.finishConnect();
}
catch(IOException e){
System.out.println(e);
}
System.out.println("Status of finishCOnnect(): " + myChannel.finishConnect() );
System.out.println("Connection was pending but now is finished connecting.");
}
There are several problems here.
The isConnectionPending() test is redundant. It must be pending, otherwise you wouldn't have got the event, but you may be tempting Providence by testing it. Get rid of this test.
You aren't doing the right thing with the finishConnect() call. If finishConnect() returns true then it is OK to deregister OP_CONNECT and register OP_READ or whatever. If it returns false, it isn't OK.
If finishConnect() throws an exception, the connect has failed and you must close the channel.
You are calling finishConnect() twice: once in the try block and once when logging the state. Get rid of the second call and use the result of the first call, if there is one. I would reorganize this to log (a) success from finishConnect(), (b) failure from finishConnect(), and (c) exception from finishConnect(), all separately.
Your final System.out.println() is just a lie in two out of the three cases. Don't tell yourself things that you don't know to be true. It just confuses the picture. Log each case separately as above.
You are assuming that the connection is readable, instead of testing isReadable().
Related
I am building this program where a server sends different order to different clients. One part of the program sends the order to the server, the server processes to which client the message goes to and then it sends it to the particular client it should go.
Here is the code where the message is send:
#Override
public void run() {
boolean active = true;
String oldMsgToDron = "";
String to_print = "";
BufferedWriter bw = new BufferedWriter(osw);
while(active) {
try {
//msgToDron is declared in DronController as: public static volatile String msgToDron;
to_print = DronController.msgToDron;
if(to_print.equals(oldMsgToDron) == false) {
System.out.println("Message we are sending to the dron: " + to_print);
if(to_print.length()>45 && to_print.startsWith("!whisper") && dronId.equals(to_print.substring(9, 45))) {
bw.write("Server whispers:" + to_print.replace("!whisper " + dronId, ""));
bw.newLine();
bw.flush();
System.out.println("Message we sent to the dron: " + to_print);
}
else if (to_print.startsWith("!whisper") == false){
bw.write(to_print);
bw.newLine();
bw.flush();
System.out.println("A message for all drones has been sent.");
}
try{Thread.sleep(5);}catch(InterruptedException ex){ex.printStackTrace();}
oldMsgToDron = "";
to_print = "";
DronController.msgToDronEsclavo = "";
}
}catch(IOException e) {
try {
active = false;
if(bw != null)
bw.close();
}catch(IOException f) {e.printStackTrace();f.printStackTrace();break;}
}
}
}
My problem is that the message is processed inside the thread that controls the connection to the client and at the end of the loop the message is changed to an empty string. This is so I can send the same order twice in a row and the server isn't constantly sending the same messages to the client.
The thing is that by doing it this way if I have 3 or more connections it starts to give me problems because whenever one of the threads reaches the end they turn the variables DronController.msgToDronEsclavo, to_print and oldMsgToDron to empty strings before the other threads had time to check if the message was for the client they have assigned.
How can I avoid that the different threads change the variable before the others have finished? Are there any kind of design pattern for this kind of structures? What are some good practices with this type of programs?
Also, I've thought about making the client check if the message sent is for them or not but I find this solution unsecure.
Usually it is the client who connects to the server via network - to request data or to send data. The server has no reliable way to know when the client would connect the next time, or trigger a connection itself.
If you want to send data from the server to the client there used to be patterns that the client would poll for data, or have always one request waiting for the next packet from the server. You may want to read about AJAX and Websocket
Another pattern would be to install a webhook, which essentially gives the server a URL at which the client can be reached. This in essence swaps the server to acting as client and the client to acting as server for this data transfer.
Well, the above was written related to your question title. Now looking at the content, you are asking how to prevent that threads impact each other.
Learn Java's concepts on thread synchronization. Here is a nice tutorial.
I'm trying to create a single-threaded echo-server, but I can't figure out how to send the input from the client back to the client again from the server. The client connects to the server alright, but it's when it's waiting for a response that it throws an IOException. I have tried connecting my chat client to other chat servers, hence I'm sure the fault is in the chat server implementation.
I'm guessing the "villain of the piece" is this method presented below that takes the input from the connected client and sends it back, but I'm not sure why it doesn't work.
private void processClientRequest(Socket clientSocket) throws IOException {
InputStream in = clientSocket.getInputStream();
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream());
long time = System.currentTimeMillis();
out.write("Server - " + time + ": " + in);
out.close();
in.close();
}
Please tell me if this method isn't the issue and you need other parts of my code instead.
Thanks in advance!
Edit: I have now managed to get my server to respond to the client. I did this by changing the processClientRequest method to this:
try {
BufferedReader in =
new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream());
long time = System.currentTimeMillis();
out.write("Server - " + time + ": " + in.readLine());
out.close();
try {
in.close();
} catch (IOException e) {
System.err.println("Couldn't close input stream");
}
} catch(IOException e) {
System.err.println("Got an IOException error while reading or writing from/to client");
}
But as of now my server can only respond the client once. If the client writes to the server a second time it does get a response, but instead of the clients message, it's "null". And since I want my echo server to be able to answer the client until the client shuts down or something like that, I need to figure out how to change that. I figure I'm going to need some kind of while loop to make this happen, but I have tried for example putting the whole try statement into an infinite while loop, but that just gave me loads of IOExceptions.
You're not reading the clients input. You're just passing the toString to your out. You need to make a while loop and read from in. Maybe in a seperate thread unless you're sure the input is short. In test code should be okay:
private void processClientRequest(Socket clientSocket) throws IOException {
InputStream in = clientSocket.getInputStream();//wrap this in a object stream or other to read lines/ utf
int i = 0;
while(i++ < 1000 && in.available() > 0){
int read = in.read();//use it if u want, like to a string builder declared out of loop and echo it back after u read input
}
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream());
long time = System.currentTimeMillis();
out.write("Server - " + time + ": " + in);
out.close();//should be in seperate try catches so if 1 close fails u still close other and finally close socket in 3rd try catch
in.close();
}
Socket server with working echo server, mini web server and helpful in many more ways.
I am working on class project for a remote string processor. It's my very first project in Java, so I do not really understand what all is going on...
I have everything finally working from Client to Server, but when it comes for the server to send the results back to the client, they both stay hang up and won't do anything until I forcefully close the server. Then "voilĂ !"... everything I was waiting for shows up on the client side.
If you have encountered such an issue, you probably are smiling right now as you click in the Answer box down below :)
Here is part of the server-side functions code, they give an idea about what I'm expecting to see on client-side as output.
//Get an output stream for writing to the client socket dataSocket
PrintStream socketOutput = new PrintStream(dataSocket.getOutputStream());
// some code here then
// This is where the various functions are executed depending on
// the value of the code entered by the user.
// A string, an integer, or a
// Boolean value depending on the case will be returned and printed
if (string1 != null && string2 != null) {
System.out.println("STRINGS 1 AND 2 WERE NOT NULL, SO LET'S ENTER SWITCH");
switch (code) {
case 1:
System.out.println("IN CASE 1");
int returnedSign = string1.compareTo(string2);
if (returnedSign > 0) {
System.out.println("IN CASE 1, returnedSign > 0");
socketOutput.println(string1+" lexically follows "+string2);
}
else if (returnedSign < 0) {
System.out.println("IN CASE 1, returnedSign < 0");
socketOutput.println(string2+" lexically follows "+string1);
}
else if (returnedSign == 0) {
System.out.println("IN CASE 1, returnedSign == 0");
socketOutput.println(string1+" equals "+string2);
}
System.out.println("AT END OF CASE 1");
socketOutput.flush();// forcing the socketOutput to let go of any data
break;
Alright, and here is some client-side code that's supposed to receive the output of the server and display it on the client screen:
// Get an output stream for writing to the socket
ObjectOutputStream myOS = new ObjectOutputStream(clientSocket.getOutputStream());
// Get stuff from the server and display them on the client's screen
BufferedReader ois = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); ...
...// Write to the Stream, that is get the code and the two strings
// to the stream
String codeMadeString = Integer.toString(code);
String messageString = code+";"+string1+";"+string2;
System.out.println("User entered: "+messageString);
myOS.writeObject(messageString);
//String serverOut = "";
String serverOut = (String)ois.readLine();
serverOut+='\n';
serverOut+=(String)ois.readLine();
serverOut+='\n';
serverOut+=(String)ois.readLine();
serverOut+='\n';
serverOut+=(String)ois.readLine();
System.out.println("Server said she saw... \n "+serverOut);
myOS.flush();
// Close the data socket
clientSocket.close();
Again, my question can also be stated as "what should I do to make sure that what's sent by the server is seen by the client without me having to close force the server to close first?"
Notes: I am working from the Terminal on MacOS Mavericks.
Any constructive ideas are welcome. Also, I am not a specialist in this, so please...
UPDATE1: I added the declaration of socketOutput.
I was not closing the buffered reader at first. Then I closed it at the wrong place. And finally, I found out it needs to be just at the end of the infinite loop server-side.
So:
while(true){
// Some code;
// Get stuff from the server and display them on the client's screen
BufferedReader ois = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// Some more code and then
ois.close(); // before I get outside the loop.
}
And that's it!
I have code that is similar to the code below. The problem that I'm having is that when the ObjectInputStream (the input variable) tries to read an object (which will only happen after the connection has been established), it crashes and gives me an error:
java.net.SocketException: Connection reset
and refers to the line with:
message = (String) input.readObject();
It goes into the ex exception loop when it should only go there if the client disconnects (As far are I know).
#Override
public void run() {
String message = "";
do{
try{
message = (String) input.readObject();
}catch(ClassNotFoundException cnfException){
System.err.println("Unable to read client data.");
}catch(Exception ex){ // Will get called if the client is no longer in communication with the server.
continueTalking = false; // If the client disconnects, the server will shut down its communication with the client.
ex.printStackTrace();
break; // Breaks out of the do...while loop.
}
if(message.equals("DISCONNECT")){
continueTalking = false;
System.out.println(connection.getLocalAddress() + " disconnected from the session.");
}
else{
//TODO Send the message off to be processed.
}
}while(continueTalking); // Continues waiting for a message until continueTalking = false
closeStreams();
}
Thank you!
UPDATE: I figured it out. I originally tried out EOFException, but for some reason that was never called. I eventually found out that it was a problem with my client side that it wasn't actually sending any data and disconnected itself as soon as it ran. For anyone experiencing the same problem as me, here is my fixed code:
/** This should handle the connection **/
#Override
public void run() {
/** The message that the client has sent to the server. **/
String message = "";
do{
try{
message = (String) input.readObject(); // Waits for the client to send a message to the server.
}catch(ClassNotFoundException cnfException){
System.err.println("Unable to read client data. Continuing on with my life.");
}catch(Exception noConnectionToSocketFound){ // Will get called if the client is no longer in communication with the server.
System.out.printf("User with handle: %s disconnected.\n", clientIP);
continueTalking = false; // If the client disconnects, the server will shut down its communication with the client.
break; // Breaks out of the do...while loop that is constantly waiting for the client to send a message to.
}
/** If the client sends the message "DISCONNECT", then the server will shut down all communications with said client. **/
if(message.equals("DISCONNECT")){
System.out.println(connection.getLocalAddress() + " disconnected from the session properly.");
continueTalking = false; // If the client wants to disconnect, then the server will stop trying to communication with said client.
break; // Breaks out of the do...while loop that is constantly waiting for the client to send a message to.
}
else if(message != ""){
System.out.printf("Got message from %s:\n%s\n", clientIP, message);
message = ""; // Is needed so that this loop doesn't get called every time after the first message has been sent. Without it, after the word "cheeseburger" is sent, it would continually think that "cheeseburger" is being repeatedly sent (this might not actually happen anymore).
//TODO Send the message off to be processed.
}
}while(continueTalking); // Continues waiting for a message until continueTalking = false
closeStreams(); // Just some clean up
The
continueTalking = false;
break;
might be a bit redundant and unnecessary (I would only really need one of them), but I feel better knowing that there are two things to fall back on.
Hope this helps!
'Connection reset' has many possible causes, but the most common one is that you have written to a connection that has already been closed by the peer: in other words, an application protocol error.
Your loop should catch EOFException separately and treat it as an orderly close.
I want to write a simple web proxy, for exercise. Here's the code I have so far:
def g = new Proxy()
g.serverPort = 9000
println "starting"
g.eachClient { Socket client ->
println "got a client"
try {
client.withStreams { input,output ->
String text = input.text
println "received $text from client"
client.close()
}
} catch(IOException io) {
println "IO error. Probably client disconnected"
//io.printStackTrace()
}
}
the thing is, the line :
String text = input.text
consumes all the available data in the Socket's InputStream. If the client isn't closing the connection, that method will just wait until it can read a end of file character ( if I remember correctly ). What do I have to prevent this from happening, and have the client's string available ASAP?
I think you'll want to check the documentation on ObjectInputStream. Do length = input.available to get the number of available bytes at the present time, then use input.read(buffer, offset, length) to read in exactly as many bytes are available. You'll probably want to launch a new thread for every new connection which transparently manages this buffer in the background, unless you're making a single-threaded proxy to begin with.