How can DataInputStream reads from HttpURLConnection? - java

in = new DataInputStream(conn.getInputStream());
String str = "";
while (in.available() > 0) {
str += in.readUTF();
}
in = new DataInputStream(conn.getInputStream());
String str = "";
while (in.available() > 0) {
str2 += Bytes.toString(in.readBytes());
}
I cannot read any response from my php page with two methods above.
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
String str2="";
while ( (str += in.readLine()) != null && in.ready()){}
And only this method can works.
Can someone tell me what it is happening either there's the problem of inputstream ,type or charset. Thanks!!

readUTF() can only read data that was written by writeUTF(). Unless you know that the server is sending data in that format you should not use it. It isn't a general-purpose string-reading method.
Possibly you're looking for BufferedReader.readLine(), but without knowing your application payload protocol it is impossible to be sure.
while ( (str += in.readLine()) != null && in.ready()){}
+= is the wrong operation here. It makes it impossible for the following null test to ever be true. Use =, and append inside the loop. The ready() test is futile here too. What you're testing here is (a) a line was returned and (b) some further data is pending ready to be read without blocking. You don't care about (b). Remove that. You probably meant to write the tests in the opposite order, but it would still be futile. Just block in readLine(). Set a read timeout if you don't entirely trust the server.

Related

Separating Get request Response body in java Socket programming

I'm trying to write a curl like program using java, which uses only java socket programming (and not apache http client or any other APIs)
I want to have the option of showing whole or only the body of the response to my get request to user. Currently came up with the following code:
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String t;
while ((t = br.readLine()) != null) {
if (t.isEmpty() && !parameters.isVerbose()) {
StringBuilder responseData = new StringBuilder();
while ((t = br.readLine()) != null) {
responseData.append(t).append("\r\n");
}
System.out.println(responseData.toString());
parameters.verbose = false;
break;
} else if(parameters.isVerbose())// handle output
System.out.println(t);
}
br.close();
When the verbose option is on, it works quick and shows the whole response body in less than a second. but when I want to just have the body of the message it takes too much time(approx 10 sec) to hand it out.
Does any one knows how can it be processed in a faster way?
Thank you.
I'm going to assume what you mean by slow is that it starts displaying something almost immediately but keeps on printing lines for a long time. Writing to the console takes time, and you're printing each line invidually while in the other code path you first store the entire response in memory and then flush it to the console.
If the verbose response is small enough to fit in memory, you should do the same, otherwise you can decide on an arbitrary number of lines to print in batches (i.e; you accumulate n lines in memory and then flush to the console, clear the StringBuilderand repeat).
The most elegant way to implement my suggestion is to use a PrintStream wrapping a BufferedOutputStream, itself wrapping System.out. All my comments and advices are condensed in the following snippet:
private static final int BUFFER_SIZE = 4096;
public static void printResponse(Socket socket, Parameters parameters) throws IOException {
try (BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream printStream = new PrintStream(new BufferedOutputStream(System.out, BUFFER_SIZE))) {
// there is no functional difference in your code between the verbose and non-verbose code paths
// (they have the same output). That's a bug, but I'm not fixing it in my snippet as I don't know
// what you intended to do.
br.lines().forEach(line -> printStream.append(line).append("\r\n"));
}
}
If it uses any language construct you don't know about, feel free to ask further questions.

Error reading from a socket in java

On the one side of the socket I know the data is going into the socket correctly.
I set up a connection:
Connection sr = new Connection();
Server server = new Server("NAME", Interger.parseInt(port));
server.setIp(ip);
sr.setServer(server);
//I know my server connection code is correct because I can send and receive data in
//other areas of my program just fine
InputStream is = null;
try
{
is = sr.getChannel().socket().getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuffer text = new StringBuffer();
int k =0;
while(k != -1)
{
k = br.read();
text.append((char) k);
}
}
catch(Exception e)
{
//no errors ever get thrown
}
And then I only get about half my data, 10989 bytes out of a total 21398 that I send. The amount of bytes it reads varies but the data always ends with ..., "values": [" which in the data I send over looks like , ..., "values": ["", ""].
Keep reading until you have all the data. This question has been showing up about once a week lately. There's no guarantee that the network is going to have all your data show up at once.
You need to keep reading until you have all your data. How do you know how much data was sent? You should probably build a little protocol between the client/server that defines how much data is going to be sent, the server reads that little header and continues to read until the full message has been received.
Don't know if this could help you :
int k =0;
while((k = br.read()) != -1){
text.append((char) k);
}
1) In your case it is making the check on the next iteration, which may lead to appending of non-representable character(char of -1) to the end of text.
2) Never leave catch block empty, may be there is some execption.
So because my sending side of the socket was in c++ I was accidentally passing in a null ASCII value into the socket. And it is undocumented on the java side of the socket that if the read encounters a null value it treats it as an end of file. So it was prematurely ending the stream because it hit the null.

BufferReader readline() method hangs for system.in

I am executing a simple java application in eclipse.
Sample code:
BufferedReader input = new BufferedReader( new InputStreamReader(System.in));
String line;
while((line = input.readLine()) != null && line.length() != 0)
{
System.out.println("------"+line);
}
In the above code the readline() method hangs when reading the last line of my input.
I have gone through some threads and understood that it waits for the end of line.
I don't want to give any '\n' or '\r' at the end of my input in the console.
so how to handle this in the code.
How is the code to know when you are not going to type anything else unless you press enter?
There is no solution to this issue. You need to re-think your use-case.

Java: Getting multiple lines from socket

I have a Java application that consists of a client and a server. The client sends encrypted commands to the server, and the server executes them.
The problem that I am having right now is that, with my encryption algorithm, sometimes the encrypted command contains "\n" or "\r" characters, which mess up my server code. This is because I am using the readLine() method, which stops when it finds a line terminator. What I need is a way to read all the characters the client sends into one string.
Here is my code:
public void run(){
System.out.println("Accepted Client!");
try{
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "ISO8859_1"));
out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), "ISO8859_1"));
String clientCommand = null;
while(RunThread){
// read incoming stream
do{
clientCommand = in.readLine();
}while(clientCommand == null);
//decrypt the data
System.out.println("Client: " + clientCommand);
if(clientCommand.equalsIgnoreCase("quit")){
RunThread = false;
}else{
//do something
out.flush();
}
}
}catch(Exception e){
e.printStackTrace();
}
}
Everything I've tried (various forms of nested loops using the read() function) hasn't worked. I would welcome any help or suggestions. Thanks, everyone!
I don't see encryption in the code you posted, but usually it's not a good idea to rely on separator characters.
When sending binary data, you should prepend the length of the data to the stream, and then you know exactly how many bytes to expect (and when the message will end.) It's more efficient to do things that way too instead of looking for a newline character.
// read incoming stream
do{
clientCommand = in.readLine();
}while(clientCommand == null);
That == null seems wrong
Try
String line = null;
do {
line = in.readLine ();
clientCommand += line
} while (line != null);
One thing you must do, when working with TCP/IP, is to send the message length before the actual message. The application level cannot foresee the package size the TCP level is delivering to the destiny. So, before your message, you have to send a header with the message size and the destiny would read just these bytes.
About readLine(), I think it's better use another approaches like streams. Shortly, one suggestion:
Socket oSocket = new Socket(sAddress, iPort);
PrintWriter out = new PrintWriter(oSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(oSocket.getInputStream()));
do{
clientCommand = in.readLine();
} while(clientCommand == null);
This makes no sense. readLine() only returns null at end of stream, so you are telling Java to loop infinitely at end of stream. I don't even understand why there is a loop at all. You don't want to ignore any input from the client, you want to process it all. You should read one line from the client, execute it, and read another line. Repeat until null, then close the socket.

Receiving mixed media over Java socket. Yours better?

I'm about to give a programming exercice in Java and I'd like my students to discover the intrinsics of HTTP themselves rather than having URLConnection doing all the job for them. In order to estimate the complexity, I came up with the following snippet, which parses the reply (imho, one of the hardest part of the job), which will return e.g. "HTTP/1.1 200 OK", push things like "Server: makato" and "content-length: 1337" in the headers vector and leave the InputStream at the first byte of the content, so that a DataInputStream or a InputStreamReader can later be built on top of it safely.
I'm curious to know if someone with more experience of the Java classes could suggest more elegant alternatives. One thing I'm not pleased with is that each individual is.read() will inevitably generate an additional system call (assuming that Socket.getInputStream() is used to feed is argument).
public static String recvHttpHeaders(InputStream is, Vector<String> headers)
throws Exception {
byte line[] = new byte[512];
String pending=null;
String status=null;
boolean complete=false, CR=false;
int n=0;
while (!complete) {
int x = is.read();
switch(x) {
case -1: throw new Exception("something went wrong");
case '\r':
if (CR) throw new Exception("encoding mismatch CRCR");
CR=true;
break;
case '\n': // bare LF are accepted silently.
String ln = new String(line,0,n,"ASCII");
if (pending!=null) ln = pending + ln;
if (status==null) status = ln;
else headers.add(ln);
complete = ln.length()==0;
pending = null;
n=0; CR=false;
break;
default:
if (CR) throw new Exception("encoding mismatch ?CR");
if (n>=512) {
String part = new String(line, "ASCII");
if (pending!=null) pending += part;
else pending = part;
n=0;
}
line[n++]=(byte)x;
break;
}
}
return status;
}
edit: admittedly, one would love to use xxx.readline() here to avoid messing up with lines reconstruction. BufferedReader (or any other *Reader, actually) converts bytes into chars according to one charset. That means I'm no longer free to chose that charset for the content if I used that feature in the header parsing. I haven't found any byte-level classes that has readline ability built-in.
performance solution: Thanks for pointing out BufferedInputStream. I made a few additional tests, and indeed, invoking as
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
String status = recvHttpHeaders(bis, headers);
rawCopy(bis, output);
indeed reduce the amount of system calls performed and still allow me to properly receive binary content unmodified.
You should rather use BufferedReader to read texts. Wrap your input stream:
BufferedReder br = new BufferedReader(new InputStreamReader(is));
Then use readLine() to read stuff line by line:
String line = null;
while((line = br.readLine()) != null) {
// deal with the line
}
Following comments of Sripathi Krishnan and Adam Paynter, the way to improve it is to use a BufferedInputStream, so that performance remains acceptable and no charset transformation happens.

Categories