前日博客崩溃之前的学习笔记全部丢失,而其中Socket搭建服务器这一篇我写的程序并不是特别完美。所以再次尝试:
日常科普:
什么是HTTP协议:
超文本传输协议 (HTTP-Hypertext transfer protocol) 是一种详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。HTTP是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型。HTTP是一个无状态的协议,无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。
URL
统一资源定位符(Uniform Resource Locator,缩写为URL)是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它
基本格式如下:
schema://host[:port#]/path/.../[;url-params][?query-string][#anchor]
schema
指定所使用的协议(http,https, ftp)
host
HTTP服务器的IP地址或者域名
port#
HTTP服务器的默认端口是80,这种情况下端口号可以省略
path 访问的资源的路径
query-string
发送给http服务器的数据
anchor-
锚
request
是指从客户端到服务器端的请求消息
Request 消息分为3部分,第一部分叫请求行, 第二部分叫http header, 第三部分是body. header和body之间有个空行
Method表示请求方法,比如"POST","GET",
Path-to-resoure表示请求的资源,
Http/version-number 表示HTTP协议的版本号,当使用的是"GET" 方法的时候, body是为空的,当使用"POST",body不为空,但是没有换行,readline不能读
response
是指服务器端到客户端的响应信息
和Request消息的结构基本一样。 同样也分为三部分,第一部分叫request line, 第二部分叫request header,第三部分是body. header和body之间也有个空行
状态码用来告诉HTTP客户端,HTTP服务器是否产生了预期的Response. HTTP/1.1中定义了5类状态码,1XX 提示信息 - 表示请求已被成功接收,继续处理;2XX 成功 - 表示请求已被成功接收,理解,接受;3XX 重定向 - 要完成请求必须进行更进一步的处理;4XX 客户端错误 - 请求有语法错误或请求无法实现;5XX 服务器端错误 - 服务器未能实现合法的请求
HTTP请求头和响应头的含义
请求头:
Accept: text/html,image/*(浏览器可以接收的类型)
Accept-Charset: ISO-8859-1(浏览器可以接收的编码类型)
Accept-Encoding: gzip,compress(浏览器可以接收压缩编码类型)
Accept-Language: en-us,zh-cn(浏览器可以接收的语言和国家类型)
Host: www.it315.org:80(浏览器请求的主机和端口)
If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT(某个页面缓存时间)
Referer: http://www.it315.org/index.jsp(请求来自于哪个页面)
User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)(浏览器相关信息)
Cookie:(浏览器暂存服务器发送的信息)
Connection: close(1.0)/Keep-Alive(1.1)(HTTP请求的版本的特点)
Date: Tue, 11 Jul 2000 18:23:51 GMT(请求网站的时间)
响应头:
Location: http://www.it315.org/index.jsp(控制浏览器显示哪个页面)
Server:apache tomcat(服务器的类型)
Content-Encoding: gzip(服务器发送的压缩编码方式)
Content-Length: 80(服务器发送显示的字节码长度)
Content-Language: zh-cn(服务器发送内容的语言和国家名)
Content-Type: image/jpeg; charset=UTF-8(服务器发送内容的类型和编码类型)
Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT(服务器最后一次修改的时间)
Refresh: 1;url=http://www.it315.org(控制浏览器1秒钟后转发URL所指向的页面)
Content-Disposition: attachment; filename=aaa.jpg(服务器控制浏览器发下载方式打开文件)
Transfer-Encoding: chunked(服务器分块传递数据到客户端)
Set-Cookie:SS=Q0=5Lb_nQ; path=/search(服务器发送Cookie相关的信息)
Expires: -1(服务器控制浏览器不要缓存网页,默认是缓存)
Cache-Control: no-cache(服务器控制浏览器不要缓存网页)
Pragma: no-cache(服务器控制浏览器不要缓存网页)
Connection: close/Keep-Alive(HTTP请求的版本的特点)
Date: Tue, 11 Jul 2000
18:23:51 GMT(响应网站的时间)
实现原理:
浏览器发送请求:----->
|
服务器接受请求
|
解析请求:获取socket,根据http协议解析socket中的内容
|
封装请求对象: request(输入流,url,method)
封装响应对象: response(输出流,out,url,path,welcome_fi)
|
执行响应 :1>普通请求:直接返回用户请求的资源
执行默认的servlet
2>类请求: 执行类
执行自定义的servler
|
浏览器接受请求:<-------
在搞清这些之后结合几天前的代码:
Server.java:
package xin.stringair.webserver; import java.net.*; import xin.stringair.util.*; public class Server { @SuppressWarnings("static-access") public static void main(String[] args) { ServerSocket mainsocket = null; System.out.println("Server Start\nServer Running..."); PropertiesFind tk = new PropertiesFind(); try { mainsocket = new ServerSocket(Integer.parseInt(tk.getKey("port"))); while (true) { Socket socket = mainsocket.accept(); new ServerThreads(socket).start(); } } catch (Exception e) { e.printStackTrace(); } } }
ServerThreads.java(多线程具体实现)
package xin.stringair.webserver; import java.net.*; public class ServerThreads extends Thread { private Socket socket = null; public ServerThreads(Socket socket) { this.socket = socket; } public void run() { Response tk = new Response(); tk.getResponse(socket, new Request().getRequest(socket)); } }
Response.java(封装响应操作)
package xin.stringair.webserver; import java.io.*; import java.net.*; import xin.stringair.util.*; public class Response { private FileInputStream fis =null; private PrintStream pw = null; private File error = null; private File pass = null; private byte array[] = new byte[1024]; @SuppressWarnings("static-access") public void getResponse(Socket socket,String bpk){ PropertiesFind tk = new PropertiesFind(); try{ error = new File(tk.getKey("path"),tk.getKey("error")); pw = new PrintStream(socket.getOutputStream()); if(bpk != null){ pass = new File(tk.getKey("path"),bpk); if(pass.exists()){ fis = new FileInputStream(pass); pw.println("http:/1.1 200 ok"); pw.println(); int len = 0; while((len = fis.read(array))!=-1) pw.write(array, 0, len); }else{ fis = new FileInputStream(error); pw.println("http:/1.1 200 ok"); pw.println(); int len = 0; while((len = fis.read(array))!=-1) pw.write(array, 0, len); } } }catch(Exception e){ e.printStackTrace(); }finally{ try{ if(fis!=null) fis.close(); if(pw!=null) pw.close(); }catch(Exception e){ e.printStackTrace(); } } } }
Request.java:(封装请求操作)
package xin.stringair.webserver; import java.io.*; import java.net.Socket; public class Request { private BufferedReader br = null; public String getRequest(Socket socket){ try{ br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String str[] = new String[5],line =null; if((line =br.readLine())!=null) str = line.split(" "); if(str[1]!=null) return str[1]; }catch(Exception e){ e.printStackTrace(); } return null; } }
PropertiesFind.java(配置文件读取 )
package xin.stringair.util; import java.io.File; import java.io.FileInputStream; import java.util.Properties; public class PropertiesFind { private static Properties properties; static{ properties = new Properties(); } public static String getKey(String key){ File tk = null; FileInputStream fis = null; try{ tk = new File("F:/JD/Doforjava/WebServer/src/xin/stringair/util/config.properties"); fis = new FileInputStream(tk); properties.load(fis); return properties.getProperty(key); }catch(Exception e){ e.printStackTrace(); } return null; } public static void main(String[] args) { System.out.print(getKey("port")); } }