计算机网络实验手写Web服务器

本次实验客户端是浏览器,服务器通过代码实现

废话少说,附上代码:


import java.net.ServerSocket;
import java.net.Socket;
import java.awt.im.InputContext;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.StringTokenizer;

public final class WebServer {
    public static void main(String[] args) throws Exception {
    	
    	//创建端口号码
        int port = 8080;
        //创建监听套接字,并指明在那个端口号处监听
        ServerSocket socket = new ServerSocket(port);

        //处理一个死循环中的 HTTP 服务请求
        while(true)
        {
            //client监听一个 TCP 连接请求
            Socket connection = socket.accept();

            // 构造一个对象来处理 HTTP 请求消息
            HttpRequest request = new HttpRequest(connection);

            //创建一个新的线程来处理请求
            Thread thread = new Thread(request);

            //开始新线程
            thread.start();
        }
    }
}

final class HttpRequest implements Runnable {

    final static String CRLF = "\r\n";
    Socket socket;
    //构造函数
    public HttpRequest(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            processRequest();
        } catch (Exception e) {
            System.out.println(e);
        }
    }
    private void processRequest() throws Exception {
        //获取套接字的输入和输出流的引用
        InputStream is = socket.getInputStream();
        DataOutputStream os = new DataOutputStream(socket.getOutputStream());
        //设置输入流的缓冲
        BufferedReader br = new BufferedReader(new InputStreamReader(is));

        //获取请求的 HTTP 请求消息的行
        String requestLine = br.readLine();
        //显示请求行
        System.out.println();
        System.out.println(requestLine);

        //得到且显示获取的头部
        String headerLine = null;
        while ((headerLine = br.readLine()).length() != 0) {
            System.out.println(headerLine);
        }
        //从请求行中提取文件名。
        StringTokenizer tokens = new StringTokenizer(requestLine);
        tokens.nextToken();
        String fileName = tokens.nextToken();
        //前面加上“.”所以,在当前目录下的文件的请求
        fileName = '.' + fileName;
        //打开文件流和文件信息
        FileInputStream fis = null;
        boolean fileExists = true;
        try {
            fis = new FileInputStream(fileName);
        } catch (FileNotFoundException e) {
            fileExists = false;
        }

        //构建响应信息
        String statusLine = null;
        String contentTypeLine = null;
        String entityBody = null;
        if (fileExists) {
            statusLine = "HTTP/1.1 200 OK" + CRLF;
            contentTypeLine = "Content-type:" + contentType(fileName) + CRLF;
        } else {
            statusLine = "HTTP/1.1 404 Not Found" + CRLF;
            contentTypeLine = "Content-type: text/html" + CRLF;
            entityBody = "<HTML>" + 
            		 	 "<HEAD><TITLE>Not Found</TITLE></HEAD>" + 
            		 	 "<BODY>Not Found</BODY></HTML>";
        }
        //发送状态行 
        os.writeBytes(statusLine);
        //发送链接类型
        os.writeBytes(contentTypeLine);
        ///发送一个空白行,以指示头行的结束
        os.writeBytes(CRLF);

        if (fileExists) {
            sendBytes(fis, os);
            fis.close();
        } else {
            os.writeBytes(entityBody);
        }
    }

    private void sendBytes(FileInputStream fis, DataOutputStream os) throws IOException {

        //构建1M缓冲的方式字节
        byte[] buffer = new byte[1024*1024];
        int bytes = 0;

        //将请求的文件复制到套接字的输出流中
        while ((bytes = fis.read(buffer)) != -1) {
            os.write(buffer, 0, bytes);
            socket.shutdownOutput();
        }
    }

    private static String contentType(String fileName) {
        if (fileName.endsWith(".htm") || fileName.endsWith(".html")) {
            return "text/html";
        }
        if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")){
            return "image/jpeg";
        }
        if (fileName.endsWith(".txt")) {
            return "text/plain";
        }
        return "application/octet-stream";
    }

}

注意:客户端浏览器发送请求之后一直得不到相应消息,原因是连接套接字被阻塞。
解决方法: 在完成将请求的文件复制到套接字的输出流后,说明数据发送完毕,不再发送更多数据。
socket.shutdownOutput();

觉得有用的别忘给作者点个赞哦,谢谢!

猜你喜欢

转载自blog.csdn.net/weixin_44768070/article/details/106448402