📄 简单的用 java socket 编写的 http 服务器应用,帮助学习http协议.htm
字号:
src="简单的用%20Java%20Socket%20编写的%20HTTP%20服务器应用,帮助学习HTTP协议_files/zhuan.gif"
width=15 border=0> 简单的用 Java Socket 编写的 HTTP 服务器应用,帮助学习HTTP协议 </A></DIV>
<DIV class=postText><SPAN style="COLOR: #008000">/**</SPAN><SPAN
style="COLOR: #008000"><BR> * SimpleHttpServer.java<BR> </SPAN><SPAN
style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN
style="COLOR: #0000ff"></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN
style="COLOR: #0000ff">import</SPAN><SPAN
style="COLOR: #000000"> java.io.</SPAN><SPAN
style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">;<BR></SPAN><SPAN
style="COLOR: #0000ff">import</SPAN><SPAN
style="COLOR: #000000"> java.net.</SPAN><SPAN
style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">;<BR></SPAN><SPAN
style="COLOR: #0000ff">import</SPAN><SPAN
style="COLOR: #000000"> java.util.StringTokenizer;<BR><BR></SPAN><SPAN
style="COLOR: #008000">/**</SPAN><SPAN
style="COLOR: #008000"><BR> * 一个简单的用 Java Socket 编写的 HTTP 服务器应用, 演示了请求和应答的协议通信内容以及<BR> * 给客户端返回 HTML 文本和二进制数据文件(一个图片), 同时展示了 404, 200 等状态码.<BR> * 首先运行这个程序,然后打开Web浏览器,键入http://localhost,则这个程序能够显示出浏览器发送了那些信息<BR> * 并且向浏览器返回一个网页和一副图片, 并测试同浏览器对话.<BR> * 当浏览器看到 HTML 中带有图片地址时, 则会发出第二次连接来请求图片等资源.<BR> * 这个例子可以帮您理解 Java 的 HTTP 服务器软件是基于 J2SE 的 Socket 等软件编写的概念, 并熟悉<BR> * HTTP 协议.<BR> * 相反的用 Telnet 连接到已有的服务器则可以帮忙理解浏览器的运行过程和服务器端的返回内容.<BR> *<BR> * <pre><BR> * 当用户在Web浏览器地址栏中输入一个带有http://前缀的URL并按下Enter后,或者在Web页面中某个以http://开头的超链接上单击鼠标,HTTP事务处理的第一个阶段--建立连接阶段就开始了.HTTP的默认端口是80.<BR> * 随着连接的建立,HTTP就进入了客户向服务器发送请求的阶段.客户向服务器发送的请求是一个有特定格式的ASCII消息,其语法规则为:<BR> * < Method > < URL > < HTTP Version > <\n><BR> * { <Header>:<Value> <\n>}*<BR> * <\n><BR> * { Entity Body }<BR> * 请求消息的顶端是请求行,用于指定方法,URL和HTTP协议的版本,请求行的最后是回车换行.方法有GET,POST,HEAD,PUT,DELETE等.<BR> * 在请求行之后是若干个报头(Header)行.每个报头行都是由一个报头和一个取值构成的二元对,报头和取值之间以":"分隔;报头行的最后是回车换行.常见的报头有Accept(指定MIME媒体类型),Accept_Charset(响应消息的编码方式),Accept_Encoding(响应消息的字符集),User_Agent(用户的浏览器信息)等.<BR> * 在请求消息的报头行之后是一个回车换行,表明请求消息的报头部分结束.在这个\n之后是请求消息的消息实体(Entity Body).具体的例子参看httpRequest.txt.<BR> * Web服务器在收到客户请求并作出处理之后,要向客户发送应答消息.与请求消息一样,应答消息的语法规则为:<BR> * < HTTP Version> <Status Code> [<Message>]<\n><BR> * { <Header>:<Value> <\n> } *<BR> * <\n><BR> * { Entity Body }<BR> * 应答消息的第一行为状态行,其中包括了HTTP版本号,状态码和对状态码进行简短解释的消息;状态行的最后是回车换行.状态码由3位数字组成,有5类: <BR> * 参看:HTTP应答码及其意义 <BR> * <BR> * 1XX 保留 <BR> * 2XX 表示成功 <BR> * 3XX 表示URL已经被移走 <BR> * 4XX 表示客户错误 <BR> * 5XX 表示服务器错误 <BR> * 例如:415,表示不支持改媒体类型;503,表示服务器不能访问.最常见的是200,表示成功.常见的报头有:Last_Modified(最后修改时间),Content_Type(消息内容的MIME类型),Content_Length(内容长度)等.<BR> * 在报头行之后也是一个回车换行,用以表示应答消息的报头部分的结束,以及应答消息实体的开始.<BR> * 下面是一个应答消息的例子:<BR> * HTTP/1.0 200 OK<BR> * Date: Moday,07-Apr-97 21:13:02 GMT<BR> * Server:NCSA/1.1<BR> * MIME_Version:1.0<BR> * Content_Type:text/html<BR> * Last_Modified:Thu Dec 5 09:28:01 1996<BR> * Coentent_Length:3107<BR> * <BR> * <HTML><HEAD><TITLE><IMG
alt=""
src="简单的用%20Java%20Socket%20编写的%20HTTP%20服务器应用,帮助学习HTTP协议_files/dot.gif"></HTML><BR> * <BR> * 在用Java语言实现HTTP服务器时,首先启动一个java.net.ServerSocket在提供服务的端口上监听连接.向客户返回文本时,可以用PrintWriter,但是如果返回二进制数据,则必须使用OutputStream.write(byte[])方法,返回的应答消息字符串可以使用String.getBytes()方法转换为字节数组返回,或者使用PrintStream的print()方法写入文本,用write(byte[])方法写入二进制数据.<BR> * <BR> * </pre><BR> * </SPAN><SPAN
style="COLOR: #808080">@author</SPAN><SPAN
style="COLOR: #008000"> 刘长炯<BR> * </SPAN><SPAN
style="COLOR: #808080">@version</SPAN><SPAN
style="COLOR: #008000"> 1.0 2007-07-24 Sunday<BR> </SPAN><SPAN
style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN
style="COLOR: #0000ff">public</SPAN><SPAN
style="COLOR: #000000"> </SPAN><SPAN
style="COLOR: #0000ff">class</SPAN><SPAN
style="COLOR: #000000"> SimpleHttpServer </SPAN><SPAN
style="COLOR: #0000ff">implements</SPAN><SPAN
style="COLOR: #000000"> Runnable {<BR> </SPAN><SPAN
style="COLOR: #008000">/**</SPAN><SPAN
style="COLOR: #008000"><BR> * <BR> </SPAN><SPAN
style="COLOR: #008000">*/</SPAN><SPAN
style="COLOR: #000000"><BR> ServerSocket serverSocket;</SPAN><SPAN
style="COLOR: #008000">//</SPAN><SPAN
style="COLOR: #008000">服务器Socket</SPAN><SPAN
style="COLOR: #008000"><BR></SPAN><SPAN
style="COLOR: #000000"> <BR> </SPAN><SPAN
style="COLOR: #008000">/**</SPAN><SPAN
style="COLOR: #008000"><BR> * 服务器监听端口, 默认为 80.<BR> </SPAN><SPAN
style="COLOR: #008000">*/</SPAN><SPAN
style="COLOR: #000000"><BR> </SPAN><SPAN
style="COLOR: #0000ff">public</SPAN><SPAN
style="COLOR: #000000"> </SPAN><SPAN
style="COLOR: #0000ff">static</SPAN><SPAN
style="COLOR: #000000"> </SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN
style="COLOR: #000000"> PORT</SPAN><SPAN
style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">80</SPAN><SPAN
style="COLOR: #000000">;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN
style="COLOR: #008000">标准HTTP端口</SPAN><SPAN
style="COLOR: #008000"><BR></SPAN><SPAN
style="COLOR: #000000"> <BR> </SPAN><SPAN
style="COLOR: #008000">/**</SPAN><SPAN
style="COLOR: #008000"><BR> * 开始服务器 Socket 线程.<BR> </SPAN><SPAN
style="COLOR: #008000">*/</SPAN><SPAN
style="COLOR: #000000"><BR> </SPAN><SPAN
style="COLOR: #0000ff">public</SPAN><SPAN
style="COLOR: #000000"> SimpleHttpServer() {<BR> </SPAN><SPAN
style="COLOR: #0000ff">try</SPAN><SPAN
style="COLOR: #000000"> {<BR> serverSocket</SPAN><SPAN
style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN
style="COLOR: #000000"> ServerSocket(PORT);<BR> } </SPAN><SPAN
style="COLOR: #0000ff">catch</SPAN><SPAN
style="COLOR: #000000">(Exception e) {<BR> System.out.println(</SPAN><SPAN
style="COLOR: #000000">"</SPAN><SPAN
style="COLOR: #000000">无法启动HTTP服务器:</SPAN><SPAN
style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN
style="COLOR: #000000">e.getLocalizedMessage());<BR> }<BR> </SPAN><SPAN
style="COLOR: #0000ff">if</SPAN><SPAN
style="COLOR: #000000">(serverSocket</SPAN><SPAN
style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN
style="COLOR: #000000">) System.exit(</SPAN><SPAN
style="COLOR: #000000">1</SPAN><SPAN style="COLOR: #000000">);</SPAN><SPAN
style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">无法开始服务器</SPAN><SPAN
style="COLOR: #008000"><BR></SPAN><SPAN
style="COLOR: #000000"> </SPAN><SPAN
style="COLOR: #0000ff">new</SPAN><SPAN
style="COLOR: #000000"> Thread(</SPAN><SPAN
style="COLOR: #0000ff">this</SPAN><SPAN
style="COLOR: #000000">).start();<BR> System.out.println(</SPAN><SPAN
style="COLOR: #000000">"</SPAN><SPAN
style="COLOR: #000000">HTTP服务器正在运行,端口:</SPAN><SPAN
style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN
style="COLOR: #000000">PORT);<BR> }<BR> <BR> </SPAN><SPAN
style="COLOR: #008000">/**</SPAN><SPAN
style="COLOR: #008000"><BR> * 运行服务器主线程, 监听客户端请求并返回响应.<BR> </SPAN><SPAN
style="COLOR: #008000">*/</SPAN><SPAN
style="COLOR: #000000"><BR> </SPAN><SPAN
style="COLOR: #0000ff">public</SPAN><SPAN
style="COLOR: #000000"> </SPAN><SPAN
style="COLOR: #0000ff">void</SPAN><SPAN
style="COLOR: #000000"> run() {<BR> </SPAN><SPAN
style="COLOR: #0000ff">while</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN
style="COLOR: #0000ff">true</SPAN><SPAN
style="COLOR: #000000">) {<BR> </SPAN><SPAN
style="COLOR: #0000ff">try</SPAN><SPAN
style="COLOR: #000000"> {<BR> Socket client</SPAN><SPAN
style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN
style="COLOR: #000000">;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN
style="COLOR: #008000">客户Socket</SPAN><SPAN
style="COLOR: #008000"><BR></SPAN><SPAN
style="COLOR: #000000"> client</SPAN><SPAN
style="COLOR: #000000">=</SPAN><SPAN
style="COLOR: #000000">serverSocket.accept();</SPAN><SPAN
style="COLOR: #008000">//</SPAN><SPAN
style="COLOR: #008000">客户机(这里是 IE 等浏览器)已经连接到当前服务器</SPAN><SPAN
style="COLOR: #008000"><BR></SPAN><SPAN
style="COLOR: #000000"> </SPAN><SPAN
style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(client</SPAN><SPAN
style="COLOR: #000000">!=</SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN
style="COLOR: #000000">) {<BR> System.out.println(</SPAN><SPAN
style="COLOR: #000000">"</SPAN><SPAN
style="COLOR: #000000">连接到服务器的用户:</SPAN><SPAN
style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN
style="COLOR: #000000">client);<BR> </SPAN><SPAN
style="COLOR: #0000ff">try</SPAN><SPAN
style="COLOR: #000000"> {<BR> </SPAN><SPAN
style="COLOR: #008000">//</SPAN><SPAN
style="COLOR: #008000"> 第一阶段: 打开输入流</SPAN><SPAN
style="COLOR: #008000"><BR></SPAN><SPAN
style="COLOR: #000000"> BufferedReader in</SPAN><SPAN
style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN
style="COLOR: #000000"> BufferedReader(</SPAN><SPAN
style="COLOR: #0000ff">new</SPAN><SPAN
style="COLOR: #000000"> InputStreamReader(<BR> client.getInputStream()));<BR> <BR> System.out.println(</SPAN><SPAN
style="COLOR: #000000">"</SPAN><SPAN
style="COLOR: #000000">客户端发送的请求信息:\n***************</SPAN><SPAN
style="COLOR: #000000">"</SPAN><SPAN
style="COLOR: #000000">);<BR> </SPAN><SPAN
style="COLOR: #008000">//</SPAN><SPAN
style="COLOR: #008000"> 读取第一行, 请求地址</SPAN><SPAN
style="COLOR: #008000"><BR></SPAN><SPAN
style="COLOR: #000000"> String line</SPAN><SPAN
style="COLOR: #000000">=</SPAN><SPAN
style="COLOR: #000000">in.readLine();<BR> System.out.println(line);<BR> String resource</SPAN><SPAN
style="COLOR: #000000">=</SPAN><SPAN
style="COLOR: #000000">line.substring(line.indexOf(</SPAN><SPAN
style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">/</SPAN><SPAN
style="COLOR: #000000">'</SPAN><SPAN
style="COLOR: #000000">),line.lastIndexOf(</SPAN><SPAN
style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">/</SPAN><SPAN
style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN
style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">5</SPAN><SPAN
style="COLOR: #000000">);<BR> </SPAN><SPAN
style="COLOR: #008000">//</SPAN><SPAN
style="COLOR: #008000">获得请求的资源的地址</SPAN><SPAN
style="COLOR: #008000"><BR></SPAN><SPAN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -