Newer
Older
NWP2 / src / j3 / Thttpd.java
@Motoki Miura Motoki Miura on 13 Nov 2021 5 KB Thttpd portnum
package j3;
/** いんちきHTTPサーバThttpd.java スレッド対応版

このプログラムはポート番号8000番で動作するサーバです。
使い方: java j3.Thttpd ファイル名 ポート番号
WWWクライアントからの接続に対して、引数で指定したファイルを返します。
また、そのファイルがあるフォルダを、DocumentRootとします。
 */

// ライブラリの利用
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.LocalDateTime;

// Thttpdクラス
public class Thttpd {
    public static void main(String args[]) {
        // サーバソケット
        ServerSocket servsock = null;
        Socket sock;

        // その他

        if (args.length == 0) // 引数がない場合、以下のファイルを返すことにする
            args = new String[] { "src/j3/index.html", "8000" }; // 相対パスで指定。windowsの場合、user.dir=NWP
        // args = new String[] { "j3/index.html" ,"8000"};//Linuxの場合、通常はcd NWP/srcしているはず
        System.out.println("このサーバは" + args[0] + "を返します。");
        System.out.println(System.getProperty("user.dir"));
        int portnum = Integer.parseInt(args[1]);
        try {
            // サーバ用ソケットの作成(デフォルトでは、ポート番号8000番)
            servsock = new ServerSocket(portnum);
            while (true) {
                sock = servsock.accept();// 接続要求の受付
                new RequestHandler(sock, args[0]);
            }
        } catch (IOException e) {
            System.out.println("異常終了:ポート番号(" + portnum + ")がすでに使われているようです");
            System.exit(1); // 異常終了は1
        }
    }
}

class RequestHandler implements Runnable {
    Socket sock;
    Thread thread;

    // 入出力
    DataOutputStream dostr;
    BufferedReader in;
    FileInputStream infile = null;
    byte[] buff = new byte[1024];
    String file;

    RequestHandler(Socket s, String file) {
        sock = s;
        this.file = file;
        thread = new Thread(this);
        thread.start();
    }

    public void run() {
        try {
            process();
        } catch (IOException e) {
            e.printStackTrace();
        }
        thread = null;
    }

    void process() throws IOException {
        System.out.println("---\nConnection Requst from: " + (sock.getInetAddress()));
        // 読み書き用オブジェクトの生成
        in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
        dostr = new DataOutputStream(sock.getOutputStream());
        // read headers
        StringBuffer request = new StringBuffer();
        String line;
        String[] get = null; // GETリクエストをスペースで区切った配列
        while ((line = in.readLine()) != null) {
            System.out.println(line);
            // 先頭がGETだったら
            if (line.toLowerCase().startsWith("get ")) {
                get = line.split(" "); // GET / HTTP/1.1 をスペースで区切った配列get を得る
            }
            request.append(line + "\r\n");
            if (line.length() < 1)
                break;
        }

        String CRLF = "\r\n";
        // Response Headerの出力
        String response = "HTTP/1.1 200" + CRLF + "Content-type: text/html; charset=UTF-8" + CRLF + CRLF;
        // もし、リクエストがfaviconだったら
        if (get[1].endsWith(".ico")) {
            response = "HTTP/1.1 200" + CRLF + "Content-type: image/x-icon" + CRLF + CRLF;
        } else if (get[1].endsWith(".java")) {
            response = "HTTP/1.1 200" + CRLF + "Content-type: text/plain; charset=UTF-8" + CRLF + CRLF;
        }
        if (!get[1].equals("/")) { // リクエストファイルがあれば、/index.html の部分を書き換える
            file = file.replaceAll("/index.html", get[1]);
        }
        // オブジェクトinfileを作り,ファイルを準備します
        try {
            infile = new FileInputStream(file);
        } catch (Exception e) {
            // ファイル準備の失敗
            System.err.println(file + " ファイルがありません");
            response = "HTTP/1.1 404" + CRLF + CRLF;
        }
        dostr.write(response.getBytes());

        // Response Bodyの出力
        boolean cont = true;
        while (cont) {
            // ファイルからの読み込みとネットワーク出力
            try {
                int n = infile.read(buff);
                dostr.write(buff, 0, n);
            } catch (Exception e) { // end of file
                cont = false;
            }
        }
        if (file.endsWith("index.html")) {
            // おまけ:レスポンスヘッダを表示
            dostr.write(request.toString().getBytes());
            // おまけ:時刻表示
            dostr.write("</pre> \n\n <h2>Current DateTime (Thttpdが動的に生成した情報)</h2>".getBytes());
            dostr.write(LocalDateTime.now().toString().getBytes());
        }

        // 接続終了
        sock.close();
        infile.close();
    }
}