我正在用java制作一个网络服务器。
任务是...
HTTP/1.1 的 Host 标头必须是可解析的。 例如,实现a.com和b.com请求的Web服务器应该能够根据域提供不同的数据。
以下内容应该可以在配置文件中进行管理。 (例如属性、json、xml、yml 等)
2-1.所实现的Web服务器的操作端口必须是可配置的。 (例如 80、8080)
2-2.必须为每个 HTTP/1.1 主机指定 HTTP_DOC_ROOT。
2-3。应该可以在每个 HTTP/1.1 主机出现 403、404 或 500 错误时指定服务器上要输出的 HTML 文件的路径。
以下是示例代码。
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
public class HttpServer {
private static final Logger logger = Logger.getLogger(HttpServer.class.getCanonicalName());
private static final int NUM_THREADS = 50;
private static final String INDEX_FILE = "index.html";
private final File rootDirectory;
private final int port;
public HttpServer(File rootDirectory, int port) throws IOException {
if (!rootDirectory.isDirectory()) {
throw new IOException(rootDirectory
+ " does not exist as a directory");
}
this.rootDirectory = rootDirectory;
this.port = port;
}
public void start() throws IOException {
ExecutorService pool = Executors.newFixedThreadPool(NUM_THREADS);
try (ServerSocket server = new ServerSocket(port)) {
logger.info("Accepting connections on port : " + server.getLocalPort());
logger.info("Document Root: " + rootDirectory);
while (true) {
try {
logger.info("Runnable Start ");
Socket request = server.accept();
Runnable r = new RequestProcessor(rootDirectory, INDEX_FILE, request);
logger.info("Runnable r1 : " + r);
pool.submit(r);
logger.info("Runnable r2 : " + r);
} catch (IOException ex) {
logger.log(Level.WARNING, "Error accepting connection", ex);
}
}
}
}
public static void main(String[] args) {
// get the Document root
File docroot;
try {
docroot = new File(args[0]);
} catch (ArrayIndexOutOfBoundsException ex) {
System.out.println("Usage: java JHTTP docroot port : " + ex);
return;
}
// set the port to listen on
int port;
try {
port = Integer.parseInt(args[1]);
if (port < 0 || port > 65535) port = 80;
} catch (RuntimeException ex) {
port = 80;
}
try {
HttpServer webserver = new HttpServer(docroot, port);
webserver.start();
} catch (IOException ex) {
logger.log(Level.SEVERE, "Server could not start", ex);
}
}
}
import java.io.*;
import java.net.Socket;
import java.net.URLConnection;
import java.nio.file.Files;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
public class RequestProcessor implements Runnable {
private final static Logger logger = Logger.getLogger(RequestProcessor.class.getCanonicalName());
private File rootDirectory;
private String indexFileName = "index.html";
private Socket connection;
public RequestProcessor(File rootDirectory, String indexFileName, Socket connection) {
if (rootDirectory.isFile()) {
throw new IllegalArgumentException(
"rootDirectory must be a directory, not a file");
}
try {
rootDirectory = rootDirectory.getCanonicalFile();
} catch (IOException ex) {
}
this.rootDirectory = rootDirectory;
if (indexFileName != null)
this.indexFileName = indexFileName;
this.connection = connection;
}
@Override
public void run() {
// for security checks
String root = rootDirectory.getPath();
logger.info("RequestProcessor Start!!!!!!!");
logger.info( "root : " + root);
try {
OutputStream raw = new BufferedOutputStream(connection.getOutputStream());
Writer out = new OutputStreamWriter(raw);
Reader in = new InputStreamReader(new BufferedInputStream(connection.getInputStream()), "UTF-8");
StringBuilder requestLine = new StringBuilder();
while (true) {
int c = in.read();
if (c == '\r' || c == '\n')
break;
requestLine.append((char) c);
}
logger.info( "requestLine : " + requestLine);
String get = requestLine.toString();
logger.info("connection.getRemoteSocketAddress" + connection.getRemoteSocketAddress() + " " + get);
String[] tokens = get.split("\\s+");
String method = tokens[0];
String version = "";
if (method.equals("GET")) {
String fileName = tokens[1];
if (fileName.endsWith("/")) fileName += indexFileName;
String contentType =
URLConnection.getFileNameMap().getContentTypeFor(fileName);
if (tokens.length > 2) {
version = tokens[2];
}
File theFile = new File(rootDirectory, fileName.substring(1, fileName.length()));
if (theFile.canRead()
// Don't let clients outside the document root
&& theFile.getCanonicalPath().startsWith(root)) {
byte[] theData = Files.readAllBytes(theFile.toPath());
if (version.startsWith("HTTP/")) { // send a MIME header
sendHeader(out, "HTTP/1.0 200 OK", contentType, theData.length);
}
// send the file; it may be an image or other binary data
// so use the underlying output stream
// instead of the writer
raw.write(theData);
raw.flush();
} else {
// can't find the file
String body = new StringBuilder("<HTML>\r\n")
.append("<HEAD><TITLE>File Not Found</TITLE>\r\n")
.append("</HEAD>\r\n")
.append("<BODY>")
.append("<H1>HTTP Error 404: File Not Found</H1>\r\n")
.append("</BODY></HTML>\r\n")
.toString();
if (version.startsWith("HTTP/")) { // send a MIME header
sendHeader(out, "HTTP/1.0 404 File Not Found", "text/html; charset=utf-8", body.length());
}
out.write(body);
out.flush();
}
} else {
// method does not equal "GET"
String body = new StringBuilder("<HTML>\r\n").append("<HEAD><TITLE>Not Implemented</TITLE>\r\n").append("</HEAD>\r\n")
.append("<BODY>")
.append("<H1>HTTP Error 501: Not Implemented</H1>\r\n")
.append("</BODY></HTML>\r\n").toString();
if (version.startsWith("HTTP/")) { // send a MIME header
sendHeader(out, "HTTP/1.0 501 Not Implemented",
"text/html; charset=utf-8", body.length());
}
out.write(body);
out.flush();
}
} catch (IOException ex) {
logger.log(Level.WARNING, "Error talking to " + connection.getRemoteSocketAddress(), ex);
} finally {
try {
connection.close();
} catch (IOException ex) {
}
}
}
private void sendHeader(Writer out, String responseCode, String contentType, int length)
throws IOException {
out.write(responseCode + "\r\n");
Date now = new Date();
out.write("Date: " + now + "\r\n");
out.write("Server: JHTTP 2.0\r\n");
out.write("Content-length: " + length + "\r\n");
out.write("Content-type: " + contentType + "\r\n\r\n");
out.flush();
}
}
我搜索了网络编程、http、Java套接字编程,也找了书籍, 所以我想我知道这个概念,但我不知道如何将其转换为java代码。即使经过搜索,我也找不到问题中主机头的代码,所以我很茫然。
本周期中复习,没有进展..
我的卡点
有没有办法用代码实现? 开发人员如何将搜索到的概念转移并使用到代码中? 如果搜索没有找到合适的代码,我不知道该怎么办。
读完请求行后,您将获得标题。如下所示:
GET /hello.html HTTP/1.0\r\n
Host: a.com\r\n
Date: Tue, 8 Aug 2023 06:16:00 GMT\r\n\r\n
请注意,无法保证标题的顺序。当您收到两个 CR-LF (
\r\n
) 时,所有标头都结束。