I am working on a client/server project for class. I have the server set up so that it is listening for inputs and will relay appropriate message/messages back to the client. For example, client sends input "help" to the server, the server will respond with 5 lines of strings back to the client's console. This is done with the code:
while (true) {
System.out.print('>');
inputLine = bufferedReader.readLine();
toServer.write(inputLine + '\n');
toServer.flush();
while ((serverInput = fromServer.readLine()) != null) {
System.out.println(serverInput);
}
So I believe the problem with this is that it is indefinitely waiting for serverInputs at the end. I would like it to go back to reading inputs from the console after all the appropriate messages have been received. Any help is greatly appreciated. Thank you
Related
I'm having problems sending messages from client to server and to server to other clients. Please can you give me a hand by telling me something.
The problem is if I do an input (line 46) I can get an answer from the server (line 51) then continue this loop.
But for example, if the server must notify a user that it's his turn, I wouldn't get the message until I try typing something.
while ((userInput = stdIn.readLine()) != null) {
/* line 46 */ out.println(userInput);
if (userInput.equals("quit")) {
break;
}
/* line 51 */ lines = in.readLine();
System.out.println(lines);
System.out.println("input next command:");
}
You have to make (at least i dont know how else to do it) a separate thread where you get user input, then use message passing (just search "message passing java") for comunication. Server messages will not get blocked by input and you can tryReceive (or some name around that lines) on channel. In main thread query for message from server, then from input channel, sleep a little and repeat. When user presses enter, channel gets filled with his message, main thread takes it when passing by.
I have a multithreaded chat server that I have converted to work with Java SSL sockets. You can see the version without SSL sockets compared to the one I converted here, on Github. (Master branch has SSL, other branch has regular sockets)
This original model (without SSL) uses "ServerThreads" controlled by the Client to communicate with other Clients by sending messages to their "ClientThreads" on the server side, which then will echo their messages out to all other ServerThreads.
Here is the run method of ServerThread_w_SSL (client side)
#Override
public void run(){
System.out.println("Welcome :" + userName);
System.out.println("Local Port :" + socket.getLocalPort());
System.out.println("Server = " + socket.getRemoteSocketAddress() + ":" + socket.getPort());
//setup handshake
socket.setEnabledCipherSuites(socket.getSupportedCipherSuites());
try{
PrintWriter serverOut = new PrintWriter(socket.getOutputStream(), false);
InputStream serverInStream = socket.getInputStream();
Scanner serverIn = new Scanner(serverInStream);
// BufferedReader userBr = new BufferedReader(new InputStreamReader(userInStream));
// Scanner userIn = new Scanner(userInStream);
socket.startHandshake();
while(!socket.isClosed()){
if(serverInStream.available() > 0){
if(serverIn.hasNextLine()){
System.out.println(serverIn.nextLine());
}
}
if(hasMessages){
String nextSend = "";
synchronized(messagesToSend){
nextSend = messagesToSend.pop();
hasMessages = !messagesToSend.isEmpty();
}
serverOut.println(userName + " > " + nextSend);
serverOut.flush();
}
}
Here is the run method of ClientThread_w_SSL (server side)
#Override
public void run() {
try{
// setup
this.clientOut = new PrintWriter(socket.getOutputStream(), false);
Scanner in = new Scanner(socket.getInputStream());
//setup handshake
socket.setEnabledCipherSuites(socket.getSupportedCipherSuites());
socket.startHandshake();
// start communicating
while(!socket.isClosed()){
if(in.hasNextLine()){
String input = in.nextLine();
// NOTE: if you want to check server can read input, uncomment next line and check server file console.
System.out.println(input);
for(ClientThread_w_SSL thatClient : server.getClients()){
PrintWriter thatClientOut = thatClient.getWriter();
if(thatClientOut != null){
thatClientOut.write(input + "\r\n");
thatClientOut.flush();
}
}
}
}
The original program works with regular sockets, but after converting to SSL sockets, I encountered a problem: input is not being echoed back from the ClientThreads (server side) to the ServerThreads (client side).
In my first attempt at converting to SSL I used certificates, keystores and truststores. I encountered the same problem then as I do here without them, instead only using the default socket factory which relies on the cacerts file that comes with the JDK.
Note that before this bug was encountered, the first problem to address was the handshake failure occurring between the client and server. Because of the way SSL and the Java PrintWriter class work, the handshake gets initiated the first time PrintWriter.flush() is called, which happens as soon as the client sends a chat message to the server. This is only resolved by manually enabling supported ciphersuites in both the ClientThread (server) and ServerThread (client), then calling SSLSocket.StartHandshake() in at least the ClientThread, if not both.
Now the server is receiving messages from the client, but it is not echoing them out to the clients.
When I run it in a debugger and try stepping through the code I find that the ClientThread receives the client's message and sends it back by calling write() on the PrintWriter for each ClientThread, then flush(). The ServerThread is supposed to receive it by calling InputStream.available() to check for input without blocking, but available() always returns '0 bytes' and so it never hits Scanner.nextLine()
So either Printwriter.write() and .flush() aren't sending data or InputStream.available() is not reading data.
EDIT: After more debugging and testing, I can only narrow the problem down to output from the server side. I determined this by having the server immediately send its own message before waiting to receive messages, and had the client just grab the nextLine() instead of checking first with available(). Since this test failed it shows that data must be being blocked somehow coming from the server side only.
EDIT 2: I changed the code to use ObjectInputStreams and ObjectOuputStreams instead of using the Scanner and PrintWriters. Now I'm sending "Message" objects from a Serializable class I made to just hold Strings. This has fixed the output issue for messages coming from the server. If I make the client simply wait for input by calling readObject() it will receive messages from the server. However, if I use the availble() method of InputStream first, it still only returns 0 even when it shouldn't. Since the InputStream serverInStream is initialized by socket.getInputStream(), it gets an ssl.AppInputStream with an ssl.InputRecord, and I'm guessing one of the two does not implement available() correctly.
I figured it out: the problem was available(), It is useless with SSL in Java. I got the solution from this answer.
I have a made a socket connection between client and server. Everything is working good if i introduce the first comand on client, receiving the message i want from the server.
#server
public PrintWriter out;
out.println(res);
#client
public BufferedReader in = null;
String line;
line = in.readLine();
At the second time i run it won't show the message i send from server cause it will read \n so it will be an empty string. If i change this:
#server
out.println("\n"+res);
The first time i run now it will jump a line, printing just the \n. And the second time i run it will show the right message.
If i change now to:
out.println("\n\n"+res);
It will just show when i introduce something to send to the server and receive back after the 3rd time (the first 2 times it prints \n).
Don't know what to do to show always the message i send from the server. Any advice?
I started to learn about server-client application and I used this Java code example for client and server:
http://docs.oracle.com/javase/tutorial/networking/sockets/examples/EchoServer.java
http://docs.oracle.com/javase/tutorial/networking/sockets/examples/EchoClient.java
I ran both applications on two instances of Eclipse.
The code remain the same, except for the change:
//out.println(inputLine);
System.out.println(inputLine);
In the server side.
And to the printings "Hello", "Bye" in the beginning and end of the main() in the server-side. And of course, I set the IP used by the Client to the IP of my computer (used ipconfig - not unique IP)
From what I understand, everything the client sends should appear on the server standard output until the client types "Cntrl C" (unless I understand wrong).
here is the input I wrote in the client side:
boooooooooo
baaaaaa
paaaaaaa
And this is what I get in the Server-side:
Hello
boooooooooo
Something in here is unexpected to me-
the server seem to run in the main(),
but from some reason after the first printing it stops.
I tried o set breakpoints inside the Client side code on the while-line
while ((userInput = stdIn.readLine()) != null) {
out.println(userInput);
System.out.println("echo: " + in.readLine());
}
but the program flow encountered the while only twice an then didn't reach there anymore.
when it did enter in, userInput was not evaluated, I suspect because readline() returned null. But why should it? if EOF character wasn't inserted to the standard input in the Client side.
I'm very new to networking in java and wanted to create a network chat program, I have found a few tutorials online and kind of drifted from that. I have the server of my program working and the only thing that is interfering is when I try to read the chat messages that the server sends over. The server does send the bytes of data over since the print message does work. So the problem is that the while loop never ends, what can this be a problem of?
public String[] updateChatDialog() throws IOException{
String returnString = "";
int accessed = -1;
while((accessed = in.read()) > 0){
System.out.println((char)accessed);
returnString = returnString + (char)accessed;
}
System.out.println(returnString);
return stringToTable(returnString);
}
Any tips on java networking would be helpful!
I do reset the BufferedInputStream every time the chats are rendered into a string, AKA the method above with the return in it.
The 'problem' is that your loop reads until end of stream, and the peer isn't closing the connection so EOS never arrives.
If you want to read messages you have to define them yourself. The easiest thing for you to do in this application is write and read lines, with e.g. PrintWriter.println() and BufferedReader.readLine().