copy bytes via sockets - bytes get lost

Hi Everyone,

I would be glad, if you could help me, get this piece of code running. It is a modification of the code, posted by "bbritta" in the following thread:

http://forum.java.sun.com/thread.jsp?forum=54&thread=446576

Description:

(two threads, which are running in an endless loop)

- the server waits for the command "next"

- the server responds with [number of bytes]

- the server sends [number of bytes] bytes

- the client post a message "next" to request some bytes

- the client reads [number of bytes], so he knows how many bytes are following

- the client reads [number of bytes] bytes

Problem/Question:

- the client gets stuck in the read-Method, because it didn't read all the bytes yet

- meanwhile the server is waiting for the "next" command, because he already sent all the bytes

What is my problem? How do I get this solved, without closing the socket?

publicclass Test{

privatestaticfinalint CHUNK_SIZE = 8192;

publicstaticvoid main(String[] arghs){

// Server-Thread

new Thread(new Runnable(){

publicvoid run(){

try{

ServerSocket ss =new ServerSocket(9998);

byte[] bytes =newbyte[1024];

for (int i = 0; i < bytes.length; i++) bytes[i] = (byte) i;

Socket s = ss.accept();

InputStream is = s.getInputStream();

BufferedReader reader =new BufferedReader(new InputStreamReader(is));

OutputStream os = s.getOutputStream();

while (true){

reader.readLine();// reads the "next", so the other Thread wants another chunk

os.write((CHUNK_SIZE +"\r\n").getBytes());// how many bytes will be sent this time?

os.flush();

int bytesSent = 0;

while (bytesSent < CHUNK_SIZE){

os.write(bytes);

bytesSent += bytes.length;

}

System.out.println("out=" + bytesSent);

System.out.flush();// flushing System.out, so we see immediatly when Thread arrives here

os.flush();

}

}catch (Exception e){

e.printStackTrace();

}

}

}).start();

// Client-Thread

new Thread(new Runnable(){

publicvoid run(){

try{

byte[] bytes =newbyte[1024];

Socket s =new Socket("127.0.0.1", 9998);

InputStream is = s.getInputStream();

BufferedReader reader =new BufferedReader(new InputStreamReader(is));

OutputStream os = s.getOutputStream();

while (true){

os.write("next\r\n".getBytes());// 'I want the next chunk'

os.flush();

String line = reader.readLine();// 'How large is it?'

int length = Integer.parseInt(line);

int x, bytesread = 0;

while (bytesread < length){

x = is.read(bytes);// after some cycles, this Thread gets stuck here . while the other one waits for the "next" command

bytesread += x;

System.out.println(" in=" + bytesread);

System.out.flush();// flushing System.out, so we see immediatly when Thread arrives here

}

}

}catch (Exception e){

e.printStackTrace();

}

}

}).start();

}

}

examle output:

in=1024

in=2048

in=3072

in=4096

in=5120

in=6144

in=7168

in=8192

out=8192

in=1024

in=2048

in=3072

in=4096

in=5120

in=6144

in=7168

in=8192

out=8192

in=1024

in=2048

in=3072

in=4096

in=5120

in=6144

in=7168

in=8192

out=8192

in=1024

in=2048

in=3072

in=4096

in=5120

in=6144

in=7168

in=8192

out=8192

out=8192

in=1024

in=2048

in=3072

in=4096

in=5120

in=6144

in=7168

in=8192

out=8192

in=6

[the output ends here, while it should go one forever]

Lost Crumb

[6635 byte] By [lost_crumb] at [2007-9-30 19:38:31]
# 1

what u r attempting is a Conversation between the client and the server, so u have to make the server wait

after each output.

what it means is that after the server has output the length of the outgoing string make it

wait for an input from the client by doing another readLine(). after the client finishes reading the length of the incoming string, just output a blank line so that the server can resume.

travis311279 at 2007-7-7 0:23:28 > top of Java-index,Security,Event Handling...
# 2

Your hint works well to prevent the deadlock, thank you.

But I cannot use it, to solve my problem because I am developing a little HTTP 1.1 -Server for self-equcation. In the end it should be compatible to browsers, but they don't send the blank for what I know. It should also be compatible to my HTTP-Client, which requests Partial-Contents, so it needs to stay connected with the server.

Can anyone help me on that?

Here is an example communication:

// this would be the "next" from my ex. code

-

GET /testfile.avi HTTP/1.1

User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [en]

Host: localhost

Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1

Accept-Language: en

Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1

Connection: Keep-Alive, TE

TE: deflate, gzip, chunked, identity, trailers

-

// this would be the length from my ex. code

****************************************************

HTTP/1.1 200 OK

Content-length: 76339788

Content-Type: application/binary

****************************************************

// now the browser should send a blank line, but it doesn't, am I right?

// finally the bytes are copied

lost_crumb at 2007-7-7 0:23:28 > top of Java-index,Security,Event Handling...
# 3

> But I cannot use it, to solve my problem because I am

> developing a little HTTP 1.1 -Server for

> self-equcation.

ok, dont know much abt the protocol itself but if u r looking for a simple HTTP server example, check Code Sample 1 at:

http://java.sun.com/developer/technicalArticles/Security/secureinternet/

hth

travis311279 at 2007-7-7 0:23:28 > top of Java-index,Security,Event Handling...
# 4

I have constructed a workaround with your help, and it works. Thanks for helping me out, Travis.

I'm still wondering what the problem is. The HTTP-Response and the following bytes could be viewed as ONE response, but they are obviously not. If someone can explain why, please don't hesitate.

Lost Crumb

lost_crumb at 2007-7-7 0:23:28 > top of Java-index,Security,Event Handling...
# 5

Hi

found an old code sample for retrieving partial contents. the only interesting part is

URL url = new URL("http://localhost:9999/index.html");

HttpURLConnection hconn = (HttpURLConnection)url.openConnection();

hconn.setRequestProperty("Range","bytes=0-50");

this will read the first 50 bytes of index.html

so, basically ur server needs to handle the Range header and return the requested bytes

check http://www.ietf.org for the RFC of HTTP 1.1 if u need the exact details

travis311279 at 2007-7-7 0:23:28 > top of Java-index,Security,Event Handling...
# 6

> I'm still wondering what the problem is. The

> HTTP-Response and the following bytes could be viewed

> as ONE response, but they are obviously not. If

> someone can explain why, please don't hesitate.

sorry, didnt see that post.

AFAIK, HTTP being a stateless protocol will view each connection as a new one. the only way u can retrieve

partial contents is that the client remember how many bytes have been read and in successive requests

request the unread bytes. as u would have noticed in that sample server, the server DOES close each connection after serving the file.

travis311279 at 2007-7-7 0:23:28 > top of Java-index,Security,Event Handling...
# 7
Your last idea sounds like another good workaround. Once again, thank you. You saved my day :-)
lost_crumb at 2007-7-7 0:23:28 > top of Java-index,Security,Event Handling...
# 8
> Your last idea sounds like another good workaround.> Once again, thank you. You saved my day :-)wc :-D
travis311279 at 2007-7-7 0:23:28 > top of Java-index,Security,Event Handling...