In my Java application I am using 2 network connections to a webserver. I ask for a range of data for a file from each interface with a GET message and when I get the data, I calc how much time it took and the bps for each link.
This part works fine.
(I haven't closed the sockets yet)
I determine which link is faster then "attempt" to send another HTTP GET request for the rest of the file on the faster link. This is where my problem is, The 2nd cOut.write(GET) doesn't send anything and hence I get no data back.
Do I have to close the socket and re-establish my connection before I can write to it again?
edit
OK to answer some Qs:
Yes TCP
The following code (used on the low speed link) is used first to grab the first block of data using the GET request:
GET /test-downloads/10mb.txt HTTP/1.1
HOST: www.cse.usf.edu
Range: bytes=0-999999
Connection: Close
Is the Connection: Close what is doing it? as when I use Keep-Alive I get a 5sec delay and still do not send/receive data on a subsequent write/read.
// This try block has another fo rthe other link but uses [1]
try {
skSocket[0] = new Socket( ipServer, 80, InetAddress.getByName(ipLowLink), 0 );
skSocket[0].setTcpNoDelay(true);
skSocket[0].setKeepAlive(true);
cOut[0] = new PrintWriter(skSocket[0].getOutputStream(),true);
cIn[0] = new InputStreamReader(skSocket[0].getInputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/* -----------------------------------
the following code is what is called
once for each link (ie cOut[0], cOut [1])
then after determining which has the better bps
(using a GET to grab the rest of the file)
this code is repeated on the designated link
----------------------------------- */
// Make GET header
GET.append(o.strGetRange(ipServer, File, startRange, endRange-1));
// send GET for a specific range of data
cOut[0].print(GET);
cOut[0].flush();
try {
char[] buffer = new char[4*1024];
int n = 0;
while (n >= 0) {
try {
n = cIn[0].read(buffer, 0, buffer.length);
} catch (IOException e) {
e.printStackTrace();
}
if (n > 0) {
raw[0].append(buffer, 0, n); // raw is a stringBuffer
}
}
}
finally {
//if (b != null) b.close();
}
I use the same code as above for my 2nd link (just shift the start/end range over a block) and after I determine the bps, I request the remaining data on the best link (don't worry about how big the file is, etc, I have all that logic done and not the point of the problem)
Now for my subsequent request for the rest of the data, I use the same code as above minus the socket/in/out creation. But the write doesn't send anything. (I hav done the socket check isClosed(), isConnected(), isBound(), isInputShutdown(), isOutboundShutdown(), and all prove that the socket is still open/useable.
According to the HTTP 1.1 spec, section 8:
An HTTP/1.1 client MAY expect a connection to remain open, but would decide to keep it open based on whether the response from a server contains a Connection header with the connection-token close. In case the client does not want to maintain a connection for more than that request, it SHOULD send a Connection header including the connection-token close.
So, you should ensure that you are using HTTP 1.1, and if you are, you should also check that your webserver supports persistent connections (it probably does). However, bear in mind that the spec says SHOULD and not MUST and so this functionality could be considered optional for some servers.
As per the excerpt above, check for a connection header with the connection-close token.
Without a SSCCE, it's going to be difficult to give any concrete recommendations.
Related
I am working on socket programming and implementing custom request response protocol. For same I have used ObjectInputstream and ObjectOutputstream in java socket API.
The area where I have stucked is to check if data(in my case object) is available to read or not, for this I have tried to use the ObjectInputstream.available() but it is returning 0 even if data is available on stream.
Why is it so?
So I have come up with solution: using exception and handling them in infinitely running loop, so even if exception(Read time out) occurs it will try to read again.
I have doubt is it good practice to do so? Or if any other solution you might have do suggest.
while (true){
try {
request = rpcClient.getRequest();
System.out.println(request);
// use threads to handle request for faster response(make use of request IDs)
rpcClient.sendResponse("test response");
} catch (SocketException e)
{// thrown when connection reset
System.out.println("Connection reset : Server is down.....");
break;
} catch (IOException e){
// thrown when read time out
System.out.println("read time out: listening again");
} catch (ClassNotFoundException e){
e.printStackTrace();
}
}
You shouldn't be using available() in the first place. Disable the read timeout, so you can just let the thread wait until there's something to read (or the connection is broken).
I wouldn't recommend using ObjectStreams for network communications though. It's not very suitable in most cases, considering the header information and other things that gets transferred. You're better off designing your own protocol to use and just send bytes over the network.
That is not a good practice since an infinite loop eats away your CPU time.
I dont quite understand your statement
but it is returning 0 even if data is available on stream
since that isnt the case. If it returns 0, there is no data that can be read from the stream. What makes you so sure there actually is data?
Also: I cant see the code that is calling available(). Could you edit your question?
I'm developing a client (Java)/server(C++) application using TCP sockets.
The protocol I used is composed of Messages beginning by 2 bytes defining the type of what will be the content of the Message.
So basically, the receiving thread waits for data to be received in a loop. But I want to use a timeout with the socket to be notified that the other host takes too long to send data.
receivingSocket.setSoTimeout(durationInMilliseconds);
DataInputStream in = new DataInputStream(receivingSocket.getInputStream());
boolean success = false;
short value = 0;
do {
try {
value = in.readShort();// will throw a SocketTimeoutException in case of timeout, without 2 bytes available from the socket
success = true;
} catch (SocketTimeoutException e) {
/// do something if it happens to often. Otherwise go on with the loop
}
} catch (IOException e) {
/// abort connection in case of other problem
}
} while (!success)
Now, what happens if the receiving thread calls in.readShort() at a point where the socket has got only one byte available in its buffer ? Does this byte remain on the socket's stack ? Or is it lost ? In the first case, I could read it next time I call in.readShort(), otherwise it seems lost for good...
readShort() here is an example, my question stands also for readInt(), ...
Thanks for your help,
It isn't specified. I believe the way the implementation works is that the half data is lost, but in any case there's nothing written that says anything else, so you just have to assume the worst.
However in practice this is very unlikely to happen, provided you observe common sense at the sender.
I am currently implementing a web proxy but i have run into a problem.I can parse my request from the browser and make a new request quite alright but i seem to have a problem with response.It keeps hanging inside my response loop
serveroutput.write(request.getFullRequest());
// serveroutput.newLine();
serveroutput.flush();
//serveroutput.
//serveroutput.close();
} catch (IOException e) {
System.out.println("Writting tothe server was unsuccesful");
e.printStackTrace();
}
System.out.println("Write was succesful...");
System.out.println("flushed.");
try {
System.out.println("Getting a response...");
response= new HttpResponse(serversocket.getInputStream());
} catch (IOException e) {
System.out.println("tried to read response from server but failed");
e.printStackTrace();
}
System.out.println("Response was succesfull");
//response code
public HttpResponse(InputStream input) {
busy=true;
reader = new BufferedReader(new InputStreamReader(input));
try {
while (!reader.ready());//wait for initialization.
String line;
while ((line = reader.readLine()) != null) {
fullResponse += "\r\n" + line;
}
reader.close();
fullResponse = "\r\n" + fullResponse.trim() + "\r\n\r\n";
} catch (IOException`` e) {
e.printStackTrace();
}
busy = false;
}
You're doing a blocking, synchronous read on a socket. Web servers don't close their connections after sending you a page (if HTTP/1.1 is specified) so it's going to sit there and block until the webserver times out the connection. To do this properly you would need to be looking for the Content-Length header and reading the appropriate amount of data when it gets to the body.
You really shouldn't be trying to re-invent the wheel and instead be using either the core Java provided HttpURLConnection or the Appache HttpClient to make your requests.
while (!reader.ready());
This line goes into an infinite loop, thrashing the CPU until the stream is available for read. Generally not a good idea.
You are making numerous mistakes here.
Using a spin loop calling ready() instead of just blocking in the subsequent read.
Using a Reader when you don't know that the data is text.
Not implementing the HTTP 1.1 protocol even slightly.
Instead of reviewing your code I suggest you review the HTTP 1.1 RFC. All you need to do to implement a naive proxy for HTTP 1.1 is the following:
Read one line from the client. This should be a CONNECT command naming the host you are to connect to. Read this with a DataInputStream, not a BufferedReader, and yes I know it's deprecated.
Connect to the target. If that succeeded, send an HTTP 200 back to the client. If it didn't, send whatever HTTP status is appropriate and close the client.
If you succeeded at (2), start two threads, one to copy all the data from the client to the target, as bytes, and the other to do the opposite.
When you get EOS reading one of those sockes, call shutdownOutput() on the other one.
If shutdownOutput() hasn't already been called on the input socket of this thread, just exit the thread.
If it has been called already, close both sockets and exit the thread.
Note that you don't have to parse anything except the CONNECT command; you don't have to worry about Content-length; you just have to transfer bytes and then EOS correctly.
I'm creating a small server using java.nio, but when trying to stress test it I keep getting messages about the connection being reset on the server side, or more specifically:
apr_socket_recv: An established connection was aborted by the software in your host machine
I've tried to narrow it down to the most simple of loops, but still no luck. I can get the error after a hundred or so connections, or maybe just after 1 or 2.
Here's the server loop:
byte[] response = ("HTTP/1.1 200 OK\r\n"
+ "Server: TestServer\r\n"
+ "Content-Type: text/html\r\n"
+ "\r\n"
+ "<html><b>Hello</b></html>").getBytes();
SocketChannel newChannel = null;
while (active) {
try {
//get a new connection and delegate it.
System.out.print("Waiting for connection..");
newChannel = serverSocketChannel.accept();
System.out.println("ok");
newChannel.configureBlocking(true);
newChannel.write(ByteBuffer.wrap(response));
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
newChannel.close();
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I've tried checking if the write didn't write all requested byte, but it seemingly does. Interestingly enough, calling System.gc() after each newChannel.close() makes the problem disappear (but in return, it's horribly slow). So either I'm not releasing all resources I should release, or the application just needs a pause..
I'm losing all of my best years on this. Oh, and by the way.. if I ignore writing to the channel and just close after I accept the connection, the problem still doesn't go away.
Well I found it out, so I might as well share it.
My app needed a pause. It was simply going too fast, and closing the connection before the client had written all of its request data. The fix would be to keep on reading until the entire HTTP request had been received. D'oh.. lesson learned.
From the docs for SocketChannel#Write (emphasis mine):
An attempt is made to write up to r bytes to the channel, where r is
the number of bytes remaining in the buffer, that is, src.remaining(),
at the moment this method is invoked.
[...]
Returns: The number of bytes written, possibly zero.
It's up to you to check the return value from the write call (which you're not doing presently), and issue successive write calls until the whole of the buffer has been sent. Something like this, I guess:
ByteBuffer toWrite = ByteBuffer.wrap(response);
while (toWrite.remaining() > 0) {
newChannel.write(toWrite);
}
You'll obviously get aborts if you don't write all of your response data and then just close the socket.
My goal is to connect to a server and then maintain the connection. The server keeps pushing me some data whenever it has any. I wrote the following but it works only the first time. The second time onwards, it gives me an exception saying that the get.getResponseBodyAsStream() is null. I was thinking that Apache's HTTPClient keeps the connection alive by default so what I understand is that I need a blocking call somewhere. Can someone help me out here?
GetMethod get = new GetMethod(url);
String nextLine;
String responseBody = "";
BufferedReader input;
try {
httpClient.executeMethod(get);
while(true) {
try {
input = new BufferedReader(new InputStreamReader(get.getResponseBodyAsStream()));
while ((nextLine = input.readLine()) != null)
responseBody += nextLine;
System.out.println(responseBody);
} catch (IOException ex) {
ex.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
Actually at the end of the day, I am trying to get a persistent connection to the server (I will handle possible errors later) so that I can keep receiving updates from my server. Any pointers on this would be great.
I haven't looked in great detail or tested code, but I think repeatedly opening up a reader on the response is probably a bad idea. I'd take and move the input = line up outside the loop, for starters.
in my opinion HttpClient library is meant for client pull situations. i recommend you to look at comet which supports server push
You cannot do it like this. When you have read the "body" of the response, that is it. To get more information, the client has to send a new request. That is the way that the HTTP protocol works.
If you want to stream multiple chunks of data in a single HTTP response, then you are going to need to do the chunking and unchunking yourself. There a variety of approaches you could use, depending on the nature of the data. For example:
If the data is XML or JSON, send a stream of XML documents / JSON objects an have the receiver separate the stream into documents / objects before sending them to the parser.
Invent your own light-weight "packetization" where you precede each chunk with a start marker and a byte count.
The other alternative is to use multiple GET requests, but try to configure things so that the underlying TCP/IP connection stays open between requests; see HTTP Persistent Connections.
EDIT
Actually, I need to send only one GET request and keep waiting for status messages from the server.
The HTTP status code is transmitted in the first line of the HTTP response message. There can be only one per HTTP response, and (obviously) there can be only one response per HTTP request. Therefore what you are trying to do is impossible using normal HTTP status codes and request/reply messages.
Please review the alternatives that I suggested above. The bullet-pointed alternatives can be tweaked to allow you to include some kind of status in each chunk of data. And the last one (sending multiple requests) solves the problem already.
EDIT 2
To be more particular, it seems that keeping the connection alive is done transparently
That is correct.
... so all I need is a way to get notified when there is some data present that can be consumed.
Assuming that you are not prepared to send multiple GET requests (which is clearly the simplest solution!!!), then your code might look like this:
while (true) {
String header = input.readLine(); // format "status:linecount"
if (header == null) {
break;
}
String[] parts = header.split(":");
String status = parts[0];
StringBuilder sb = new StringBuilder();
int lineCount = Integer.parseInt(parts[1]);
for (int i = 0; i < lineCount; i++) {
String line = input.readLine();
if (line == null) {
throw new Exception("Ooops!");
}
sb.append(line).append('\n');
}
System.out.println("Got status = " + status + " body = " + body);
}
But if you are only sending status codes or if the rest of each data chunk can be shoe-horned onto the same line, you can simplify this further.
If you are trying to implement this so that your main thread doesn't have to wait (block) on reading from the input stream, then either use NIO, or use a separate thread to read from the input stream.