How do I read a server reply without it blocking me? - java

I'm writing a proxy and have the following code:
Socket conUser;
Socket conDest;
try{
ServerSocket ss = new ServerSocket(Integer.parseInt(p.getProperty("proxy.port")));
while(true){
//Connect to user
conUser = ss.accept();
BufferedReader inputFromUser = new BufferedReader(new InputStreamReader(conUser.getInputStream()));
BufferedWriter outputToUser = new BufferedWriter(new OutputStreamWriter(conUser.getOutputStream(), "UTF8"));
//Get user request
StringBuffer req = new StringBuffer();
getUserRequest(inputFromUser, req);
System.out.println("User requested the following:");
System.out.println(req);
//Connect to server
InetAddress a = InetAddress.getByName(determineHost(req));
conDest = new Socket(a,80);
//Send request to server
BufferedWriter outputToServer = new BufferedWriter(new OutputStreamWriter(conDest.getOutputStream(), "UTF8"));
InputStreamReader inputFromServer = new InputStreamReader(conDest.getInputStream(), "UTF8");
outputToServer.write(req.toString());
outputToServer.flush();
System.out.println("==============================");
System.out.println("Server replied with the following:");
//Read reply from the server
//=========================================
int chars;
while ((chars = inputFromServer.read()) != -1) {
System.out.print((char)chars);
outputToUser.write(chars);
outputToUser.flush();
//serverReply.append(chars);
}
//Relay reply to user
//outputToUser.write(serverReply.toString());
//System.out.println(serverReply);
//outputToUser.flush();
conUser.close();
conDest.close();
}
}
catch (Exception e) {
System.err.println(e);
}
What happens is: I make a connection and it succeeds. I also send the request, and that succeeds too. I also get a reply, and am able to load the entire page's HTML, except that the read doesn't seem to terminate when it reaches the end of the content.
Specifically, I was attempting to load Google's homepage and the chunked transfer reached 0 (that is- end of chanked transfer), and thus there should've been no more input to read, but this did not cause the loop to stop reading. What's also strange to me is that pretty much all code examples of proxies do use this loop, and assuming they work, I don't see much differences between their code and mine.
How do I make the loop terminate correctly?
EDIT: for the record, yes- I know that the TCP connection should be kept open to handle further connections. This is not relevant to the problem I'm having. I need to get this loop to terminate per response.

In general the connection is not closed at the end of each response. Creating TCP connections is relatively time-consuming so the connection is left open, ready for you to send your next request.
Here are a couple of explanatory links:
http://en.wikipedia.org/wiki/HTTP_persistent_connection
http://en.wikipedia.org/wiki/HTTP_pipelining

If you want to terminate connection correctly after receiving HTTP response, your simple loop is not enough. You have to determine the end of message as described in section 4.4 Message Length of RFC 2616 and then close the connection.
However, it would be better to use existing libraries, such as built-in URLConnection.

Related

How can I get full Http Request via Java

I'm trying to write a httpserver using sockets and I meet this problem.
As everyone knows , a Http request is like this.
GET /index.html HTTP/1.1
Cache-Control: max-age=0
Host: 127.0.0.1
Accept:xxxxx
User-Agent: xxxx
Connection: keep-alive
CRLF
This is message body!
The question is how can I get full Http request including message body.
I tried to write like this.
ServerSocket serverSocket = new ServerSocket(8000);
while (true) {
Socket socket = serverSocket.accept();
new Thread() {
{
InputStream is = socket.getInputStream();
BufferedReader input = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = input.readLine()) != null) {
System.out.println(line);
}
System.out.print("finish");
}
}.start();
}
And the console would never print "finish".Then I changed like this
ServerSocket serverSocket = new ServerSocket(8000);
while (true) {
Socket socket = serverSocket.accept();
new Thread() {
{
InputStream is = socket.getInputStream();
BufferedReader input = new BufferedReader(new InputStreamReader(is));
String line = null;
while (input.ready()) {
line = input.readLine();
System.out.println(line);
}
System.out.println("finish");
}
}.start();
}
Things go to be better, We can see "finish"! But if I refresh the page a little bit faster.The bufferdreader will not be ready and don't get in the while{} !
I want to print all the rerquest and "finish"
Please help me.
Thanks a lot!!
Both your approaches are incorrect.
In the first one, input.readLine() will return null only when the end of the stream has been reached, not when the request ended. That means that you'll loop there as long as the browser maintains the TCP connection open. That might take a while. Plus, multiple requests might be sent on the same connection, so you might end up printing all of them (I don't know if that's what you want to do).
In the second one, you have timing problem. input.ready() checks whether the receive buffer has any content to read, instead of checking whether the request ended. So you might end up printing only a part of the request instead of waiting for the whole thing. With this approach and the right timings, you might end up printing a part of a request, multiple requests, or anything in between (like a request and a half).
Also note that HTTP GET messages almost never carry any payalod, and no browser will requests like the one in your example.

multiple threads writing to one server

I have a problem. I want to create a network connection so that I can make a multiplayer game. I know and understand sockets.
My problem is that if I press two keys on the keyboard at the same time it writes to the socket at the same time which causes an error. What I then did was create multiple sockets for one client to writ to and only writes to a socket that isn't busy. By for some reason seems to overload it or something. Any ideas for simultaneously sending messages to server and vice versa.
Is your code doing like this in server?
while (true) {
try {
socket = serverSocket.accept();
} catch (IOException e) {
System.out.println("I/O error: " + e);
}
// new threa for a client
new MyThread(socket).start();
}
then, inside MyThread#run
inp = socket.getInputStream();
brinp = new BufferedReader(new InputStreamReader(inp));
out = new DataOutputStream(socket.getOutputStream());
line = brinp.readLine(); // read the data.
out.writeBytes(line + "\n\r"); //write back to client
out.flush(); // flush socket
Java NIO would faster and efficient. Please refer open source netty servers as well.
I have used a queueing method and has fixed the problem.

Java communication with TCP socket and PIC stuck in read()

I try to communicate with a java application to a µController in wifi (Flyport).
I have a problem with the java application :
It first create a socket to communicate with the Flyport server, then send a message and receive the Flyport answer.
Everything work fine until the read part. I'm polling the read() function of the BufferedReader until it return -1, but it doesn't. The first read works fine, all the answer are red, but the application stay stuck when it tries to read again.
My code is very simple :
Java application :
try (
Socket clientSocket = new Socket(hostName, portNumber);
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in =
new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
)
{
...//Connection and sending message works fine
}
char[] buffer = new char[500];
while ((in.read(buffer)) != -1) { // first read() works fine, second read() stay stuck...
System.out.println(buffer); // display all answer sent by flyport
}
The code in the flyport :
while(isClientConnected){
//check if client is still connected
...
//read client message
while((RxLen=TCPRxLen(sock))>0)
{
TCPRead(sock,bff,RxLen);
strcat(msg,bff);
}
//write back to the client that the order is received
TCPWrite(sock, msg, strlen(msg));
//process the client order
...
//Write to the client that the process is done
TCPWrite(sock, msg2, strlen(msg2));
}
The java application read msg and msg2 with the first read(). msg and msg2 have "\r\n" at the end.
Doesn't somebody can tell me where I am wrong ?
Is there a function from BufferedReading that tells how much data there is left to read ?
Thanks and regards.
NB : I try with a small buffer in the java application, the problem is the same, read() is stuck when there is nothing left to read...
You're reading from the socket until end of stream, and you're never causing end of stream, as you are never closing the socket at the sender. Either close the socket or don't read until end of stream.

IOUtils copy and write issues

I'm trying to send strings to a server from a client but it doesn't seem to be reading from the input stream.
Client
Scanner scanner = new Scanner(System.in);
Socket connection = new Socket("localhost", 13)
OutputStream out = connection.getOutputStream();
while(true) {
String message = scanner.nextLine();
IOUtils.write(message, out, "UTF-8");
out.flush();
}
Server
ServerSocket server = new ServerSocket(localhost,13);~
Socket connection = server.accept();
InputStream in = connection.getInputStream();
StringWriter writer = new StringWriter();
while(true) {
try {
IOUtils.copy(in, writer);
System.out.println(writer.toString());
} catch(IOException io) {}
}
It reads if I close the stream from the client's outputstream but I am trying to send multiple messages from the client to the server. Could someone please help
You seem to think that each time you call flush() at client-side, the server will know it and be able to know that this is the end of a message. That's not the case. IOUtils.copy() reads everything from a stream of bytes. While the stream end hasn't been reached, copy() won't return.
You can see streams as two sides of a long tube. If you pour 10 buckets of water in the at the end of the tube, all you'll get at the other side is a continuous flow of water.
If you need multiple separate messages, then you need to design a protocol allowing to separate messages, and read until the end of a message has been reached. It could be based on separators for example. Or you could send the length of the message followed by the message itself, to let the server know how many bytes it must read to get the next message.

Sending packets over TCP socket

I'm writing this tiny utility method to test sending raw packets to a specific messaging network (planning on developing a client to connect to it).
The network is the Deviantart messaging network (chat.deviantart.com:3900; TCP).
My class:
protected void connect() throws IOException{
Socket dAmn = null;
//BufferedWriter out = null;
PrintWriter out = null;
BufferedReader in = null;
/*
* Create Socket Connection
*/
try{
dAmn =
new Socket("chat.deviantart.com", 3900);
/*out =
new BufferedWriter(new OutputStreamWriter(dAmn.getOutputStream()));*/
out =
new PrintWriter(dAmn.getOutputStream(), true);
in =
new BufferedReader(new InputStreamReader(dAmn.getInputStream()));
}
catch(SocketException e){
System.err.println("No host or port for given connection");
//handle
}
catch(IOException e){
System.err.println("I/O Error on host");
//handle
}
String userInput;
BufferedReader userIn =
new BufferedReader(new InputStreamReader(System.in));
/*
* dAmn communication
*/
while((userInput = userIn.readLine()) != null){
out.write(userInput);
System.out.println(in.readLine());
}
if(in!=null)
in.close();
if(out!=null)
out.close();
if(dAmn!=null)
dAmn.close();
}
The server requires a handshake to be sent before the login may proceed. A typical login packet looks like thus:
dAmnclient damnClient (currently 0.3)
agent= agent
Every packet must end with a newline and a null.
My handshake packet would look something like:
dAmnClient 0.3\nagent=SomeAgent\n\0
However the server simply replies with disconnect
I think something is incorrectly being parsed, any advice? Also, if you're super intersted in helping me out: here's some quick documentation on the client -> server dAmn protocol:
http://botdom.com/wiki/DAmn#dAmnClient_.28handshake.29
You should use Wireshark
With Wireshark you can sniff traffic from/to hosts. It makes it really easy to spot where your application does something else than the standard client.
BTW you have a \n in front of agent=, it might be the problem
The line read from the user will not contain the actual line termination, and it will not contain any null-termination either. Typing \n at the input will actually transmit "\n" rather than a new-line.
You could add a new-line by replacing write with println (careful, it may use \n, \r\n or just \r depending on platform):
out.println(userInput);
You could support packet termination e.g. by checking for a specific user input, like so:
if (userInput.equals(".")) {
out.write((char) 0);
out.flush();
} else {
out.println(userInput);
}
The user can now terminate packets by typing a dot.
(Actually the code could perform the handshake automatically without waiting for user input, but that's another story.)

Categories

Resources