Small http server using java?

2019-05-12 21:51发布

I have created the following test server using java:

   import java.io.*;
import java.net.*;

class tcpServer{
    public static void main(String args[]){
        ServerSocket s = null;
        try{
            s = new ServerSocket(7896);
            //right now the stream is open.
            while(true){
                Socket clientSocket = s.accept();
                Connection c = new Connection(clientSocket);
                //now the connection is established
            }
        }catch(IOException e){
            System.out.println("Unable to read: " + e.getMessage());
        }
    }
}
class Connection extends Thread{
    Socket clientSocket;
    BufferedReader din;
    OutputStreamWriter outWriter;

    public Connection(Socket clientSocket){
        try{
            this.clientSocket = clientSocket;
            din = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "ASCII"));
            outWriter = new OutputStreamWriter(clientSocket.getOutputStream());
            this.start();
        }catch(IOException e){
            System.out.println("Connection: " + e.getMessage());
        }   
    }
    public void run(){
        try{
        String line = null;
        while((line = din.readLine())!=null){
            System.out.println("Read" + line);
            if(line.length()==0)    
                break;
        }
        //here write the content type etc details:
        System.out.println("Someone connected: " + clientSocket);
        outWriter.write("HTTP/1.1 200 OK\r\n");
        outWriter.write("Date: Tue, 11 Jan 2011 13:09:20 GMT\r\n");
        outWriter.write("Expires: -1\r\n");
        outWriter.write("Cache-Control: private, max-age=0\r\n");
        outWriter.write("Content-type: text/html\r\n");
        outWriter.write("Server: vinit\r\n");
        outWriter.write("X-XSS-Protection: 1; mode=block\r\n");
        outWriter.write("<html><head><title>Hello</title></head><body>Hello world from my server</body></html>\r\n");
        }catch(EOFException e){
            System.out.println("EOF: " + e.getMessage());
        }
        catch(IOException e){
            System.out.println("IO at run: " + e.getMessage());
        }finally{
            try{
                            outWriter.close();  
                clientSocket.close();
            }catch(IOException e){
                System.out.println("Unable to close the socket");
            }
        }
    }
}

Now i want this server to respond to my browser. that's why i gave url: http://localhost:7896 and as a result i receive at the server side:

ReadGET / HTTP/1.1
ReadHost: localhost:7896
ReadConnection: keep-alive
ReadCache-Control: max-age=0
ReadAccept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
ReadUser-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10
ReadAccept-Encoding: gzip,deflate,sdch
ReadAccept-Language: en-US,en;q=0.8
ReadAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
ReadCookie: test_cookie=test cookie
Read
Someone connected: Socket[addr=/0:0:0:0:0:0:0:1,port=36651,localport=7896]

And a blank white screen at my browser and source code also blank. In google chrome browser.

So can anyone please tell me where i m wrong. actually i am new to this thing. so please correct me.

Thanks in advance

5条回答
爷的心禁止访问
2楼-- · 2019-05-12 22:32

You almost certainly don't want to be using DataOutputStream on the response - and writeUTF certainly isn't going to do what you want. DataOutputStream is designed for binary protocols, basically - and writeUTF writes a length-prefixed UTF-8 string, whereas HTTP just wants CRLF-terminated lines of ASCII text.

You want to write headers out a line at a time - so create an OutputStreamWriter around the socket output stream, and write to that:

writer.write("HTTP/1.1 200 OK\r\n");
writer.write("Date: Tue, 11 Jan 2011 13:09:20 GMT\r\n");

etc.

You may want to write your own writeLine method to write out a line including the CRLF at the end (don't use the system default line terminator), to make the code cleaner.

Add a blank line between the headers and the body as well, and then you should be in reasonable shape.

EDIT: Two more changes:

Firstly, you should read the request from the client. For example, change din to a BufferedReader, and initialize it like this:

din = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(),
                                               "ASCII"));

then before you start to write the output, read the request like this:

String line;
while ((line = din.readLine()) != null) {
    System.out.println("Read " + line);
    if (line.length() == 0) {
        break;
    }
}

EDIT: As noted in comments, this wouldn't be appropriate for a full HTTP server, as it wouldn't handle binary PUT/POST data well (it may read the data into its buffer, meaning you couldn't then read it as binary data from the stream). It's fine for the test app though.

Finally, you should also either close the output writer or at least flush it - otherwise it may be buffering the data.

After making those changes, your code worked for me.

查看更多
在下西门庆
3楼-- · 2019-05-12 22:33
  • The HTTP protocol is ASCII based, exept the body which depends on the Content-Type header. So, no UTF-8 headers!
  • Headers and body must be separated by an empty line.
  • Why do you set your Transfert-Encoding to chuncked? Your body is not.
查看更多
别忘想泡老子
4楼-- · 2019-05-12 22:37

I'm not sure if you have can use writeUTF instead, instead you may need to use writeBytes. Also, you need to terminate each line with a '\n'.

查看更多
女痞
5楼-- · 2019-05-12 22:41

If you're interested in learning the design and development of network servers like HTTP servers in Java, you might also have a look at this repo:

https://github.com/berb/java-web-server

It's a small HTTP server in Java I started for educational purposes. Though, it shouldn't be used in production or serious use cases yet. I'm still adding new features. It currently provides multi-threading, static file handling, Basic Authentication, logging and a in-memory cache.

EDIT

An obvious error in your code is the missing \r\n between your Response Header and your HTML. Just append an additional \r\n to your last header. Additionally, you must provide the content length, unless you're using Chuncked Encoding:

String out = "<html><head><title>Hello</title></head><body>Hello world from my server</body></html>\r\n";

outWriter.write("Content-Length: "+out.getBytes().length+"\r\n\r\n");
outWriter.write(out);
查看更多
在下西门庆
6楼-- · 2019-05-12 22:49
登录 后发表回答