浏览器与服务端的通信01

来源:互联网 发布:如何防止sql攻击 编辑:程序博客网 时间:2024/05/16 00:25

在pom.xml中导入两个jar包:jaxen1.1.4和dom4j1.6.1




WebServer类:

/** * 基于Http协议的Web服务端程序 * @author live */public class WebServer {    private ServerSocket server;    /*     * 线程池,管理用于处理客户端请求的线程     */    private ExecutorService threadPool;    /**     * 构造方法,用于初始化服务端程序     * @throws Exception     */    public WebServer() throws Exception{    try{    server=new ServerSocket(ServerContent.ServerPort);    threadPool=Executors.newFixedThreadPool(ServerContent.max_thread);    }catch(Exception e){    throw e;    }    }        public void start(){    try{    while(true){    System.out.println("等待客户端连接");    Socket socket=server.accept();    System.out.println("客户端已连接");    /*     * 将处理该客户端请求的任务交给线程池     */    threadPool.execute(new ClientHandler(socket));        }    }catch(Exception e){    e.printStackTrace();    }    }      public static void main(String[] args) {try{WebServer server=new WebServer();server.start();}catch(Exception e){e.printStackTrace();System.out.println("服务端启动失败!");}}    }

ClientHandler类:

/** * 处理客户端请求 * @author live * */public class ClientHandler implements Runnable{private Socket socket;public ClientHandler(Socket socket){this.socket=socket;}public void run(){try{/*     * HTTP协议中的请求信息格式:     * 请求行       资源                    协议               换行     * GET/index.html  HTTP1.1 CRLF(请求方式) POST     * 消息报头     * 消息正文     *      * 以行为单位发送至服务端 每行结尾以(CR LF)     * CR:回车  LF:换行     * http://localhost:8080     */    //获取输入流,读取客户端发送过来的数据InputStream in=socket.getInputStream();    OutputStream out=socket.getOutputStream();    //读取一行字符串,请求行信息//Method Request-URI Http-version(CRLF)//如://GET/index.html HTTP/1.1CRLF//生成HttpRequest表示请求信息HttpRequest request=new HttpRequest(in);HttpResponse response=new HttpResponse(out);if(request.getUri()!=null){File file=new File(ServerContent.web_root+request.getUri());    if(file.exists()){    //设置状态行    response.setStatus(HttpContent.STATUS_CODE_OK);    //设置响应头    response.setContentType(getContentTypeByFile(file));    responseFile(file,response);    response.setContentLength((int)file.length());    System.out.println("响应客户端完毕!");    }else{    //响应客户端没有该资源(显示个错误页面)    response.setStatus(HttpContent.STATUS_CODE_NOT_FOUND);    //错误页面    file=new File(ServerContent.web_root+File.separator+ServerContent.notFoundPage);//"/notfound.html"    response.setContentType(getContentTypeByFile(file));    response.setContentLength((int)file.length());    responseFile(file,response);    }}       }catch(Exception e){e.printStackTrace();/* * 505 */}finally{try{socket.close();}catch(Exception e){e.printStackTrace();}}}/** * 根据给定的文件获取对应的Content-Type * @param file * @return */private String getContentTypeByFile(File file){/** * 1:首先获取该文件的名字 * 2:获取该文件名的文件类型(文件名的后缀) * 3:根据类型名从ServerContent的types中作为key获取对应的Content-Type */String filename=file.getName();String ext=filename.substring(filename.lastIndexOf(".")+1);String contentType=ServerContent.types.get(ext);System.out.println("contentType:"+contentType);return contentType;}/** *  响应文件 * @param file  * @param response * @throws Exception  */public void responseFile(File file,HttpResponse res) throws Exception{BufferedInputStream bis=null;try{/* * 将该文件中每个字节通过客户端输出流发送给服务端 */ bis=new BufferedInputStream( new FileInputStream(file));/* * 通过Response取出输出流,这里就自动发发送 * 了状态行和响应头 */OutputStream out=res.getOutputStream();int d=-1;while((d=bis.read())!=-1){out.write(d);}}catch(IOException e){throw e;}finally{if(bis!=null){bis.close();}}} }

HttpContent类:

/** * 定义HTTP协议中的相关信息 * @author live * */public class HttpContent {/* * 回车 */public static final int CR=13;/* * 换行 */public static final int LF=10;/** * 状态码:成功 */public static final int  STATUS_CODE_OK=200;/** * 状态描述:成功 */public static final String STATUS_VALUE_OK="Ok";/** * 状态代码:未找到 */public static final int STATUS_CODE_NOT_FOUND=404;/** * 状态描述:未找到 */public static final String STATUS_VALUE_NOT_FOUND="Not Found";/** * 状态代码:错误 */public static final int STATUS_CODE_ERROR=500;/** * 状态描述:错误 */public static final String STATUS_VALUE_ERROR="Internal Server Error";}

ServerContent类:


/** * 记录服务端相关信息 * @author live */public class ServerContent {/* * 服务端口 */public static int ServerPort;//服务端最大并发数public static int max_thread;//服务端应用根目录public static String web_root;/* * 服务器使用的Http协议的版本 */public static String protocol;//根据媒体文件后缀对应Content-Type的类型public static Map<String,String> types=new HashMap<String,String>();/* * 404页面 */public static String notFoundPage;static{//初始化 ServerContent的静态init();}/** * 加载server.xml文件对ServerContent进行初始化 */private static void init(){ try{ SAXReader reader=new SAXReader(); Document doc=reader.read(new FileInputStream(  "config"+File.separator+"server.xml")); Element root=doc.getRootElement(); //解析<service> Element serviceEle=root.element("service"); //解析<connector> Element connEle=serviceEle.element("connector"); protocol=connEle.attributeValue("protocol"); System.out.println("protocol:"+protocol); ServerPort=Integer.parseInt( connEle.attributeValue("port")); System.out.println(" ServerPort:"+ ServerPort); max_thread=Integer.parseInt( connEle.attributeValue("maxThread")); System.out.println(" max_thread:"+  max_thread); //解析<webroot> web_root=serviceEle.elementText("webroot"); System.out.println(" web_root:"+   web_root);  //解析<not-found-page> notFoundPage=serviceEle.elementText("not-found-page"); System.out.println("not-found-page:"+   notFoundPage);  /*  * 解析<type-mappings>  */ Element mappingsEle=root.element("type-mappings"); List<Element> mappingsList=mappingsEle.elements(); for(Element mapping:mappingsList){ types.put(mapping.attributeValue("ext"),  mapping.attributeValue("type")); } System.out.println("types:"+types); }catch(Exception e){ e.printStackTrace(); }}}

HttpRequest类:

/* * 封装Http请求相关内容 */public class HttpRequest {//请求方法  private String method;  //请求资源  private String uri;  //请求协议  private String protocol;  /*   * 构造方法,用于创建HttpRequest实例   *    * @param in 对应客户端输入流,通过该流读取客   * 户端发送过来的请求信息并封装到当前HttpRequest对象中   */  public HttpRequest(InputStream in){  /* * HTTP协议中的请求信息格式: * 请求行       资源                    协议               换行 * GET/index.html  HTTP1.1 CRLF(请求方式) POST * 消息报头 * 消息正文 *  * 以行为单位发送至服务端 每行结尾以(CR LF) * CR:回车  LF:换行 * http://localhost:8080 */  try{      //读取一行字符串,请求行信息//Method Request-URI Http-version(CRLF)//如://GET/index.html HTTP/1.1CRLF String line=readline(in); if(line.length()>0){ String[] data=line.split("\\s"); method=data[0]; uri=data[1]; protocol=data[2]; }  }catch(IOException e){  e.printStackTrace();    }  }      /**   * 从给定的输入流中读取一行字符窜并返回。   * 当读取到CR LF时认为一行结束   *       13 10   *   * @param in   * @return   * @throws IOException   */  private String readline(InputStream in)throws IOException{/* * 顺序的从流中读取每个字节并转换为对应的字符 * 然后拼接在一起,直到连续读取了CR LF时停止 * 并将拼接的字符串返回 */  StringBuilder builder=new StringBuilder();  try{  int ch1=-1,ch2=-1;  while((ch2=in.read())!=-1){  if(ch1==HttpContent.CR&&ch2==HttpContent.LF){  break;  }  builder.append((char)ch2);  ch1=ch2;  }  return builder.toString().trim();  }catch(IOException e){  throw e;  }  }public String getMethod() {return method;}public String getUri() {return uri;}public String getProtocol() {return protocol;}  }

HttpResponse类:

/** * 封装Http响应 * HTTP响应格式 * 1:状态行 * 2:响应头 * 3:响应正文 *  * 状态由3部分组成:协议版本,数字形式的状态代码,状态描述 * 格式:Http_Version Status-code  Reason-Phrase  CRLF *  * 例如:HTTP/1.1  200   OK  CRLF *  * 状态代码第一个数字有5种: * 1xx:指示信息,表示请求已接收,继续处理。 * 2xx:成功,表示请求已接收,理解,接受 * 3xx:重定向,要完成请求需要更进一步的操作 * 4xx:客户端错误,请求语法错误或请求无法实现 * 5xx:服务端错误,服务端未能实现该请求 * 常见的状态码及描述: * 200 OK     客户端请求成功  * 400 Bad   Request    客户端请求有语法错误,服务端不能理解 * 401 Unauthonzed      请求未授权 * 403  Forbidden  服务端收到请求,但是拒绝提供服务 * 404   Not Found  请求的资源不存在 * 500   Internal  Server  Error   服务器发生了不可预期的错误 * 503  Service Unavailable  服务器当前不能够处理客户端请求 *                 * 回应客户端对应的资源     * HTTP中响应的格式:     * 1:状态行     * 2:响应头     * 3:响应正文     * 状态行格式:     * HTTP-Version Status_code Reason_phrase CRLF     * HTTP协议                     状态代码                状态描述CRLF     * 例如:     * HTTP/1.1  200 OK  CRLF     * 2:响应头     * 响应头注明很多返回的信息,按行输出     * 常见:     * Content-Type:用来指明发送给接收者的媒体类型     * 常见的Content-Type:     * text/html:HTML格式文件(网页)     * text/xml:XML格式文件     * image/gif:gif格式图片     * image/jpeg:jpeg格式图片     * image/png:png格式图片     * Content-Length,用来指明发送给接受者实体正文的长度     * 简单的说就是发送过去的数据的字节量     *      * HTTP协议要求实际响应客户端时的数据格式:     * HTTP/1.1  200 OK  CRLF       状态行     * Content-Type:text/html  CRLF 响应头信息     * Content-Length:100CRLF       响应头信息     * CRLF 单独发送CRLF指明响应头全部发送完毕     * DATA 实际数据     * TLD   type  length  data     *     * @author live */public class HttpResponse {private OutputStream out;/* * 响应格式中所需要的信息 */private int status;//状态行中的状态代码private String contentType;//响应头中的正文类型private int contentLength;//响应头中的正文长度//表示响应状态行以及响应头信息是否已经发送过private boolean hasPrintHeader;//记录所有可用状态码及描述。private Map<Integer,String> statusMap;/* * 构造方法 * @param out  对应客户端的输出流,通过该输出流 * 将消息响应给客户端 */     public HttpResponse(OutputStream out){     this.out=out;     statusMap=new HashMap<Integer,String>();     statusMap.put(HttpContent.STATUS_CODE_OK,HttpContent.STATUS_VALUE_OK);     statusMap.put(HttpContent.STATUS_CODE_NOT_FOUND,HttpContent.STATUS_VALUE_NOT_FOUND);     statusMap.put(HttpContent.STATUS_CODE_ERROR,HttpContent.STATUS_VALUE_ERROR);               }public OutputStream getOutputStream() throws Exception {if(!hasPrintHeader){/* * 获取输出流前,将状态行,响应头信息自动发送 *///发送状态行    println(ServerContent.protocol+" "+status+" "+statusMap.get(status));//发送响应头信息    println("ContentType:"+contentType);    println("ContentLength:"+contentLength);    println("");//单独发送空行表示响应头发送完毕hasPrintHeader=true;}return out;}public int getStatus() {return status;}public void setStatus(int status) {this.status = status;}public String getContentType() {return contentType;}public void setContentType(String contentType) {this.contentType = contentType;}public int getContentLength() {return contentLength;}public void setContentLength(int contentLength) {this.contentLength = contentLength;}public Map<Integer, String> getStatusMap() {return statusMap;}/* * 将给定的一行字符串以HTTP协议格式要求按行写出 */private void println(String str) throws Exception{try {out.write(str.getBytes("ISO8859-1"));out.write(HttpContent.CR);out.write(HttpContent.LF); } catch (UnsupportedEncodingException e) {e.printStackTrace();System.out.println("不受支持的编码");throw e;} catch (IOException e) {e.printStackTrace();throw e;}}}

server配置文件:

<?xml version="1.0" encoding="UTF-8"?><server>    <service>    <connector protocol="HTTP/1.1" port="8888" maxThread="100"/>        <webroot>webapps</webroot>    <not-found-page>notfound.html</not-found-page>    </service>    <!-- 不同媒体类型对应的Content-Type值 --><type-mappings>   <type-mapping ext="html" type="text/html"/>   <type-mapping ext="png" type="image/png"/>   <type-mapping ext="xml" type="text/xml"/>   <type-mapping ext="jpeg" type="image/jpeg"/>   <type-mapping ext="gif" type="image/gif"/>    <type-mapping ext="ico" type="image/ico"/></type-mappings></server>


原创粉丝点击