Java. BufferedInputStream working with images - java

I'm trying to write server and client sides on java.
So, client side sends request like GET / HTTP/1.0, server side responses(if file exists) like HTTP/1.0 200 OK, put in header content-type and content length and writes to the BufferedOuputStream the stream from FileInputStream.
Server side:
String endLine = "\r\n";
File f = new File(fileName);
FileInputStream fstream;
fstream = new FileInputStream(f);
response = "HTTP/1.0 200 OK" + endLine;
header = "Content-type: "+ contentType + endLine + "Content-length: " + f.length() + endLine + endLine;
bout.write(response.getBytes());
bout.write(header.getBytes());
int lol;
while((lol = fstream.read(buffer)) != -1) {
bout.write(buffer,0,lol);
}
System.out.println("Message sent");
bout.flush();
socket.close();
Client side:
byte[] res = new byte[bufferSize];
int got;
int i=0;
int temp = 0;
int j = 0;
while((got = bis.read(res))!=-1){
for(j=0;j<res.length;j++){
//dividing from header
if(res[j]=='\n'&&res[j-1]=='\r'&&res[j-2]=='\n'&&res[j-3]=='\r'){
temp = j+1;
}
}
fout.write(res,temp,got-temp);
i++;
}
So, with .html files it works fine, but with images...
Found the solution. The error was on offsets:
fout.write(res,temp,got-temp);
This line adds the offsets on every iteration. I need only on first:
if(i==0){
fout.write(res,temp,got-temp);
}else{
fout.write(res,0,got);
}

You should not parse the contents checking for new lines etc when transferring binary data, your pictures also contains these \n r characters

Related

How to get the file name from an RRQ datagramPacket?

Im working on a TFTP server. Basing on the image the max length of my packets is 516 bytes (2+2+512).
I'm trying to take the original length from the client datagrampacket(in this case sends 13 bytes in a RRQ packet), instead im getting the server datagrampacket length (516 bytes) where i save the client datagrampacket.
I need that for extract the filename, i did that but the string content is "filename + nullBytes", those null bytes come from the server datagrampacket.
This is the code where im stuck:
public static short RRQ = 1;
enter code here
public void dataMetod() throws IOException{
byte[] packet = new byte[516];
//socket with listening port 5000
DatagramSocket datagramSocket = new DatagramSocket(5000);
//while receive packets
while (true) {
DatagramPacket datagramPacket = new DatagramPacket(packet,packet.length);
datagramSocket.receive(datagramPacket);
System.out.println("server: new packet!!:");
//create a byte[] with the "received packet length"(that's not true)
byte[] inData = new byte[datagramPacket.getLength()];
inData = datagramPacket.getData();
System.out.println("length: "+inData.length);
byte code;
code = inData[1];
System.out.println(code);
//check if its an RRQ packet
if (code == RRQ) {
System.out.println("server: RRQ PACKET!!");
String fileName = this.getFileName(inData);
System.out.println(fileName);
}
public String getFileName(byte[] inData) {
byte[] aux = new byte[inData.length - 7];
for (int i = 0; i < aux.length; i++) {
aux[i] = inData[i + 2];
}
return new String(aux);
}
http://i.stack.imgur.com/6dTH6.png
Try this:
public String getFileName(byte[] inData) {
final int maxLen = inData.length;
final StringBuilder sb = new StringBuilder();
int i = 2;
byte b;
while ( (i < maxLen) && (b = inData[i]) != 0 ) {
final int v = ((int)b) & 0xff;
sb.append( (char) v );
i++;
}
return sb.toString();
}
Instead of getting the original length of the received packet(to search the file name through the array), we could do that by adding "\n" at fileName String in client class, then use BufferedReader which will detect "\n" and save the fileName.
Code:
public String getFileName(byte[] inData) throws IOException {
//get a sub-array, from index[2] (beacuse we dont want opCode) to inData length
byte[] b =Arrays.copyOfRange(inData, 2, inData.length);
InputStream is = new ByteArrayInputStream(b);
BufferedReader bf = new BufferedReader(new InputStreamReader(is));
//We read a word that will be saved when "\n" is found.
//(adding "\n" previously to the fileName String in client class)
String filename = bf.readLine();
bf.close();
is.close();
System.out.println("server: filename is: "+filename.length()+" bytes");
return filename;
}

ClosedChannelException on Socket

I am trying to build a TCP/IP sniffer for android using VpnService.I modified ToyVpn example I am correctly getting the output IP packet from the descriptor and for the moment I am just trying to send it to the destination socket without IP and TCP headers and show in Log the response from the destination server. Actualy, what I have to do is to deliver the packet in the network and when I have a response write it in the OutputStream coresponding to the ParcelFileDescriptor.
I am using this code:
while (vpnInterface != null && vpnInterface.getFileDescriptor() != null
&& vpnInterface.getFileDescriptor().valid()) {
packet.clear();
// Read the outgoing packet from the input stream.
final byte[] data = packet.array();
int length = in.read(data);
//use this to get the unsigned byte
int[] d = new int[data.length];
if (length > 0) {
packet.limit(length);
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < data.length; i++) {
d[i] = data[i] & 0xFF;
sb.append(d[i] + " ");
}
Log.i("packet", sb.toString());
Socket socket = SocketChannel.open().socket();
if ((null != socket) && (null != this)) {
this.protect(socket);
}
//connect to dest ip and port
socket.connect(new InetSocketAddress(d[16] + "." + d[17] + "."
+ d[18] + "." + d[19], (d[22] * 256) + d[23]));
DataOutputStream dOut = new DataOutputStream(
socket.getOutputStream());
DataInputStream dIn = new DataInputStream(
socket.getInputStream());
dOut.write(data, 40, data.length - 40);
dOut.flush();
dOut.close();
length = dIn.read(data);
if (length > 0) {
sb = new StringBuilder("");
for (int i = 0; i < data.length; i++) {
d[i] = data[i] & 0xFF;
sb.append(d[i] + " ");
}
Log.i("response", sb.toString());
dIn.close();
}
}
Thread.sleep(10);
}
The problem is that I get ClosedChannelException when trying to read the InputStream from the socket. Do you have any ideea why is this happening? The ideea is that I don't know how to manage the input packets from the dest socket.
Sorry if I made any mistake but I am beginner in JAVA.
You're closing the InputStream that you've got from the Socket. JavaDoc says:
Closing the returned InputStream will close the associated socket.
Usually, you should never close a stream that you do not own!
The same is true for the OutputStream you get with socket.getOutputStream(). If you close it, the socket will be closed too!

While reading from socket how to detect when the client is done sending the request?

I am now writing a http server and I am having problem with reading from a socket.
My problem is that the inputStream from the client never ends and it keeps reading until the client is closed.
I know that the client doesn't close the connection with the server immediately after sending the http request.
How can I quit the while loop when client has sent all the request data (i.e. headers + body).
while (in.hasNextLine()) {
String line = in.nextLine();
if (line.equals("")){ // last line of request header is blank
break; // quit while loop when last line of header is reached
} else {
request = request + line + "\n";
}
}
After reading comments and answer from you guys, this is what I came up with,
is = incoming.getInputStream();
os = incoming.getOutputStream();
in = new Scanner(is);
out = new DataOutputStream(os);
RequestHandler rh = new RequestHandler();
int length = 0;
while (in.hasNextLine()) {
String line = in.nextLine();
if (line.equals("")) { // last line of request message
// header is a
// blank line
break; // quit while loop when last line of header is
// reached
}
if (line.startsWith("Content-Length: ")) { // get the
// content-length
int index = line.indexOf(':') + 1;
String len = line.substring(index).trim();
length = Integer.parseInt(len);
}
request = request + line + "\n";
}
byte[] body = new byte[length];
int i = 0;
while (i < length) {
byte b = in.nextByte();
body[i] = b;
i++;
}
but, I still don't get it about reading by bytes. I can write my code to read until -1, but still stuck when there is no EOF and client is not closing connection.
There are 3 ways of detecting the end of the stream depending on what requests you are handling:
If it is a GET or HEAD request, you only need to read the HTTP headers, request body is normally ignored if it exists, so when you encounter \r\n\r\n, you reach the end of the request(actually the request headers).
If it is a POST method, read the Content-Length in the header and read up to Content-Length bytes.
If it is a POST method and the Content-Length header is absent, which is most likely to happen, read until -1 is returned, which is the signal of EOF.
I've got it :) Thank you guys for comments and answers...
is = incoming.getInputStream(); // initiating inputStream
os = incoming.getOutputStream(); // initiating outputStream
in = new BufferedReader(new InputStreamReader(is)); // initiating
// bufferReader
out = new DataOutputStream(os); // initiating DataOutputSteream
RequestHandler rh = new RequestHandler(); // create a
// requestHandler
// object
String line;
while ((line = in.readLine()) != null) {
if (line.equals("")) { // last line of request message
// header is a
// blank line (\r\n\r\n)
break; // quit while loop when last line of header is
// reached
}
// checking line if it has information about Content-Length
// weather it has message body or not
if (line.startsWith("Content-Length: ")) { // get the
// content-length
int index = line.indexOf(':') + 1;
String len = line.substring(index).trim();
length = Integer.parseInt(len);
}
request.append(line + "\n"); // append the request
} // end of while to read headers
// if there is Message body, go in to this loop
if (length > 0) {
int read;
while ((read = in.read()) != -1) {
body.append((char) read);
if (body.length() == length)
break;
}
}
request.append(body); // adding the body to request
I want to share my code that works great:
private static String getClientRequest(Socket client) throws IOException, SocketException {
System.out.println("Debug: got new client " + client.toString());
BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));
StringBuilder requestBuilder = new StringBuilder();
String line;
int contectLegnth = 0;
while (!(line = br.readLine()).isBlank()) {
requestBuilder.append(line + "\r\n");
if (line.toLowerCase().startsWith("content-length")) {
contectLegnth = Integer.parseInt(line.split(":")[1].trim());
}
}
StringBuilder requestBodyBuilder = new StringBuilder();
if (contectLegnth > 0) {
int read;
while ((read = br.read()) != -1) {
requestBodyBuilder.append((char) read);
if (requestBodyBuilder.length() == contectLegnth)
break;
}
requestBuilder.append("\r\n" + requestBodyBuilder);
}
return requestBuilder.toString();
}

How to send file in parts using header "Range"?

I would like to send big file by dividing it to small parts and send them separately.
I tried to use the hedder "Range" and got "org.apache.http.client.NonRepeatableRequestException: Cannot retry request with a non-repeatable request entity".
// create authenticate client
DefaultHttpClient client = new DefaultHttpClient();
// create HTTP put with the file
HttpPut httpPut = new HttpPut(url);
final File recordingFile = new File(mDir, mName);
long fileLength = recordingFile.length();
for (int i=0; i < fileLength; i += 4096) {
int length = Math.min(4096, (int)recordingFile.length() - i);
InputStreamEntity entity = new InputStreamEntity(inputStream, length);
httpPut.setEntity(entity);
httpPut.addHeader("Connection", "Keep-Alive");
httpPut.addHeader("Range", "bytes=" + i + "-" + (i + length));
// Execute
HttpResponse res = client.execute(httpPut);
int statusCode = res.getStatusLine().getStatusCode();
}
I also tried "Content-Range" header (instead of "Range") and I got the same exception.
httpPut.addHeader("Content-Range", "bytes=" + i + "-" + (i + length) + "/" + fileLength);
httpPut.addHeader("Accept-Ranges", "bytes");
You repeatedly send multiple of 4096 bits. E.g. let's take the first two steps:
i = 0
Send range 0-4096
i = 4096
Send range 4096-8192.
Fix this lines:
for (int i=0; i <= fileLength; i += 4097) {
int length = Math.min(4096, (int)recordingFile.length() - i + 1);
/*...*/
}
and it should work fine.
Update:
Maybe the problem is that for some reasons (e.g. authentication failure) it tries to resend the same chunk again, in which case the inputstream is already consumed.
Try using a ByteArrayEntity instead of InputStreamEntity, something like this:
ByteArrayInputStream bis = new ByteArrayInputStream(recordingFile);
for (int i=0; i <= fileLength; i += 4097) {
int length = Math.min(4096, (int)recordingFile.length() - i + 1);
byte[] bytes = new byte[length];
bis.read(bytes);
ByteArrayEntity entity = ByteArrayEntity(bytes);
/*...*/
}

Java stream socket can only send once

I'm writing a simple download accelerator. The problem is I can send and receive messages once. The next time I try to send and receive message, I get no response froms server. I'm not even sure if I am able to send the second message.
The first message is something like;
*HEAD /TIPS/LAWLER/PANOHOW2.PDF HTTP/1.0\r\n
HTTP/1.0\r\n
Connection: close\r\n
\r\n*
and response is;
*HTTP/1.1 200 OK
Date: Mon, 24 Jan 2011 10:53:38 GMT
Server: Apache
Last-Modified: Tue,
22 Sep 1998 13:19:52 GMT
ETag: "1968013-2b4f4-3386e15b6ee00"
Accept-Ranges: bytes
Content-Length: 177396
Connection: close
Content-Type: application/pdf*
When i attemp to sen message;
GET /TIPS/LAWLER/hedeh/PANOHOW2.PDF HTTP/1.0\r\n
Range: bytes=0-44349\r\n
Connection: close\r\n
\r\n
I get nothing.
What is wrong with my code?
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
//Parse URL
String cmd = "http://www.imaging-resource.com"; //Host Name
if (cmd.contains("http://"))
{
cmd = cmd.substring(7); //
if (cmd.contains("/"))
{
int index = cmd.indexOf("/");
cmd = cmd.substring(0, index);
System.out.println(cmd);
}
}
String str = "HEAD /TIPS/LAWLER/PANOHOW2.PDF HTTP/1.0\r\nConnection: close\r\n\r\n"; //First message to send
//Create socket, connect, initialize read and write handlers
//in, out
Socket socket = null; //Create a client socket
SocketAddress sockaddr = null;
InetAddress address = null;
InputStream input = null; //Input handler
OutputStream output = null; //Output handler
try
{
address = InetAddress.getByName(cmd); //Get ip using host name
socket = new Socket(); //Contrusct Socket
sockaddr = new InetSocketAddress(address, 80);
//socket.setTcpNoDelay(false);
socket.connect(sockaddr, 2000); //Connect to server set and timeout to 2 sec
} //End of try Block
catch (Exception ex)
{
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
System.out.println(ex);
} //End of catch Block
if (!socket.isConnected())
{
System.out.println("not connected");
System.exit(-1);
}
//Sending package here
try
{
int c;
byte[] buf = new byte[65535];
char[] chr = new char[65535];
input = socket.getInputStream(); //Input handler is created
output = socket.getOutputStream(); //Output handler is created
buf = str.getBytes(); //HEAD message converted into byte array
output.write(buf); //Sending message to server
output.flush();
int counter = 0;
while ((c = input.read()) != -1) //Reading received package
chr[counter++]=(char)c;
//input.reset();
str = new String(chr); //For better manipulation, server message is converted to string
System.out.println(str);
} catch (IOException e)
{
System.err.print(e);
} //End of catch
int index = str.indexOf("Content-Length"); //Look for "Content-Length" in response
str = str.substring(index); //Using its beginning index create an substring
index = str.indexOf("\r\n"); //Search for end of line
str = str.substring(0, index); //Erase end if line chars - \r\n
str = str.substring(16, str.length()); //"Content-Length: " 16 chars
int fileSize = Integer.parseInt(str); //Lentgh of file is converted to Integer
int[][] parts = new int[4][2]; //Beginning and en of jobs for threads will be stored here
int remainder = fileSize; //Bytes left to split for rest of the threads will be stored here
int start = 0;
int finish = 0;
for (int i = 0; i < 4; i++) //Number of threads many times
{
parts[i][0] = start; //*******Each threads job Interval(eg. 0-108)
//System.out.print(parts[i][0] + "-"); //******
finish += remainder / 4 - i; //*****
parts[i][1] = finish; //****
start = finish + 1; //***
if (i + 1 == 4)
parts[i][1] = fileSize; //*
}
str = "GET /TIPS/LAWLER/hedeh/PANOHOW2.PDF HTTP/1.0\r\nRange: bytes=" + parts[0][0] + "-" + parts[0][1] + "\r\nConnection: close\r\n\r\n";
//System.out.println(str);
if(!socket.isConnected())
{
System.out.println("closed");
try
{
socket.connect(sockaddr, 2000);
}//End od try
catch(Exception e){
System.err.print(e);
}//End of catch
}//End of If
System.out.println("Is Outputhandler closed :"+socket.isOutputShutdown());
System.out.println("Is Inputhandler closed :"+socket.isInputShutdown());
try
{
int c;
byte[] buf = new byte[65535];
char[] chr = new char[65535];
buf = str.getBytes(); //Output handler is created
output.write(buf); //Sending message to server
output.flush();
int counter = 0;
if((c = input.read()) != -1)
{
chr[counter++] = (char) c;
while ((c = input.read()) != -1) //Reading received package
{
System.out.println("response is not -1");
chr[counter++]=(char)c;
}
str = new String(chr); //For better manipulation, serve message is converted to string
System.out.println("Response "+str);
}//End of If
else System.out.println("No Response!");
}catch(Exception e)
{System.err.print(e);}
//Closing open stuff
try {
output.close();
input.close();
socket.close();
} catch (Exception e) {
System.out.println(e);
}
}// End of main method
}//End of class definition
The first message is something like;
HTTP/1.0\r\n
You have to use HTTP version 1.1 to use multiple requests on a single TCP connection.
From the Wikipedia article on HTTP:
In HTTP/0.9 and 1.0, the connection is closed after a single request/response pair. In HTTP/1.1 a keep-alive-mechanism was introduced, where a connection could be reused for more than one request.
Also, as #Joachim Sauer points out in the comments, you're explicitly saying Connection: close in your header. :-)
I think that the problem is that you are trying to connect to HTTP server using plain TCP socket. Yes, HTTP is on top of TCP but it is complicated protocol that requires a lot of things to know. I'd suggest you to work with higher level API that implements HTTP protocol and provides you more convenient API.
The simplest example is URL+URLConnection from JDK. Probably better is HttpClient from Jakarta.

Categories

Resources