Маленький http-сервер, использующий Java? - PullRequest
3 голосов
/ 11 января 2011

Я создал следующий тестовый сервер с использованием 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");
            }
        }
    }
}

Теперь я хочу, чтобы этот сервер отвечал на мой браузер. вот почему я дал URL: http://localhost:7896 и в результате я получаю на стороне сервера:

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]

И пустой белый экран в моем браузере, и исходный код также пуст. В браузере Google Chrome.

Так может кто-нибудь, пожалуйста, скажите мне, где я не прав. на самом деле я новичок в этом деле. пожалуйста, поправьте меня.

Заранее спасибо

Ответы [ 5 ]

6 голосов
/ 11 января 2011

Вы почти наверняка не хотите использовать DataOutputStream в ответе - и writeUTF определенно не будет делать то, что вы хотите. DataOutputStream в основном предназначен для двоичных протоколов, а writeUTF записывает строку UTF-8 с префиксом длины, в то время как HTTP просто хочет завершить CRLF строки текста ASCII.

Вы хотите записать заголовки из строки за один раз - поэтому создайте OutputStreamWriter вокруг выходного потока сокета и напишите в него:

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

и т.д.

Возможно, вы захотите написать свой собственный метод writeLine, чтобы написать строку, включая CRLF в конце (не используйте системный терминатор строки по умолчанию), чтобы сделать код чище.

Добавьте также пустую строку между заголовками и телом, и тогда вы будете в разумной форме.

РЕДАКТИРОВАТЬ: еще два изменения:

Во-первых, вы должны прочитать запрос от клиента. Например, измените din на BufferedReader и инициализируйте его следующим образом:

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

затем, прежде чем начать писать вывод, прочитайте запрос следующим образом:

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

EDIT: как отмечено в комментариях, это не подходит для полноценного HTTP-сервера, так как он не будет хорошо обрабатывать двоичные данные PUT / POST (он может считывать данные в свой буфер, то есть вы не сможете читать как двоичные данные из потока). Впрочем, для тестового приложения это нормально.

Наконец, вы также должны либо закрыть выходной модуль записи, либо хотя бы очистить его - в противном случае он может буферизовать данные.

После внесения этих изменений ваш код сработал для меня.

2 голосов
/ 11 января 2011

Если вы заинтересованы в изучении проектирования и разработки сетевых серверов, таких как HTTP-серверы на Java, вы также можете взглянуть на этот репо:

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

Небольшой HTTP-сервер на Java я начал в образовательных целях.Однако, это не должно использоваться в производстве или серьезных случаях использования.Я все еще добавляю новые функции.В настоящее время он обеспечивает многопоточность, статическую обработку файлов, базовую аутентификацию, ведение журнала и кэш в памяти.

РЕДАКТИРОВАТЬ

Очевидная ошибка в вашем коде - отсутствие \ r \ n между заголовком ответа и вашим HTML.Просто добавьте дополнительный \r\n к вашему последнему заголовку.Кроме того, вы должны указать длину содержимого, если только вы не используете 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);
1 голос
/ 11 января 2011
  • Протокол HTTP основан на ASCII, за исключением тела, которое зависит от заголовка Content-Type. Таким образом, нет заголовков UTF-8!
  • Заголовки и тело должны быть разделены пустой строкой.
  • Почему вы устанавливаете свою кодировку Transfert на chuncked? Твоего тела нет.
0 голосов
/ 11 января 2011

Проверьте это, это уже сделано для вас:

http://www.mcwalter.org/technology/java/httpd/tiny/index.html

0 голосов
/ 11 января 2011

Я не уверен, что вместо этого вы можете использовать writeUTF, вместо этого вам может понадобиться writeBytes. Кроме того, вам нужно завершить каждую строку с '\n'.

...