The answer back comes as an InputStream from the server and thus it has to
be converted to ascii characters (I'm right, am I not?) before being
displayed.
The problem is that the while statement that I use to convert the bytes to
characters seems to, I dunno, get stuck.
I read in the API help that when
InputStream().read()
returns -1 (a single byte can't be negative) you have reached the end of the
InputStream and thus the while-loop should end.
The problem is that it seems to stop processing the InputStream when it has
reached its end but without leaving the while-loop (as it's supposed to do),
so the next part of the code (closing the socket, printing the string and
exiting the program) is never executed.
It's very confusing and driving me insane. Does anyone out there have any
idea why this is and what I should do about it?
Below is the code:
---------------------------------------
import java.net.*;
import java.io.*;
public class main {
public static void main(String args[]) {
x y = new x();
y.test();
}
}
class x {
void test() {
String text = new String();
try {
Socket s = new Socket("elvis.swip.net",110);
int number;
while ((number=s.getInputStream().read()) != -1) {
text = text + (char)number;
//converting from ascii code (the byte's value) to a character
System.out.println("Current string: "+text);
//displaying the string as characters are added to it
}
//<-- seems like it never gets out of this part, please help!
s.close();
System.out.println(text);
}
catch (IOException und) {System.out.println("Error");}
System.exit(0);
}
}
---------------------------------------
Perhaps it's some basic thing I'm doing wrong, but hey, I've just started -
so please help me out! :)
Thanx in advance...! :)
--
Mvh, Erik
E-mail: ruler_o...@cheerful.com
alt. mer...@hotmail.com
Homepage: http://www.meracl.com
& http://surf.to/partybilder
First off, I have never used InputStream before, so this may be useless.
Wouldn't the getInputStream reset the resulting InputStream to the
beginning? I would have done something like:
InputStream inStream = s.getInputStream();
while((number = inStream.read()) != -1)
Just a thought
--
MistWing SilverTail
Dragon Code
DC2.Dw Gf L6m3t5w W- T Phfwlt Sks,wl Cau+,bau,bl' Bfl/pl/zz A- Fr+++ Nn
M O/ H--- $ Fo R- Ac+ J+ S+ U! I--# V+++![Power] V---[Control] V++[Food
Fight Magic ++] Q+++[tk] Tc+++[sw] Tc+[other]
Furry Code
FMSmpsw3r A-- C- D H+ M- P R+ T+++ W- Z+ S- RLCT ca++$ d-- e+ f- h- i+
j+ p-- sx--
I've never used the Socket class before, but it presents an interesting
question. A quick look at the documentation tells me that the read() method
blocks until input is received, the stream is closed, or an exception
occurs. Since you are reading from a non-cooperating site, I suspect that
the stream is not being "closed" from the other end. In other words, I think
you are just waiting for more input.
I added some code to see what you were receiving and noted that the last two
characters received were a carriage return and a linefeed. Your data source
thinks it's done when it issues that.
Anyway, that's why you aren't exiting your loop.
I'm waiting to see what corrective actions are prescribed by the regulars
around here.
- Virgil
Weird huh?
"MistWing SilverTail" <Mist...@erols.com> wrote in message
news:a9qehg$fet$1...@bob.news.rcn.net...
That thing with the carriage return and a linefeed is the way you talk with
a POP3 server.
When you send data you always end your data string with carriage return +
linefeed and the same thing when data is recieved.
But what you are saying basically is that the POP3 server is evil because it
doesn't in any way announce that it's done sending data and therefor the
Socket class is waiting for more?
"Virgil Green" <v...@obsydian.com> wrote in message
news:he3w8.31$ab4.22...@newssvr12.news.prodigy.com...
>I'm thinking about writing this e-mail client and just tried to write a
>simple little code snippet that would connect to a POP3 server, take the
>message sent back from the POP3 server that the connection was succeful and
>just display it.
>
>The answer back comes as an InputStream from the server and thus it has to
>be converted to ascii characters (I'm right, am I not?) before being
>displayed.
>
>The problem is that the while statement that I use to convert the bytes to
>characters seems to, I dunno, get stuck.
>I read in the API help that when
>
>InputStream().read()
>
=>
> while ((number=s.getInputStream().read()) != -1) {
> text = text + (char)number;
>//converting from ascii code (the byte's value) to a character
> System.out.println("Current string: "+text);
>//displaying the string as characters are added to it
> }
>//<-- seems like it never gets out of this part, please help!
>
>
You're blocking on the read waiting for data or the stream to close.
TCP can wait a long time. Unlike UDP there aren't boundaries that
define that define a packet. It's a stream oriented protocol. Since
you are using 110 as port I presume you are trying to talk to a POP
server. You process the handshake a line at a time - a call and
response scenario. Once the niceties are satisfied the server will,
upon request send your mail terminating the transmission with a . on a
line by itself.
You might find it easier to use a stream handler with a readline
method.
If you haven't already read rfc1225 you might want to take a look.
StringBuffer buf=new StringBuffer();
Reader r=new InputStreamReader(s.getInputStream());
char c;
while ((c=r.read())!= -1) {
buf.append(c);
System.out.println("Read so far: "+buf);
}
(Note characters are 2 bytes in Java, readers will take care of the proper
conversion)
Now, the second (and more likely significant) part of your problem is a
matter of protocol. POP is most likely expecting some sort of interaction
from you: userid, password, requests, etc..., and thus the server is not
closing the socket because it is waiting for you. Strictly for testing
purposes, you could force your socket to time-out, and throw an IOException.
(You'll still need to close the socket yourself) Just use:
s.setSoTimeout(15000); //15 seconds
Then just catch the IOException, output what you've got, and close the
socket.
This should be enough to output the same screen you'ld get if you just
telnet directly to your POP server on port 110... You'll need to post
understood commands to the server from there.
Hope this helps!
Frank
"Erik Åkerlund" <ruler_o...@cheerful.com> wrote in message
news:3cc0b224$1...@news.mhogaming.com...
InputStream is an abstract class and read() is an abstract method that
must be spelled out by any subclass of InputStream, for example,
BufferedInputStream:
---------------------------------------------------------------------
import java.net.*;
import java.io.*;
public class SocketTest {
public static void main(String args[]) {
new X().test();
}
}
class X {
public void test() {
String text = new String();
try {
Socket s = new Socket("elvis.swip.net",110);
BufferedInputStream ins = new BufferedInputStream( s.getInputStream() );
int number;
while ((number=ins.read()) != -1) {
text = text + (char)number;
//converting from ascii code (the byte's value) to a character
System.out.println("Current string: "+text);
//displaying the string as characters are added to it
} catch( IOException ioe ) {
ioe.printStackTrace();
} catch( UnknownHostException uhe ) {
uhe.printStackTrace();
}
//<-- seems like it never gets out of this part, please help!
s.close();
System.out.println(text);
}
}
-----------------------------------------------------------------------------------
This code differs by assigning the result of Socket.getInputStream() to
a concrete Java class, BufferedInputStream. Here are some of the other
standard Java implementations of InputStream. You must use one of these or
write your own read() method.
class java.io.InputStream
class java.io.ByteArrayInputStream
class java.io.FileInputStream
class java.io.FilterInputStream
class java.io.BufferedInputStream
class java.util.zip.CheckedInputStream
class java.io.DataInputStream (implements java.io.DataInput)
class java.security.DigestInputStream
class java.util.zip.InflaterInputStream
class java.util.zip.GZIPInputStream
class java.util.zip.ZipInputStream (implements java.util.zip.ZipConstants)
class java.io.LineNumberInputStream
class java.io.PushbackInputStream
class java.io.ObjectInputStream (implements java.io.ObjectInput,
java.io.ObjectStreamConstants)
class java.io.PipedInputStream
class java.io.SequenceInputStream
class java.io.StringBufferInputStream
Good luck with learning Java.
- Tony Dahlman
The end of the input stream when you're talking to a socket means when
the socket has been closed. It doesn't mean when the other end just
hasn't sent any more data. This is your problem - the server has
indicated that it has finished *in the data*, and is waiting for you to
ask it another question.
> while ((number=s.getInputStream().read()) != -1) {
> text = text + (char)number;
This code needs reworking:
o Calling socket.getInputStream() repeatedly *may* be safe, but doesn't
strike me as a good idea. Call it once and get an inputstream to work
on, then keep using that one inputstream.
o As another poster mentioned, use a reader, converting with
InputStreamReader. However, the other poster didn't mention that you
should almost *always* specify the encoding when you use
InputStreamReader. Find out which encoding POP3 uses and specify that.
o Using BufferedReader and readLine will improve performance
o Avoid string concatenation like that within loops like the plague. See
http://www.pobox.com/~skeet/java/stringbuffer.html
(A single 100K message would have generated nearly 10 *gigabytes* of
memory churn using your method above.)
[I've removed comp.lang.java from the newsgroups list, as it doesn't
exist. See http://www.pobox.com/~skeet/java/newsgroups.html]
--
Jon Skeet - <sk...@pobox.com>
http://www.pobox.com/~skeet/
If replying to the group, please do not mail me too
This is definitely not the problem here. What you get back from
Socket.getInputStream() sure is a concrete class - it couldn't be anything
else.
For example, with my Sun JDK1.4, the output of
socket.getInputStream().getClass().getName()
prints "java.net.SocketInputStream", which is a concrete class extending
FileInputStream.
But in reality, all you know is that it is an InputStream, and that's
enough. Of course, if you want to do more than read raw bytes from it, you
wrap it in something else.
Michiel
While this is a good tip, it will only work if the server uses the same
encoding as the client platform. By default, InputStreamReader uses the
platform default. If they differ, you need to tell the InputStreamReader
which encoding to use, with the two arg constructor. I have no idea what
encoding POP3 servers use, but it's probably in the RFC.
HTH,
Michiel
I mean that it isn't a site under your control or working under any
agreement with you about when it will close the socket from its end other
than, maybe, some published standard. That published standard would the the
RFC identified by other posters.
> That thing with the carriage return and a linefeed is the way you talk
with
> a POP3 server.
> When you send data you always end your data string with carriage return +
> linefeed and the same thing when data is recieved.
>
> But what you are saying basically is that the POP3 server is evil because
it
> doesn't in any way announce that it's done sending data and therefor the
> Socket class is waiting for more?
I'm not saying it's evil. I'm saying that it hasn't closed the socket when
you expected it to. Others in the thread have now pointed out the need to
carry on the conversation. You are, indeed, sitting there waiting for data.
Oh, I get it. You are Michiel, not Erik. And you don't
need help. What is your solution, then, Michiel?
While yours is perhaps a valid statement, it might not be.
There is no way I am going to use JDK 1.4 till it's been
seasoned a bit.
Since this was Erik's question and he's the one who asked
for help, let's each of us post what we think and see what
helps Erik in the end, shall we?
- Tony Dahlman
No one suggested that you use JDK 1.4. It was merely pointed out that it
could be used to discover the true class of the returned InputStream. I get
the same result in JDK 1.3.
>
> Since this was Erik's question and he's the one who asked
> for help, let's each of us post what we think and see what
> helps Erik in the end, shall we?
Except that your response was nonsensical and others who might be mislead by
it should be warned. The InputStream reference returned by the
getInputStream method HAS to be a concrete class of some sort else it could
not have been instantiated. Your response wrapped another object around the
returned InputStream (actually a subclass of InputStream) but did not
"assign it to a concrete class." That had already happened when it was
instantiated, before it was returned.
You were merely corrected, and politely at that.
- Virgil
- Virgil
> Oh, I get it. You are Michiel, not Erik. And you don't
> need help.
I never claimed to be any kind of authority, did I?
Sorry for the confusion. :)
> What is your solution, then, Michiel?
Oh, that has already been posted: the connection isn't being closed, because
it shouldn't be. The fact that the server has stopped sending is indicated
by the data it sends, as defined in the RFC.
> While yours is perhaps a valid statement, it might not be.
> There is no way I am going to use JDK 1.4 till it's been
> seasoned a bit.
OK. The outcome would probably be the same for another JDK though. The point
is it doesn't matter, as long as getInputStream() upholds its contract of
returning an InputStream.
> Since this was Erik's question and he's the one who asked
> for help, let's each of us post what we think and see what
> helps Erik in the end, shall we?
Well, I thought that pointing out that your response was, in part,
incorrect, would be useful to both you and Erik. You'll never receive an
abstract class from any method, simply because you can't have an instance of
one. While a method can be declared to return an abstract type, the actual
class will always be concrete.
HAND,
Michiel
Erik Åkerlund wrote:
>
> InputStream().read()
>
> returns -1 (a single byte can't be negative) you have reached the end of the
> InputStream and thus the while-loop should end.
>
>
>
The -1 return code indicates an error from the IO call, I would
recommend exception handling that checks for the return code of the call.
something like ------ if(isReturnCode < 0) { throw IOException(e) }
else
{ the rest of your processing code }
No it doesn't - it indicates that the end of the stream has been reached, as
the above quote from the documentation says.
[Removed comp.lang.java, which isn't a valid newsgroup.]
(Also, as another poster noted if you are connecting to a POP3 server you
need to follow the correct protocol -- ie reading and writing the correct
number/format of bytes. -- and there is a setencoding function for certain
types of streams, most protocols use standard 8bit ASCII encodint which is
specified in Java as UTF-8 I beleive.)
Good luck,
--Russ
"Erik Åkerlund" <ruler_o...@cheerful.com> wrote in message
news:3cc0b224$1...@news.mhogaming.com...
> int number;
>
> while ((number=s.getInputStream().read()) != -1) {
> text = text + (char)number;
> //converting from ascii code (the byte's value) to a character
> System.out.println("Current string: "+text);
> //displaying the string as characters are added to it
> }
> //<-- seems like it never gets out of this part, please help!
>
>
> s.close();
> System.out.println(text);
> }
#########
Hey, had a look at your code. The problem is that after you have read the
message the server returns to you it waits for some input. i.e. a username.
The character that the mail client recieves last is 10. The ASCII code for
a newline. To get out of the loop you need to look for this and not -1.
New code included below. Hope this helps.
Rafe
#########
import java.net.*;
import java.io.*;
public class main {
public static void main(String args[]) {
x y = new x();
y.test();
}
}
class x {
void test() {
String text = new String();
try {
Socket s = new Socket("elvis.swip.net",110);
int number;
while ((number=s.getInputStream().read()) != 10) { // checks for
newline character
System.out.println(number);
text = text + (char)number;
System.out.println("Current string: "+text);
System.out.println("in while loop"); //debugging code
//converting from ascii code (the byte's value) to a character
//displaying the string as characters are added to it
}
s.close();
System.out.println("out of while loop"); //debugging code
System.out.println(text);
}
//if error occurs, prints out stack trace and gives abnormal exit signal
catch (IOException e) {
System.err.println("Error");
e.printStackTrace();
System.exit(1);
}
//normal exit
System.exit(0);
}
}