• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • 瀏覽器與服務端的通信01

    在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>


    版權聲明:本文為Anzhongliu原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/Anzhongliu/article/details/77011185

    智能推薦

    websocketj--隨時隨地在Web瀏覽器中操作你的服務端程序

    0 - 有沒有覺得Linux標準終端界面輸入輸出枯燥無味? 1 - 什么?vmstat命令的輸出數據不直觀?有沒有想過能夠可視化該命令的輸出? 2 - 嘗試過用瀏覽器操作Windows中的cmd嗎? websocketj可以解決以上所有問題,讓你隨時隨地通過瀏覽器訪問任何平臺上的應用程序。 websocketj是什么? 如何使用websocketj? websocketj是如何工作的? 在瀏覽器中...

    1.瀏覽器與web服務器的通信原理概述

      TCP/IP、以太網等技術,是一種規定網絡物理設備和軟件如何工作的一種規則,僅僅學習這些規則是無法看到設備和軟件的內部構造的,本書將重點介紹其內部工作方式 網絡實際上由兩大部分組成: 1. 傳輸信息的機制:網絡控制軟件,交換機、路由器登硬件 2. 瀏覽器、web服務器這些網絡應用程序 目錄 1.1 生成HTTP請求消息 1.2 向DNS服務器查詢web服務器的IP地址 1.3 DNS...

    模擬網站服務器,使用瀏覽器訪問自己編寫的服務端程序,查看網頁效果。

    模擬B\S服務器 模擬網站服務器,使用瀏覽器訪問自己編寫的服務端程序,查看網頁效果。 代碼: 效果:...

    3D游戲編程與設計——游戲對象與圖形基礎章節作業與練習

    3D游戲編程與設計——游戲對象與圖形基礎章節作業與練習 3D游戲編程與設計——游戲對象與圖形基礎章節作業與練習 自學資源 作業內容 1、基本操作演練【建議做】 天空盒的制作: 地圖的制作: 整體效果: 2、編程實踐 項目要求: 項目結構: 代碼詳解: Actions: ISSActionCallback.cs SSAction.cs SSAction...

    猜你喜歡

    FlycoTabLayout 的使用

    FlycoTabLayout 一個Android TabLayout庫,目前有3個TabLayout SlidingTabLayout:參照PagerSlidingTabStrip進行大量修改. 新增部分屬性 新增支持多種Indicator顯示器 新增支持未讀消息顯示 新增方法for懶癌患者 CommonTabLayout:不同于SlidingTabLayout對ViewPager依賴,它是一個不...

    爬蟲項目實戰八:爬取天氣情況

    爬取天氣情況 目標 項目準備 接口分析 代碼實現 效果顯示 寫入本地 目標 根據天氣接口,爬取接下來一周的天氣情況。 項目準備 軟件:Pycharm 第三方庫:requests,BeautifulSoup,csv 接口地址:http://api.k780.com:88/?app=weather.future&weaid=城市名&appkey=10003&sign=b59bc...

    關于web項目的目錄問題

    先給段代碼: 上面這個代碼一直出錯,我不知道原因,后面不停的查找資料發現了問題:我的web項目輸出目錄有問題,因為我也是第一次用idea寫web項目,發現很多bug 其實都沒有太大問題,我們需要注意的是你必須在out這個輸出文件夾中擁有這個文件,out輸出文件夾會默認過濾這些文件...

    二叉搜索樹轉化為雙向鏈表

    題目描述: 輸入一棵二叉搜索樹,將該二叉搜索樹轉換成一個排序的循環雙向鏈表。要求不能創建任何新的節點,只能調整樹中節點指針的指向。 為了讓您更好地理解問題,以下面的二叉搜索樹為例: 我們希望將這個二叉搜索樹轉化為雙向循環鏈表。鏈表中的每個節點都有一個前驅和后繼指針。對于雙向循環鏈表,第一個節點的前驅是最后一個節點,最后一個節點的后繼是第一個節點。 下圖展示了上面的二叉搜索樹轉化成的鏈表。&ldqu...

    Cocos2d-x 2.0 網格動畫深入分析

    [Cocos2d-x相關教程來源于紅孩兒的游戲編程之路CSDN博客地址:http://blog.csdn.net/honghaier] 紅孩兒Cocos2d-X學習園地QQ2群:44208467加群寫:Cocos2d-x 紅孩兒Cocos2d-X學習園地QQ群:249941957[暫滿]加群寫:Cocos2d-x 本章為我的Cocos2d-x教程一書初稿。望各位看官多提建議! Cocos2d-x ...

    精品国产乱码久久久久久蜜桃不卡