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();
}
}