javaWeb服务器socket实现

目标:采用Socket和多线程技术,实现一个java Web服务器,加深对HTTP的认识。

新建java项目

       webServer

新建java文件

      WebServer.java

       Processor.java

 

  一、HTTP协议的作用原理

  WWW是以Internet作为传输媒介的一个应用系统,WWW网上最基本的传输单位是Web网页。WWW的工作基于客户机/服务器计算模型, 由Web 浏览器(客户机)和Web服务器(服务器)构成,两者之间采用超文本传送协议(HTTP)进行通信。HTTP协议是基于TCP/IP协议之上的协议,是 Web浏览器和Web服务器之间的应用层协议,是通用的、无状态的、面向对象的协议。HTTP协议的作用原理包括四个步骤:

  (1) 连接:Web浏览器与Web服务器建立连接,打开一个称为socket(套接字)的虚拟文件,此文件的建立标志着连接建立成功。

  (2) 请求:Web浏览器通过socket向Web服务器提交请求。HTTP的请求一般是GET或POST命令(POST用于FORM参数的传递)。GET命令的格式为:

  GET 路径/文件名 HTTP/1.0

  文件名指出所访问的文件,HTTP/1.0指出Web浏览器使用的HTTP版本。

  (3) 应答:Web浏览器提交请求后,通过HTTP协议传送给Web服务器。Web服务器接到后,进行事务处理,处理结果又通过HTTP传回给Web浏览器,从而在Web浏览器上显示出所请求的页面。
 
  例:假设客户机与
www.mycompany.com:8080/mydir/index.html建立了连接,就会发送GET命令:GET /mydir/index.html HTTP/1.0。主机名为www.mycompany.com的Web服务器从它的文档空间中搜索子目录mydir的文件index.html。如果找到该文件,Web服务器把该文件内容传送给相应的Web浏览器。

  为了告知 Web浏览器传送内容的类型,Web服务器首先传送一些HTTP头信息,然后传送具体内容(即HTTP体信息),HTTP头信息和HTTP体信息之间用一个空行分开。
常用的HTTP头信息有:

  ① HTTP 1.0 200 OK

  这是Web服务器应答的第一行,列出服务器正在运行的HTTP版本号和应答代码。代码“200 OK”表示请求完成。

  ② MIME_Version:1.0

  它指示MIME类型的版本。

  ③ content_type:类型

  这个头信息非常重要,它指示HTTP体信息的MIME类型。如:content_type:text/html指示传送的数据是HTML文档。

  ④ content_length:长度值

  它指示HTTP体信息的长度(字节)。

  (4) 关闭连接:当应答结束后,Web浏览器与Web服务器必须断开,以保证其它Web浏览器能够与Web服务器建立连接。

  二、Java实现Web服务器功能的程序设计

  根据上述HTTP协议的作用原理,实现GET请求的Web服务器程序的方法如下:

  (1) 创建ServerSocket类对象,监听端口8080。这是为了区别于HTTP的标准TCP/IP端口80而取的;

  (2) 等待、接受客户机连接到端口8080,得到与客户机连接的socket;

  (3) 创建与socket字相关联的输入流instream和输出流outstream;

  (4) 从与socket关联的输入流instream中读取一行客户机提交的请求信息,请求信息的格式为:GET 路径/文件名 HTTP/1.0

  (5) 从请求信息中获取请求类型。如果请求类型是GET,则从请求信息中获取所访问的HTML文件名。没有HTML文件名时,则以index.html作为文件名;

  (6) 如果HTML文件存在,则打开HTML文件,把HTTP头信息和HTML文件内容通过socket传回给Web浏览器,然后关闭文件。否则发送错误信息给Web浏览器;

  (7) 关闭与相应Web浏览器连接的socket字。

 

java代码实现:

WebServer.java

[java]  view plain copy print ?
  1. package com.webserver;  
  2. import java.io.IOException;  
  3. import java.net.ServerSocket;  
  4. import java.net.Socket;  
  5.   
  6. public class WebServer {  
  7.   
  8.     /** 
  9.      * @param args 
  10.      */  
  11.   
  12.     public void serverStart(int port) {  
  13.         try {  
  14.             ServerSocket serverSocket = new ServerSocket(port);  
  15.             while (true) {  
  16.                 /* accept()方法:Listens for a connection to be made to this socket and accepts it.  
  17.                  * The method blocks until a connection is made.  
  18.                  */  
  19.                 Socket socket = serverSocket.accept();  
  20.                 new Processor(socket).start();  
  21.             }  
  22.         } catch (IOException e) {  
  23.             // TODO Auto-generated catch block  
  24.             e.printStackTrace();  
  25.         }  
  26.   
  27.     }  
  28.   
  29.     public static void main(String[] args) {  
  30.         // TODO Auto-generated method stub  
  31.   
  32.         int port = 8080;//定义服务器端口号,该端口号不可被其他进程占用  
  33.         if (args.length == 1) {  
  34.             port = Integer.parseInt(args[0]);  
  35.         }  
  36.         new WebServer().serverStart(port);//调用服务器启动方法  
  37.   
  38.     }  
  39.   
  40. }  


Processor.java

[java]  view plain copy print ?
  1. package com.webserver;  
  2. import java.io.BufferedReader;  
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileNotFoundException;  
  6. import java.io.IOException;  
  7. import java.io.InputStream;  
  8. import java.io.InputStreamReader;  
  9. import java.io.PrintStream;  
  10. import java.net.Socket;  
  11.   
  12. public class Processor extends Thread {  
  13.   
  14.     private Socket socket;  
  15.     private InputStream in;  
  16.     private PrintStream out;  
  17.     public final static String WEB_ROOT = "E:\\projects\\javaprojects\\htmls";//该目录下需要存在html文档  
  18.     public Processor(Socket socket) {  
  19.         this.socket = socket;  
  20.           
  21.         try {  
  22.             in = socket.getInputStream();  
  23.             out = new PrintStream(socket.getOutputStream());  
  24.         } catch (IOException e) {  
  25.           
  26.             e.printStackTrace();  
  27.         }  
  28.           
  29.     }  
  30.   
  31.     public void run() {  
  32.         String fileName = this.parse(in);  
  33.         this.sendFile(fileName);  
  34.     }  
  35.   
  36.     public String parse(InputStream in) {  
  37.   
  38.         BufferedReader br = new BufferedReader(new InputStreamReader(in));  
  39.         String fileName = null;  
  40.         try {  
  41.             String httpMessage = br.readLine();  
  42.             String[]content = httpMessage.split(" ");//协议状态号,名称,版本号  
  43.               
  44.             //如果客戶端輸入协议错误则返回错误页面  
  45.             if(content.length != 3) {  
  46.                 this.sendErrorMessage(400"Client query error!");  
  47.                 return null;  
  48.             }  
  49.             //否则输出协议信息  
  50.             System.out.println("code:"+content[0]+",filename"+content[1]+  
  51.                     "httpversion:"+content[2]);  
  52.               
  53.             fileName = content[1];  
  54.         } catch (IOException e) {  
  55.               
  56.             e.printStackTrace();  
  57.         }  
  58.         return fileName;  
  59.   
  60.     }  
  61.   
  62.     //错误页面输出方法  
  63.     public void sendErrorMessage(int ErrorCode, String ErrorContent) {  
  64.   
  65.         out.println("HTTP/1.0 "+ErrorCode+" "+ErrorContent);  
  66.         out.println("content-type: text/html");  
  67.         out.println();  
  68.         out.println("<html>");  
  69.           
  70.         out.println("<title>Error Message");  
  71.         out.println("</title>");  
  72.         out.println("<body>");  
  73.         out.println("<h1>ErrorCode:"+ErrorCode+",Message:"+ErrorContent+"</h1>");         
  74.           
  75.         out.println("</body>");  
  76.         out.println("</html>");  
  77.           
  78.         out.flush();  
  79.         out.close();  
  80.         try {  
  81.             in.close();  
  82.         } catch (IOException e) {  
  83.             // TODO Auto-generated catch block  
  84.             e.printStackTrace();  
  85.         }  
  86.     }  
  87.   
  88.     public void sendFile(String fileName) {  
  89.         File file = new File(Processor.WEB_ROOT+fileName);  
  90.         if(!file.exists()) {  
  91.             this.sendErrorMessage(404"file not found");  
  92.             return ;  
  93.         }  
  94.         try {  
  95.             InputStream in = new FileInputStream(file);  
  96.             byte content[] = new byte[(int)file.length()];  
  97.             try {  
  98.                 in.read(content);  
  99.                 out.println("HTTP/1.0 200 queryfile");  
  100.                 out.println("content-length:"+content.length);  
  101.                 out.println();  
  102.                 out.write(content);  
  103.                 out.flush();  
  104.                 in.close();  
  105.             } catch (IOException e) {  
  106.                   
  107.                 e.printStackTrace();  
  108.             }  
  109.         } catch (FileNotFoundException e) {  
  110.           
  111.             e.printStackTrace();  
  112.         }  
  113.           
  114.     }  
  115. }  


运行该项目无异常时即可,在IE浏览器中输入:

随即出现相应页面。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要手写一个 JavaWeb 服务器,需要掌握以下步骤: 1. 创建一个 ServerSocket 对象,指定服务器监听的端口号; 2. 在一个循环中,不断接收客户端的请求,每次接收到一个请求,就创建一个 Socket 对象与客户端进行连接; 3. 创建一个线程池,来处理客户端的请求。每当有一个客户端连接时,就将该客户端的请求交给线程池去处理; 4. 在线程池中,根据请求的 URL,读取对应的静态资源文件,并将其返回给客户端; 5. 如果请求的是动态资源,即需要执行 Java 代码生成内容的,那么就需要在服务器端编写对应的 Servlet。在处理请求时,根据 URL 匹配对应的 Servlet,并调用其相应的方法生成内容,并将其返回给客户端; 6. 在处理完客户端请求之后,需要关闭连接。 下面是一个简单的 JavaWeb 服务器的示例代码: ```java import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SimpleServer { private final static int PORT = 8080; private final static String WEB_ROOT = "src/main/resources/"; public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(PORT); ExecutorService threadPool = Executors.newFixedThreadPool(10); System.out.println("Server is running at http://localhost:" + PORT); while (true) { Socket socket = serverSocket.accept(); Runnable task = () -> { try { String request = getRequest(socket.getInputStream()); String url = parseUrl(request); if (url.equals("/")) { url = "/index.html"; } String filePath = WEB_ROOT + url; File file = new File(filePath); if (file.exists() && file.isFile()) { String contentType = guessContentType(filePath); byte[] content = readFile(file); sendResponse(socket.getOutputStream(), "HTTP/1.1 200 OK", contentType, content); } else { sendResponse(socket.getOutputStream(), "HTTP/1.1 404 Not Found", "text/html", "404 Not Found".getBytes()); } } catch (IOException e) { e.printStackTrace(); } finally { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } }; threadPool.execute(task); } } private static String getRequest(java.io.InputStream input) throws IOException { byte[] buffer = new byte[1024]; int len = input.read(buffer); return new String(buffer, 0, len); } private static String parseUrl(String request) { int index1, index2; index1 = request.indexOf(' '); if (index1 != -1) { index2 = request.indexOf(' ', index1 + 1); if (index2 > index1) { return request.substring(index1 + 1, index2); } } return null; } private static byte[] readFile(File file) throws IOException { try (FileInputStream fis = new FileInputStream(file)) { byte[] buffer = new byte[fis.available()]; fis.read(buffer); return buffer; } } private static String guessContentType(String fileName) { if (fileName.endsWith(".html") || fileName.endsWith(".htm")) { return "text/html"; } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) { return "image/jpeg"; } else if (fileName.endsWith(".gif")) { return "image/gif"; } else if (fileName.endsWith(".png")) { return "image/png"; } else if (fileName.endsWith(".css")) { return "text/css"; } else if (fileName.endsWith(".js")) { return "application/javascript"; } else { return "application/octet-stream"; } } private static void sendResponse(OutputStream output, String status, String contentType, byte[] content) throws IOException { output.write((status + "\r\n").getBytes()); output.write(("Content-Type: " + contentType + "\r\n").getBytes()); output.write(("Content-Length: " + content.length + "\r\n").getBytes()); output.write("\r\n".getBytes()); output.write(content); output.flush(); } private static void sendResponse(OutputStream output, String status, String contentType, String content) throws IOException { sendResponse(output, status, contentType, content.getBytes()); } } ``` 这个示例代码实现了一个简单的静态资源服务器。当客户端请求一个 URL 时,服务器会读取对应的静态资源文件,如果找到了文件,则将其返回给客户端。如果找不到文件,则返回一个 404 Not Found 响应。在这个示例中,我们使用了线程池来处理客户端请求,通过解析 HTTP 请求报文,来获取客户端请求的 URL,然后再根据 URL 来读取对应的资源文件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值