常識を導入し、手動でtomcat1を実装Tomcat--

1. HTTPプロトコル

1.1特長

1.サポートするクライアント/サーバモデル。
2.シンプルかつ高速:サーバーへの顧客サービス要求、代わりにリクエストメソッドとパスを送ります。リクエスト方法は、一般的にGET、HEAD、POSTを使用していました。各メソッドは、クライアントはサーバーの異なる種類を提供します。シンプルなHTTPプロトコルのためには、HTTPサーバーは、プログラム小規模になりますので、コミュニケーションは非常に高速です。
3.フレキシブル:HTTPデータ・オブジェクトの任意のタイプの送信を可能にします。コンテンツタイプでマークされている伝送のタイプです。
4.接続なし:なし制限を意味しないが、接続ごとに1つだけの要求を取り付けていません。サーバがクライアントの要求を処理し、顧客の応答を受信した後、すなわち、切断。このようにして、送信時間を節約することができます。
5.ステートレス:HTTPプロトコルはステートレスなプロトコルです。いかなる状態は、トランザクション処理とメモリのためのプロトコルではありません。接続ごとに送信されるデータの量をもたらすことができる情報の前に必要なその後の処理は、それが再送信されなければならないことを状態手段の欠如は、増加された場合。一方、それはより速く、サーバーに応じて、以前の情報を必要としません。

1.2要求部

 要求ライン、要求ヘッダー、リクエストボディ:HTTPリクエストは、3つの部分、すなわち、から成り

1.2.1要求行

この方法は、スペース、URIによって分離され、リクエストラインシンボルで始まり、プロトコルバージョンは、次の形式の要求が続く:方法のRequest-URI HTTP-版CRLF  

1.メソッドは、要求メソッドを表します。

2.リクエストURIは、ユニフォームリソース識別子です。

3. HTTP-バージョンリクエストのHTTPプロトコルのバージョンを表します。

4.キャリッジリターンとラインCRLF表す(添加の終了としてCRLFを、それが別のキャラクタCRまたはLFはできません)。

例えば:POST /index.htmlがHTTP / 1.1(ラインフィード)

1.2.2要求ヘッダー

クライアントのリクエストヘッダをサーバに送信することができますことは、追加情報を要求し、クライアント自身の情報。

フォーマット:空白行で区切られたキーと値のペアの形式で要求ヘッダーは、最終的にリクエストヘッダの終了を示します。

例えば:

k1:v1
k2:v2
k3:v3

username=xxx

一般的なリクエストヘッダは
受け入れ
受け入れリクエストヘッダフィールドは、クライアントが受け入れられた情報の種類を指定するために使用されます。例えば:受け入れ:画像/ gif形式を、クライアントの願いはリソースのGIF画像フォーマットを受信することを示し、受け入れ:text / htmlで、クライアントがHTMLテキストを受け入れることを望んでいることを示しています。
文字セットは、受け入れ
文字セットリクエストヘッダフィールドがクライアントによって受け入れられた文字セットを指定するために使用されて受け入れます。例えば::. ISO-文字セットを受け入れ -8859-1、2312 このフィールドは要求メッセージに設定されていない場合は、デフォルトの文字セットは、任意の許容することができます。
受け入れ-encoding
受け入れエンコードリクエストヘッダフィールドは受け入れに似ているが、それはコンテンツのエンコードを指定するための許容されます。例:要求がメッセージサーバにこのフィールドを設定されていない場合にAccept-エンコーディングを:. gzip.deflateを様々なコンテンツをエンコードするため、クライアントが許容されていることを前提としています。
言語受け入れる
受け入れに似たAccept-Languageリクエストヘッダフィールドを、自然言語を指定するために使用されます。例えば:受け入れ言語:. ZH -cn 要求はメッセージヘッダフィールドに設定されていない場合、サーバはクライアントがさまざまな言語を受け入れることができていることを前提としています。
許可は
承認リクエストヘッダフィールドは、主にクライアントがリソースを表示する権限を持っていることを証明するために使用されます。サーバは401(不正)の応答コードを受信した場合、ブラウザは、ページにアクセスするときは、要求のAuthorizationリクエストヘッダフィールドは、含まれている検証するためにサーバを必要と送ることができます。
ホスト(送信要求、ヘッダフィールドが必要とされます)
ホストリクエストヘッダフィールドは、主に要求されたリソースのインターネットホストおよびポート番号を指定するために使用される、それは通常、HTTP URLから抽出され、例えばされています。
私たちはあなたのブラウザに入力します。http://www.guet.edu.cn/index .htmlの
ブラウザによって送信された要求メッセージは、ホスト要求ヘッダーフィールドを含むことになる、として次の
ホスト:www.guet.edu.cnは、
ポート番号を指定した場合、本明細書中にデフォルトのポート番号80を使用し、次のようになる。ホスト: www.guet.edu.cn:ポート番号の指定
のUser-Agentを
、我々はインターネットフォーラムを上陸させた、あなたは、多くの場合、オペレーティングシステムの名前とバージョンを示していますいくつかのウェルカムメッセージ、あなたが使用しているブラウザの名前が表示されます多くの場合、多くの人々は非常に不思議な感じさせるのバージョンでは、実際には、要求情報にUser-Agentヘッダフィールドからサーバーアプリケーションを取得することです。User-Agentリクエストヘッダフィールドは、そのオペレーティングシステム、ブラウザにクライアントを可能にし、他の属性は、サーバーに指示します。しかし、ヘッダフィールドが必要とされていない、あなたはブラウザ自分自身を書いた場合、サーバは、私たちのメッセージを知ることができません、User-Agentリクエストヘッダフィールドを使用しないでください。
例としては、ヘッダを要求:
HTTP / 1.1 /form.html GET(CRLF)
受け入れ:画像/ GIF、画像/ X-xbitmap、画像/ JPEG、ファイルアプリケーション/ X-ショックウェーブ-フラッシュ、ファイルアプリケーション/ vnd.ms-エクセル、ファイルアプリケーション/ VND Powerpoint-.ms、アプリケーション/ mswordは、* / *(CRLF)
受け入れ言語:ZH-CN(CRLF)
のAccept-エンコード:GZIP、DEFLATEを(CRLF)
変更-開始:水曜日、2007年1月5日午前11時21分25秒GMT(CRLF)
の場合-なし-マッチ:W / "80b1a4c018f3c41:8317"(CRLF)
のUser-Agent:Mozillaの/ 4.0(互換; MSIE6.0。 Windows NTの5.0)(CRLF)
ホスト:www.guet.edu.cn(CRLF)
接続:キープアライブ(CRLF)
(CRLF)

1.2.3リクエストボディ

POSTリクエストのボディモードのみ。リクエストの内容の後に要求ブランクラインヘッド本体、サービス配信クライアント側にデータを搬送するための担体であります

応答の1.3一部

 要求メッセージを受信し、解釈した後、サーバは、HTTPレスポンスメッセージを返します。

ステータスライン、メッセージヘッダ、応答体:HTTPレスポンスは、3つの部分、すなわち、で構成されています

1.3.1ステータス行

ステータスラインの形式は次のとおりです。HTTP-バージョンのステータスコード理由-フレーズCRLF

HTTP-バージョンは、HTTPプロトコルサーバーのバージョンを示します。

ステータスコードは、応答ステータスコードを送り返すサーバーを表します。

理由-フレーズステータスコードのテキスト説明を表します。

1.3.2メッセージヘッダ

  サーバーへのクライアントと組成に応じて、サーバーからクライアントへのHTTPリクエストメッセージ。要求および応答メッセージは、スタートラインであり、メッセージヘッダ(オプション)、空行(CRLFラインのみ)、メッセージ本体(要求メッセージ、要求ラインが開始ライン、応答メッセージ、ステータス行は、開始行です) (任意)コンポーネント。

HTTPメッセージヘッダは、共通ヘッダ、要求ヘッダ、応答ヘッダ、ヘッダ・エンティティを含みます。
各ヘッダフィールドは名前+である「:」+、メッセージヘッダフィールドの名前は、ケース鈍感スペース+値の組成物です。

図1に示すように、一般的なヘッダ
すべての要求メッセージと応答メッセージの数が少ないため、だけでなく、メッセージの送信のために送信されるエンティティの通常のヘッダ内のヘッダフィールド。
EG:
キャッシュ制御コマンドはキャッシュを指定するために使用され、命令キャッシュが単方向である(バッファコマンド応答は、必ずしも要求に表示されません)、および独立した命令キャッシュ(別のメッセージ処理へのメッセージに影響を与えませんプラグマのヘッダフィールドHTTP1.0の使用と同様キャッシュ機構)。
ノーキャッシュを(要求または応答メッセージを示すことができないキャッシュ)、無店舗、MAX-:キャッシュ命令要求が含まれていない年齢、MAX-陳腐、MIN-新鮮なキャッシュのみ-IF-、
キャッシュ命令応答含みます:パブリック、プライベート、キャッシュ-NO、NO-ストア、変換-NO、MUST-再検証、プロキシ再検証、MAXAGE、S-MAXAGE。
EG:IEブラウザ(クライアント)を示すためにないキャッシュ・ページ、サーバ側次のようにJSPプログラムを書くことができる。response.sehHeader(「キャッシュ・コントロール」、「キャッシュ-NO」)
//response.setHeader("Pragma","no-cacheを「);アクションは上記のコードに対応する、通常の両方/ /の組み合わせ
、このコードは、応答メッセージに共通のヘッダーフィールドで提供されるが送信:のCache-Control:ノーキャッシュ


日付共通ヘッダフィールドは、メッセージの生成日時を示します

接続通常のヘッダ・フィールドは、送信オプションが接続を指定可能にします。例えば、連続接続が指定した、または指定された応答が終了した「クローズ」オプション、通知サーバ、近くに接続

図2に示すように、リクエストヘッダ
自体についての要求された情報の付加情報とクライアントとサーバにクライアントを許可するリクエスト・ヘッダー。
一般的なリクエストヘッダは
受け入れ
受け入れリクエストヘッダフィールドは、クライアントが受け入れられた情報の種類を指定するために使用されます。例えば:受け入れ:画像/ gif形式を、クライアントの願いはリソースのGIF画像フォーマットを受信することを示し、受け入れ:text / htmlで、クライアントがHTMLテキストを受け入れることを望んでいることを示しています。
文字セットは、受け入れ
文字セットリクエストヘッダフィールドがクライアントによって受け入れられた文字セットを指定するために使用されて受け入れます。例えば::. ISO-文字セットを受け入れ -8859-1、2312 このフィールドは要求メッセージに設定されていない場合は、デフォルトの文字セットは、任意の許容することができます。
受け入れ-encoding
受け入れエンコードリクエストヘッダフィールドは受け入れに似ているが、それはコンテンツのエンコードを指定するための許容されます。例:要求がメッセージサーバにこのフィールドを設定されていない場合にAccept-エンコーディングを:. gzip.deflateを様々なコンテンツをエンコードするため、クライアントが許容されていることを前提としています。
言語受け入れる
受け入れに似たAccept-Languageリクエストヘッダフィールドを、自然言語を指定するために使用されます。例えば:受け入れ言語:. ZH -cn 要求はメッセージヘッダフィールドに設定されていない場合、サーバはクライアントがさまざまな言語を受け入れることができていることを前提としています。
許可は
承認リクエストヘッダフィールドは、主にクライアントがリソースを表示する権限を持っていることを証明するために使用されます。サーバは401(不正)の応答コードを受信した場合、ブラウザは、ページにアクセスするときは、要求のAuthorizationリクエストヘッダフィールドは、含まれている検証するためにサーバを必要と送ることができます。
ホスト(送信要求、ヘッダフィールドが必要とされます)
ホストリクエストヘッダフィールドは、主例えば、通常はHTTP URLから抽出された要求されたリソースのインターネットホストとポート番号を指定するために使用されます。
我々は、ブラウザで次のコマンドを入力します。http://www.guet.edu.cn/index .htmlの
ブラウザによって送信された要求メッセージは、ホスト要求ヘッダーフィールドを含むことになる、として次の
ホスト:www.guet.edu.cnは、
ポート番号を指定した場合、本明細書中にデフォルトのポート番号80を使用し、次のようになる。ホスト:www.guet.edu.cn:ポート番号の指定
のUser-Agentを
、我々はインターネットフォーラムを上陸させた、あなたは、多くの場合、オペレーティングシステムの名前とバージョンを示していますいくつかのウェルカムメッセージ、あなたが使用しているブラウザの名前が表示されます多くの場合、多くの人々は非常に不思議な感じさせるのバージョンでは、実際には、要求情報にUser-Agentヘッダフィールドからサーバーアプリケーションを取得することです。User-Agentリクエストヘッダフィールドは、そのオペレーティングシステム、ブラウザにクライアントを可能にし、他の属性は、サーバーに指示します。しかし、ヘッダフィールドが必要とされていない、あなたはブラウザ自分自身を書いた場合、サーバは、私たちのメッセージを知ることができません、User-Agentリクエストヘッダフィールドを使用しないでください。
例としては、ヘッダを要求:
HTTP / 1.1 /form.html GET(CRLF)
受け入れ:画像/ GIF、画像/ X-xbitmap、画像/ JPEG、ファイルアプリケーション/ X-ショックウェーブ-フラッシュ、ファイルアプリケーション/ vnd.ms-エクセル、ファイルアプリケーション/ VND Powerpoint-.ms、アプリケーション/ mswordは、* / *(CRLF)
のAccept-言語:ZH-CN(CRLF)
受け入れエンコード:gzipで、デフレート(CRLF)
を変更される場合--ので:水曜日、2007年1月5日午前11時21分25秒GMT(CRLF)
の場合-なし-マッチ:W / "80b1a4c018f3c41:8317"(CRLF)
のUser-Agent: Mozillaの/ 4.0(互換; MSIE6.0;のWindows NT 5.0)(CRLF)
ホスト:www.guet.edu.cn(CRLF)
接続:キープアライブ(CRLF)
(CRLF)

図3は、レスポンスヘッダ
レスポンスヘッダは、サーバがステータスラインに応答し、次のステップへのアクセス要求-URIによって識別されるリソースに、サーバーの詳細情報に追加情報を通過させることができません。
一般的な応答ヘッダー
の場所
新しい場所にリダイレクトするための場所レスポンスヘッダフィールドの受信機。場所レスポンスヘッダフィールドは、時間にドメイン名を置き換えるために使用されます。
サーバー
サーバーのレスポンスヘッダフィールドは、情報要求を処理するサーバソフトウェアが含まれています。ヘッダフィールドは、User-Agentリクエストの対応です。以下の通りである
:例えば、サーバ応答ヘッダーフィールド
サーバー:Apacheの-コヨーテ/ 1.1
WWW認証が
WWW認証応答ヘッダフィールドは401(不正な)応答メッセージに含まれている必要があり、クライアント401は、応答メッセージの時刻を受信し、そしてAuthorizationヘッダフィールドサーバが検証するための要求を送信するとき、サーバの応答ヘッダは、ヘッダフィールドを含んでいます。
例えば:WWW認証:基本レルム 「!ベーシック認証テスト」= // サーバは要求されたリソース上で見ることができ、基本的な認証メカニズムを使用しています。


4、のエンティティヘッダ
要求および応答メッセージは、エンティティを送信することができます。エンティティヘッダフィールドによってエンティティ、およびエンティティ体組成が、一緒にするために、テキストを送信するために、エンティティヘッダフィールドとエンティティということを意味するものではありません、あなただけのエンティティヘッダフィールドを送ることができます。エンティティは、エンティティボディに定義ヘッダ:メタ情報リソース(例えばエンティティボディかどうか)と、要求識別。
共通のエンティティヘッダ
のコンテンツをコードする
コンテンツ符号化エンティティヘッダフィールドはメディアタイプの修飾子として使用され、符号化を示す値が参照されるContent-Typeヘッダフィールドを得ることが、追加コンテンツのエンティティボディに適用されていますメディアタイプは、対応する復号化機構を使用しなければなりません。、EGのような文書を記録するためのコンテンツ圧縮符号化方式:コンテンツ・エンコード:gzipの
コンテンツ言語
コンテンツ言語エンティティヘッダフィールドが使用自然言語リソースを記述する。設定されていないこのフィールドは、すべての言語の読みに実体コンテンツが利用可能になると考えられている
ことで。EG:コンテンツ言語:DA
コンテンツ長
進数のエンティティボディの長さを示すLengthヘッダフィールドを表すためにバイト単位で格納されているコンテンツ・エンティティ。
タイプコンテンツ
コンテンツ用語Typeヘッダフィールドはメディアタイプの受信側エンティティボディにエンティティを示しています。EG:
コンテンツタイプ:テキスト/ HTML;のcharset = ISO-8859-1
のContent-Type:テキスト/ HTML;のcharset = GB2312
のLast-Modified
リソースの最終更新日時表示のためのLast-Modifiedエンティティヘッダフィールド。
有効期限
ヘッダフィールドはレスポンスの期限が切れ、エンティティの日付と時間を与える有効期限。(、ページがキャッシュから直接ロード、再び訪問された応答時間の短縮にアクセスし、サーバーの負荷を軽減する場合)ページのプロキシサーバーやブラウザのためには、一定期間後にキャッシュを更新し、私たちが使用することができますが、エンティティヘッダフィールド指定されたページの有効期限時間が期限切れ。EGは:有効期限:木、2006年9月15日夜四時23分12秒GMT
HTTP1.1クライアントとキャッシュの有効期限が切れていると考えられ(ゼロを含む)その他の違法な日付形式でなければなりませんが。例:キャッシュしないページへのブラウザためには、我々はまた、使用が次のようにエンティティヘッダフィールド、0に設定し、JSPプログラムを有効期限することができます(「有効期限」「response.setDateHeaderは 0」);

2.ソケットプログラミング

2.1アナログクライアント

クライアントのために書かれたデータは、サーバの応答を取得します

package cn.bjc.bs;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class TestClient {
	/*
	 * 1. 建立一个Socket对象,连接网址与端口号
	 * 2. 获取输出流对象
	 * 3. 获取输入流对象
	 * 4. 将HTTP协议的请求部分发送到服务端
	 * 5. 读取来自服务端的数据打印到控制台
	 * 6. 释放资源
	 * */
	public static void main(String[] args) throws Exception {
		// 1. 建立一个Socket对象,连接网址与端口号
		Socket socket = new Socket("yun.itheima.com",80);
		// 2. 获取输出流对象
		InputStream in = socket.getInputStream();
		// 3. 获取输入流对象
		OutputStream out = socket.getOutputStream();
		// 4. 将HTTP协议的请求部分发送到服务端  
		// 4.1 请求资源  /open/c-4/p/1.html
		out.write("GET /open/c-4/p/1.html HTTP 1.1\n".getBytes());
		// 4.2 请求头
		out.write("HOST:yun.itheima.com\n".getBytes());
		// 4.3 空行
		out.write("\n".getBytes());
		
		// 5. 读取来自服务端的数据打印到控制台
		int i = in.read();
		while(i != -1){
			System.out.print((char)i);
			i = in.read();
		}
		
		// 6. 释放资源
		in.close();
		in = null;
		out.close();
		out=null;
	}
}

2.2アナログサービス終了

コードの一部、アナログブラウザに応答してサーバーに要求を書き込みます

package cn.bjc.bs;

import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TestServer {

	public static void main(String[] args) throws Exception{
		ServerSocket serverSocket = null;
		Socket socket = null;
		OutputStream out = null;
		try {
			// 1. 创建ServerSocket对象,监听本机的8080端口
			serverSocket = new ServerSocket(8080);
			while(true){
				// 2. 等待来自客户端的请求获取和客户端对应的Socket对象
				socket = serverSocket.accept();
				// 3. 通过获取到的Socket对象获取到输出流
				out = socket.getOutputStream();
				// 4. 通过获取到的输出流对象将HTTP协议响应部分发送到客户端
				// 4.1 响应头
				out.write("HTTP/1.1 200 OK\n".getBytes());
				out.write("Content-Type:text/html;charset=utf-8\n".getBytes());
				out.write("Server:Apache-Coyote/1.1\n".getBytes());
				out.write("\n\n".getBytes());
				// 4. 响应体
				StringBuffer buffer = new StringBuffer();
				buffer.append("<html>");
				buffer.append("  <head><title>标题</title></head>");
				buffer.append("  <body>");
				buffer.append("       <h1>xxx</h1>");
				buffer.append("       <a href='http://www.baidu.com'>百度</a>");
				buffer.append("  </body>");
				buffer.append("</html>");
				out.write(buffer.toString().getBytes());
				out.flush();
			}
		} finally{
			// 5. 释放资源
			out.close();
			out = null;
			socket.close();
			socket = null;
		}
	}
}

ブラウザで入力してください:HTTP:// localhostを:8080 /

図サーバーの応答:

3.手動では、Tomcatを達成します

3.1静的リソース

ケース:

WebContentをdemo1.html、demo2.htmlで静的リソースを公開1

2. Tomcatを起動

3.サーバーへのクライアントが別の要求、localhostを開始する:8080 / demo.htmlを

4.サーバーは、クライアントに応じて対応するHTMLページであることができます。

3.1.1プロジェクトの作成

Javaプロジェクトを作成し、よう:

3.1.2サーバー側の準備を実装

1.静的変数にWEB.ROOTのWebContentディレクトリを格納するための絶対パスを定義します。

2.定義静的変数のURL、店の静的リソースは、名前のこのサービスの終了を要求します

例えば:

// 定义静态变量,用于存放服务端weContent目录的绝对路径
public static String WEB_ROOT = System.getProperty("user.dir")+File.separator+"webContent";
// 定义静态变量,用于存放本次请求的静态页面的名称
private static String url;

3.1.3サーバの起動コードを実装

、ポート8080上のマシンのリッスンをServerSocketオブジェクトを作成します。1.

2.クライアントからの要求を待っています

public static void main(String[] args) throws Exception {
    ServerSocket server = null;
	Socket socket = null;
	// 1. 创建ServerSocket,监听本地8080端口,等待来自客户端的请求
	try {
		server = new ServerSocket(8080);
		while(true){
			// 获取客户端对应的socket
			socket = server.accept();
		}
	} catch (IOException e) {
		e.printStackTrace();
}

コードの要求された部分を達成するために、3.1.4 HTTPサーバ

データ読み出し要求HTTPプロトコルの1部分

2.解析要求ライン、この要求の静的リソース名を取得します

public static void main(String[] args) throws Exception {
	ServerSocket server = null;
	Socket socket = null;
	OutputStream out = null;
	InputStream in = null;
	// 1. 创建ServerSocket,监听本地8080端口,等待来自客户端的请求
	try {
		server = new ServerSocket(8080);
		while(true){
			// 获取客户端对应的socket
			socket = server.accept();
			// 获取输入流对象
			in = socket.getInputStream();
			// 获取输出流对象
			out = socket.getOutputStream();
			// 获取HTTP协议的请求部分,截取客户端要访问的资源名称,将这个资源名称赋值给url
			parse(in);
			// 发送静态资源
			sendStaticResource(out);
		}
	} catch (IOException e) {
		e.printStackTrace();
	} finally {
		
	}
}

3.1.5 HTTPプロトコルサーバーを実装すると、クライアントの一部に応答を送信

入力ストリームメモリを介してサーバへ1.読み取り静的リソース

クライアント部分に2伝送プロトコルHTTPレスポンス

private static void sendStaticResource(OutputStream out) throws Exception {
		// 1. 定义一个字节数组,用于存放本次请求的静态资源demo01.html的内容
		byte[] bytes = new byte[2048];
		// 2. 定义一个文件输入流,用户获取静态资源demo01.html中的内容
		FileInputStream fis = null;
		try {
			// 3. 创建文件对象File,代表本次要请求的资源demo01.html
			File file = new File(WEB_ROOT,url);
			// 4. 如果文件存在
			if(file.exists()){
				// 4.1 向客户端输出HTTP协议的响应行/响应头
				out.write("HTTP/1.1 200 OK\n".getBytes());
				out.write("Server:apache-Coyote/1.1\n".getBytes());
				out.write("Content-Type:text/html;charset=utf-8\n".getBytes());
				out.write("\n".getBytes());
				// 4.2 获取到文件输入流对象
				fis = new FileInputStream(file);
				// 4.3 读取静态资源demo01.html中的内容到数组中
				int ch = fis.read(bytes);
				while(ch != -1){
					// 4.4 将读取到数组中的内容通过输出流发送到客户端
					out.write(bytes, 0, ch);
					ch = fis.read(bytes);
				}
			}else {
				// 5. 如果文件不存在
				// 5.1 向客户端响应文件不存在的消息
				out.write("HTTP/1.1 404 not found\n".getBytes());
				out.write("Server:apache-Coyote/1.1\n".getBytes());
				out.write("Content-Type:text/html;charset=utf-8\n".getBytes());
				out.write("\n".getBytes());
				String errMsg = "file not found";
				out.write(errMsg.getBytes());
			}
		} catch(Exception e){
			e.printStackTrace();
		}finally {
			// 6. 释放资源
			if(null != fis){
				fis.close();
			}
		}
		
	}

完全なコード:

package cn.bjc.mytomcat.v1;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TestServer {

	// 定义静态变量,用于存放服务端weContent目录的绝对路径
	public static String WEB_ROOT = System.getProperty("user.dir")+File.separator+"webContent";
	// 定义静态变量,用于存放本次请求的静态页面的名称
	private static String url;
	public static void main(String[] args) throws Exception {
		ServerSocket server = null;
		Socket socket = null;
		OutputStream out = null;
		InputStream in = null;
		// 1. 创建ServerSocket,监听本地8080端口,等待来自客户端的请求
		try {
			server = new ServerSocket(8080);
			while(true){
				// 获取客户端对应的socket
				socket = server.accept();
				// 获取输入流对象
				in = socket.getInputStream();
				// 获取输出流对象
				out = socket.getOutputStream();
				// 获取HTTP协议的请求部分,截取客户端要访问的资源名称,将这个资源名称赋值给url
				parse(in);
				// 发送静态资源
				sendStaticResource(out);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			
		}
	}
	
	private static void sendStaticResource(OutputStream out) throws Exception {
		// 1. 定义一个字节数组,用于存放本次请求的静态资源demo01.html的内容
		byte[] bytes = new byte[2048];
		// 2. 定义一个文件输入流,用户获取静态资源demo01.html中的内容
		FileInputStream fis = null;
		try {
			// 3. 创建文件对象File,代表本次要请求的资源demo01.html
			File file = new File(WEB_ROOT,url);
			// 4. 如果文件存在
			if(file.exists()){
				// 4.1 向客户端输出HTTP协议的响应行/响应头
				out.write("HTTP/1.1 200 OK\n".getBytes());
				out.write("Server:apache-Coyote/1.1\n".getBytes());
				out.write("Content-Type:text/html;charset=utf-8\n".getBytes());
				out.write("\n".getBytes());
				// 4.2 获取到文件输入流对象
				fis = new FileInputStream(file);
				// 4.3 读取静态资源demo01.html中的内容到数组中
				int ch = fis.read(bytes);
				while(ch != -1){
					// 4.4 将读取到数组中的内容通过输出流发送到客户端
					out.write(bytes, 0, ch);
					ch = fis.read(bytes);
				}
			}else {
				// 5. 如果文件不存在
				// 5.1 向客户端响应文件不存在的消息
				out.write("HTTP/1.1 404 not found\n".getBytes());
				out.write("Server:apache-Coyote/1.1\n".getBytes());
				out.write("Content-Type:text/html;charset=utf-8\n".getBytes());
				out.write("\n".getBytes());
				String errMsg = "file not found";
				out.write(errMsg.getBytes());
			}
		} catch(Exception e){
			e.printStackTrace();
		}finally {
			// 6. 释放资源
			if(null != fis){
				fis.close();
			}
		}
		
	}
	private static void parse(InputStream in) throws Exception {
		// 1. 定义一个变量,存放HTTP协议请求部分数据
		StringBuffer content = new StringBuffer();
		// 2. 定义一个数组,存放HTTP协议请求部分数据
		byte[] buffer = new byte[2048];
		// 3. 定义一个变量i,代表读取数据到数组中之后,数据量的大小
		int i = -1;
		// 4. 读取客户端发过来的数据,将数据读取到字节数组buffer中,i代表读取数据量的大小311字节
		i = in.read(buffer);
		// 5. 遍历字节数组,将数组中的数据追加到content变量中
		for(int j = 0 ; j < i ; j++){
			content.append((char)buffer[j]);
		}
		// 6. 打印HTTP协议请求部分数据
		System.out.println(content);
		// 7. 截取客户端要请求的资源路径 demo.html,赋值给url
		parseUrl(content.toString());
		System.out.println(url);
	}

	// 解析请求数据得到请求连接
	private static void parseUrl(String content) {
		/*
		 * 	GET /erp/dep/getAll HTTP/1.1
			Host: localhost:8080
			Connection: keep-alive
			Upgrade-Insecure-Requests: 1
			User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
			Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng;q=0.8
			Accept-Encoding: gzip, deflate, br
			Accept-Language: zh-CN,zh;q=0.9
			Cookie: __guid=111872281.1743065663273879000.1567260921404.8972
		 * 
		 * */
		// 1. 截取客户端请求资源的名称   /erp/dep/getAll
		// 2. 定义2个变量,存放请求行的2个空格位置
		int index1,index2;
		// 3. 获取http请求行的第一个空格的位置
		index1 = content.indexOf(" ");
		if(index1 != -1){ // 表示存在第一个空格
			// 从第一个空格之后开始查找
			// 4. 获取http请求行的第二个空格的位置
			index2 = content.indexOf(" ", index1+1);
			if(index2 > index1){
				// 5. 截取字符串获取到本次请求的资源的名称
				url = content.substring(index1+2, index2);
			}
		}
	}

}

業績:

ブラウザで入力してください:HTTP:// localhostを:8080 / demo1.html

ブラウザで入力してください:HTTP:// localhostを:8080 / demo11.html

公開された128元の記事 ウォンの賞賛6 ビュー3234

おすすめ

転載: blog.csdn.net/weixin_43318134/article/details/103658349
おすすめ