I'm a real newbie to java, so please excuse me if this is a hopelessly straightforward problem.
I have the following from my java game server:
// Get input from the client
DataInputStream in = new DataInputStream (server.getInputStream());
PrintStream out = new PrintStream(server.getOutputStream());
disconnect=false;
while((line = in.readLine().trim()) != null && !line.equals(".") && !line.equals("") && !disconnect) {
System.out.println("Received "+line);
if(line.equals("h")){
out.println("h"+EOF); // Client handshake
System.out.println("Matched 1");
}else if (line.equals("<policy-file-request/>")) {
out.println("..."+EOF); // Policy file
System.out.println(server.getInetAddress()+": Policy Request");
disconnect=true;
System.out.println("Matched 2");
}else if(line.substring(0,3).equals("GET")||line.substring(0,4).equals("POST")){
out.println("HTTP/1.0 200 OK\nServer: VirtuaRoom v0.9\nContent-Type: text/html\n\n..."); // HTML status page
disconnect=true;
System.out.println("Matched 3");
} else {
System.out.println(server.getInetAddress()+": Unknown command, client disconnected.");
disconnect=true;
System.out.println("Matched else");
}
}
server.close();
First of all, the client sends an "h" packet, and expects the same back (handshake). However, I want it to disconnect the client when an unrecognised packet is received. For some reason, it responds fine to the handshake and HTML status request, but the else clause is never executed when there's an unknown packet.
Thanks
From the information added in your comments it seems that what will be happening is the client is sending a single character (e.g. 'n'). The line
line.substring(0,3).equals("GET")||line.substring(0,4).equals("POST"))
will be executed, but since line is only a single character line.substring(0,3) will throw a StringIndexOutOfBoundsException. Either this is causing your program to fail and you haven't mentioned that. Or you have some exception handling going on in another part of your code that you haven't shown and this is either supressing the error or printing a log line or something and again you haven't mentioned this (or noticed it).
Try replacing substring().equals with startsWith
You need to check for null before you trim it. The result of trim() can never be null.
You should check disconnect first, before the readLine(), otherwise you are always doing one readLine() too many.
If you are never getting to your 'else' it means one of the other conditions is always true.
There are a number of problems with your code
in.readLine().trim()
readLine do returns null and calling null.trim() will result in ... NullPointerException
Is there a reason to append EOF to every response you send.
calling substring without making sure it has at least that much elements will throw StringIndexOutOfBoundsException if it is shorter.
Are you testing with "P" for example?
It would seem highly unlikely that the else is not executing. Are you sure your loop does not exit on such packets and hence your conditions do not even run? Does your
System.out.println("Received "+line); print anything for the packet that seems to be missing the else statement?
Related
I want to check if the InputStream buffer contains any data which it can read and output without having to initially call readLine() and waiting for data.
I have looked into available() but this didn't seem to work as it always output 0.
while (true)
{
fromServer = in.readLine(); //Causing a hang waiting for reply
System.out.println(fromServer);
if ((fromUser = stdIn.readLine()) != null)
{
out.println(fromUser);
fromServer = in.readLine();
System.out.println(fromServer);
}
}
available() might tell you the number of bytes available, if implemented, but nothing can tell you whether there is a complete line other than trying to read it.
You need to read in a separate thread.
The issue is readLine() causes the client to get stuck hanging for a server reply if access isn't permitted for the client.
So the issue is really that the server should send something 'if access isn't permitted for the client', i.e. a message that says so, rather than doing nothing. You can't use absence of a message as a message in a blocking I/O system.
You also need to check every readLine() result for null, and if you get it when reading a socket you need to close it.
Create a new Instance of BufferedInputStream and call available on that object:
InputStream is = ...;
BufferedInputStream bis = new BufferedInputStream(inputStream);
if (bis.available() == 0) {
// do sth if input is available
}
I tried it with a little server-client application, it worked for me.
EDIT: Type mismatch gone.
As the Java Documentation says, the InputStream.available() always returns zero. In comparison to that, the BufferedInputStream returns „the number of bytes remaining that can be read in the buffer“
I'm writing a simple tcp stream SMTP server. I wrote following code to check if the client connection is still available. Simply peeking one byte to see if socket input stream is working. But when I set in.mark(x) read ahead limit to 1, it shows error when I attempt to send Header for the second time. When it's set to 2, it doesn't seem to have any problem at all. Why is this?
// check if client disconnected
try {
in.mark(1); // 1 char read ahead limit
if (in.read() == -1) {
System.out.println("CONNECTION CLOSED BY CLIENT!");
return; // end of thread
} else {
in.reset();
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
The error I get is this:
java.io.IOException: Mark invalid
at java.io.BufferedReader.reset(BufferedReader.java:512)
at smtp.server.SocketThread.run(SocketThread.java:59)
The entire code is on my github.
Forget it. Just read and write, and deal with the exceptions as they arise.
At present you are engaged in fortune-telling. Even if you find a method that works to tell you whether the client connection is alive now, it could go down between calling this method and the very next line of code.
The only method that actually works of trying to detect whether a resource is available is to try to use it in the normal way.
In most Java client/server examles they use ServerSocket.accept() method to receive messages from the client. This method blocks the thread. This looks good becouse server does not do useless work and can answer immediately. But on the client side they use infinite loop like this:
BufferedReader in = new BufferedReader (new InputStreamReader (socket.getInputStream ()));
while (true)
{
String cominginText = "";
try
{
cominginText = in.readLine ();
System.out.println (cominginText);
}
catch (IOException e)
{
//error ("System: " + "Connection to server lost!");
System.exit (1);
break;
}
}
This looks bad because in my mind client does useless work.
Is there some way to receive a message on the client side without doing useless work and immediately like on server side (may be should use listeners?)
"What do you mean by useless work? – Braj 31 mins ago "
for example checking in loop is button pressed (we should use listener)
while (!button.isPressed() ) { } is bad way.
There is no 'useless work' here, as the socket is in blocking mode, but there is:
A pointless initialization of 'comingText'.
A failure to check it for null, so it will spin mindlessly at EOS.
An incorrect handling of IOExceptions: not all of them are fatal, e.g. SocketTimeoutException, and none of them should cause an immediate System.exit().
The line read is thrown away, which is an application protocol error.
So it is definitely wrong.
in.readLine() blocks. The loop wont continue until a String returns
I have noticed that in a few pieces of example code for a TCP chat program, written in Java, both the read string from client and send string to server both occur in main.
For example, here is a tutorial where I don't see the distinction between an input thread and in output thread... http://www.cise.ufl.edu/~amyles/tutorials/tcpchat/TCPChat.java
"BufferedReader input" and "PrintWriter output" are both used with a TCP Socket from within the same thread. As a complete novice, this confuses me because previously, if I had something that waits for input, like the "getch()" get character function from C, that thing that will hold up the thread (unless it is an event or an exception). Normally, when I imagine code in a thread being executed, I imagine it being executed line by line, with occasional jumps in execution for exceptions and events. But writing to a stream and reading from a stream is neither an exception nor an event - I don't know what the main thread would do if it received an input string and was supposed to send out an output string both at the same moment. Is the stream itself actually handled by some other thread or some other program, like the terminal or the OS?
I had felt so weird about this that I split the chat program into two separate threads to make me feel more comfortable - one thread for receiving strings from the TCP socket and another thread for sending strings out through the same socket. Can someone provide an explanation as to why my act of splitting input and output into two separate threads is totally unnecessary? And before someone marks this down due to lack of research and understanding, I did my best to read online Java tutorials on Sockets and I have had experience writing to and reading from streams (terminal and plain text file).
case CONNECTED:
try {
// Send data
if (toSend.length() != 0) {
out.print(toSend); out.flush();
toSend.setLength(0);
changeStatusTS(NULL, true);
}
// Receive data
if (in.ready()) {
s = in.readLine();
if ((s != null) && (s.length() != 0)) {
// Check if it is the end of a trasmission
if (s.equals(END_CHAT_SESSION)) {
changeStatusTS(DISCONNECTING, true);
}
// Otherwise, receive what text
else {
appendToChatBox("INCOMING: " + s + "\n");
changeStatusTS(NULL, true);
}
}
}
}
catch (IOException e) {
cleanUp();
changeStatusTS(DISCONNECTED, false);
}
break;
I took this code snippet from the "main procedure" of the link you provided.
The method that would halt the thread from continuing like you were talking about is in.readLine(); The thread would wait until there was something to read from the input stream before continuing. I would like to point out the if statement " if(in.ready()) " By having that if statement there, the code checks first if the input stream has something to read. Otherwise, it skips over it and continues.
Events are being forwarded to a client socket, which is being read by the code below. Most of the time the code works as expected. Sometimes a data packet is sent to the socket which causes the readline to unblock with a null message. From that point forward, the readline call never blocks again, causing a CPU spike. I have verified with code that the socket is not closed, the input stream has not been shutdown, isSocketClosed and isInputShutdown both return false. The ready call is just an attempt to see what's happening, the read call always returns -1. The socket is still accepting data, new valid packets come in, processed correctly, but the readline never blocks again. Any idea how why readline is behaving this way?
while (!this.isInterrupted())
{
String message = null;
do {
message = reader.readLine();
if ( message != null && message.length() > 0 ) {
//if ( log().isDebugEnabled())
log().info( "Got a message, raw data: " + message );
createEvent( message );
}
} while ( message != null && !this.isInterrupted());
if(!reader.ready()) {
log().info("Bytes read: " + reader.read());
Thread.sleep(1000);
}
}
BufferedReader.readLine() returns null when the other end closes the connection.
If it is not doing this you have a particularly bug JVM. I would make sure you have the latest update.
I have verified with code that the socket is not closed, the input stream has not been shutdown, isSocketClosed and isInputShutdown both return false
This just means your end didn't close() the stream. It doesn't tell you anything about the other end of the stream.
The ready call is just an attempt to see what's happening, the read call always returns -1
This also means you have an end of stream.
Just a small thing, but if you have empty (not null) strings coming in on your socket, they won't fall under if ( message != null && message.length() > 0 ).
You might wanna change it to if ( message != null ).
The reason this happens comes from the String#length() method:
Returns the length of this string. The length is equal to the number
of Unicode code units in the string. #return the length of the
sequence of characters represented by this object.
You have a bug in your code. If readLine() returns null, it means the peer has closed the connection. You must do likewise and exit the loop. Once it has returned null, it will never block again, and it will never stop returning null.
The part of your loop that tests ready() and sleeps is literally a compete waste of time. Remove it.