Java多线程Web服务器的设计与实现

任务:

以JDK为开发工具,利用 Socket通信机制实现一个多线程的WEB服务器,该服务器具有以下功能:

1.能够并行服务于多个请求。

2.对于每个请求,显示接收到的HTTP请求报文的内容,并产生适当的响应(若找到用户请求对象,则返回该对象。否则发送一个包含适当提示信息的响应消息,从而可以在浏览器窗口中显示差错信息。)

代码:

import java.io.* ;
import java.net.* ;
import java.util.StringTokenizer;

final class HttpRequest implements Runnable {
    final static String CRLF = "\r\n";
    final static Boolean DEBUG = false;
    InetAddress clientIP;
    int clientPort;
    Socket socket;

    /*
    public HttpRequest(Socket socket, InetAddress clientIP, int clientPort) {
        this.socket = socket;
        this.clientIP = clientIP;
        this.clientPort = clientPort;
    }
     */

    public HttpRequest(Socket socket) {
        this.socket = socket;
        this.clientIP = socket.getInetAddress();
        clientPort = socket.getPort();
    }

    public void run() {
        try {
            processRequest();
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    private void processRequest() throws Exception {
        InputStreamReader is=new InputStreamReader(this.socket.getInputStream());
        BufferedReader br = new BufferedReader(is);
        DataOutputStream os = new DataOutputStream(this.socket.getOutputStream());

        String requestLine = br.readLine();
        StringTokenizer tokens = new StringTokenizer(requestLine);
        String method = tokens.nextToken().toUpperCase();

        if (method.contentEquals("GET")) {
            String fileName = tokens.nextToken();
            if (fileName.startsWith("/"))
                fileName = "." + fileName;

            if (DEBUG) {
                System.out.println("到达了一个Request消息!");
                System.out.println("客户:IP:" + (clientIP.toString()).substring(1) + "Port:" + clientPort);
                String headLine;
                while (((headLine = br.readLine()).length()) != 0) {
                    System.out.println(headLine);
                }
            }


            FileInputStream fis = null;
            boolean fileExists;
            try {
                fis = new FileInputStream(fileName);
                fileExists = true;
            } catch (FileNotFoundException e) {
                fileExists = false;
            }

            String statusLine;
            String contentTypeLine;
            String contentLength;
            String entityBody = null;


/*
            if (fileExists) {
                statusLine = "HTTP/1.0 200 OK" + CRLF;
                contentLength = "Content-Length:" + fis.available() + CRLF;
                contentTypeLine = "Content-Type:" + contentType(fileName) + CRLF + CRLF;
            }

            else {
                statusLine = "HTTP/1.0 200 OK" + CRLF;
                contentLength = "Content-Length:113" + CRLF;
                contentTypeLine = "Content-Type:text/htm;" + CRLF + CRLF;

                entityBody = "<html>" + "<head>" + "<title>404 not found</title>" + "</head>" +
                       "<body>The object you requested is not server!</body>" + "</html>";
            }

            os.writeBytes(statusLine);
            os.writeBytes(contentLength);
            os.writeBytes(contentTypeLine);
*/

            if (fileExists) {
                statusLine="HTTP/1.1 200 OK"+CRLF;
                contentTypeLine = "Content-type: " + contentType( fileName ) + CRLF;

            } else {
                statusLine="HTTP/1.1 404 NotFound"+CRLF;
                contentTypeLine = "Content-type: text/html"+CRLF;
                entityBody ="<html><title>Not found</title><h1>404 NotFound</h1></html>";
            }

            os.writeBytes(statusLine);
            os.writeBytes(contentTypeLine);
            os.writeBytes(CRLF);

            if (fileExists) {
                sendBytes(fis, os);
                fis.close();
            } else {
                os.writeBytes(entityBody);
            }
        } else {
            System.out.println("The method supported by the web server is GET only");
        }
        os.close();
        br.close();
        this.socket.close();
    }

    private static void sendBytes(FileInputStream fis, OutputStream os) throws Exception {
        byte[] buffer = new byte[1024];
        int bytes;
        while ((bytes = fis.read(buffer)) != -1) {
            os.write(buffer, 0, bytes);
        }
    }

    private static String contentType(String fileName) {

        if (fileName.endsWith(".htm") || fileName.endsWith(".html")) {
            return "text/html";
        }
        if (fileName.endsWith(".java") || fileName.endsWith(".cc") || fileName.endsWith(".c")) {
            return "text/plain";
        }
        if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") || fileName.endsWith(".jpe")) {
            return "image/jpeg";
        }
        if (fileName.endsWith(".doc")) {
            return "application/msword";
        }
        if (fileName.endsWith(".docx")) {
            return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        }
        if (fileName.endsWith(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (fileName.endsWith(".xls")) {
            return "application/vnd.ms-excel";
        }
        return "text/plain";
    }
}
import java.net.* ;

public final class MultiThreadedWebServer {
    public static void main(String[] args) throws Exception {
        int port = 8080;
        /*
        if (args.length < 1) {
            System.out.println("启动服务器时必须指定Server的工作端口!格式:MultiThreadedWebServer XXXX");
        } else {
            port = Integer.parseInt(args[0]);
        }
         */
        ServerSocket socket = new ServerSocket(port);

        System.out.println("The Web Server is ready for you! Its working port is " + port);

        while (true) {
            Socket connection = socket.accept();
            HttpRequest request = new HttpRequest(connection);
            Thread thread = new Thread(request);
            thread.start();
        }
    }
}

运行效果:

需要注意:

博主一开始将准备好的文件(.jpg,.txt, .java等)放入src文件夹中会出现在浏览器找不到相关文件的情况,在放入上一级文件夹并且将out/production中产生的文件删除才得以显示。还要注意参考HTTP Response消息Content-Type头部规范。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值