自己动手,写个Web服务器(Java版)——第一篇、浏览器和Web服务器的语言Http
来源:互联网 发布:网站如何seo 编辑:程序博客网 时间:2024/05/22 17:49
浏览器如何根Web服务器交谈呢?请看下图
浏览器和Web服务器通过一个叫TCP的管子通话。浏览器先说:我要……。Web服务器回答:给你……。如此往复。Web服务器不会主动回答的,只有浏览器发出请求,Web服务器才会回答。
浏览器和Web服务器都是机器,不懂人的语言。它们有自己的语言——http。其中请求和响应的语法都差不多。都是由头、(空行)、体组合而成。头是由一行一行的格式如:name: value(回车换行)的行组成的。
下面就来写两个简单的程序看看浏览器和Web服务器到底说了些什么吧:)
1 浏览器的请求
Server是用Java写第一版的Web服务器。它打开一个80端口的ServerSocket等待浏览器连入。当浏览器接入后,把浏览器发送的请求打印出来。
package mywebserver1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.StringTokenizer;
/**
* @author allen
* @version 0.1
*/
public class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(80);
Socket s = ss.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(s
.getInputStream()));
String requestLine = "";
char[] body;
boolean haveBody = false;
int length = 0;
do {
requestLine = br.readLine();
System.out.println(requestLine);
// post方式提交的请求还要取得,请求体的内容
if (requestLine.startsWith("Content-Length")) {
StringTokenizer st = new StringTokenizer(requestLine, ":");
st.nextToken();
String bodyLength = st.nextToken().trim();
length = Integer.parseInt(bodyLength);
haveBody = true;
}
if (requestLine.equals("") && haveBody) {
body = new char[length];
br.read(body, 0, length);
System.out.println(new String(body));
}
} while (!requestLine.equals(""));
br.close();
s.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
//资源清理代码
}
}
}
以下是控制台打印出的浏览器请求的内容
1. Get方式
GET / HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-silverlight, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
If-Modified-Since: Tue, 02 Sep 2008 06:15:50 GMT
If-None-Match: W/"648-1220336150812"
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; aff-kingsoft-ciba)
Host: 127.0.0.1
Connection: Keep-Alive
Cookie: __utma=96992031.200084460.1247665275.1247665275.1247665275.1; __utmz=96992031.1247665275.1.1.utmccn=(direct)|utmcsr=(direct)|utmcmd=(none)
2. Post方式
POST / HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-silverlight, */*
Accept-Language: zh-cn
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; aff-kingsoft-ciba)
Host: 127.0.0.1
Content-Length: 19
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: __utma=96992031.200084460.1247665275.1247665275.1247665275.1; __utmz=96992031.1247665275.1.1.utmccn=(direct)|utmcsr=(direct)|utmcmd=(none)
user=Mike&pass=1234
这个是测试用的index.html页面
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
</HEAD>
<BODY>
<a href="http://127.0.0.1/">Get方式提交的请求!</a>
<form name="FormRequest" action="http://127.0.0.1/" method="post">
<input name="user" type="text" value="Mike" />
<input name="pass" type="password" value="1234" />
<input type="submit" value="Test"/>
</form>
</BODY>
</HTML>
2 Web服务器的回应
Client.java是测试用的客户端。它手工构造了一个请求(访问的是www.baidu.com),然后把服务器的响应打出来。
/**
*
*/
package mywebserver1;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.StringTokenizer;
/**
* @author allen
* @version 0.1
*/
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
String host = "www.baidu.com";
String resource = "/";
int port = 80;
//手工构造请求
StringBuilder request = new StringBuilder();
request.append("GET " + resource + " HTTP/1.1/n");
request.append("/n");
System.out.println("请求是:/n" + request.toString());
try {
InetAddress[] ipaddr = InetAddress.getAllByName(host);
Socket s = new Socket(ipaddr[0], port);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s
.getOutputStream()));
bw.write(request.toString());
bw.flush();
// 发送完请求,开始接收响应
BufferedReader br = new BufferedReader(new InputStreamReader(s
.getInputStream()));
String requestLine = "";
char[] body;
boolean haveBody = false;
int length = 0;
boolean ifchunked = false;
do {
requestLine = br.readLine();
System.out.println(requestLine);
// 响应体的取得,与请求体的取得类似。
if (requestLine.startsWith("Content-Length")) {
StringTokenizer st = new StringTokenizer(requestLine, ":");
st.nextToken();
String bodyLength = st.nextToken().trim();
length = Integer.parseInt(bodyLength);
haveBody = true;
}
if (requestLine.startsWith("Transfer-Encoding")) {
StringTokenizer st = new StringTokenizer(requestLine, ":");
st.nextToken();
String transferEncoding = st.nextToken().trim();
if ("chunked".equalsIgnoreCase(transferEncoding)) {
ifchunked = true;
}
}
//读取响应Body
if (requestLine.equals("") && haveBody) {
body = new char[length];
br.read(body, 0, length);
String responseBody = new String(body);
System.out.println(responseBody.length());
System.out.println(responseBody);
}
//响应的Transfer-Encoding是chunked,需要特殊的处理
if (requestLine.equals("") && ifchunked) {
char[] chunkedbody = new char[1024];
int readin = 0;
do {
readin = br.read(chunkedbody);
System.out.println(new String(chunkedbody, 0, readin));
} while (readin > 0);
}
} while (!requestLine.equals(""));
bw.close();
br.close();
s.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
以下是百度返回的响应
HTTP/1.1 200 OK
Date: Sun, 26 Jul 2009 13:34:30 GMT
Server: BWS/1.0
Content-Length: 3509
Content-Type: text/html
Cache-Control: private
Expires: Sun, 26 Jul 2009 13:34:30 GMT
Set-Cookie: BAIDUID=1FAAFC4F63BD53DED54944E06B8FACEA:FG=1; expires=Sun, 26-Jul-39 13:34:30 GMT; path=/; domain=.baidu.com
P3P: CP=" OTI DSP COR IVA OUR IND COM "
3509
<html><head><meta http-equiv=Content-Type content="text/html;charset=gb2312"><title>百度一下,你就知道</title>省略了</html><!--c8e53c7e25ef8339-->_
- 自己动手,写个Web服务器(Java版)——第一篇、浏览器和Web服务器的语言Http
- 自己动手,写个Web服务器(Java版)——第二篇、Web服务器0.2
- 自己动手,写个Web服务器(Java版)——第三篇
- 自己动手,写个Web服务器(Java版)——第四篇 WebShare
- 自己动手写web服务器一(浏览器的访问信息)
- 自己动手写web服务器三(web服务器是如何处理浏览器取消的请求的)
- 自己动手写的Web服务器<一>
- 自己动手写http服务器---java版
- 自己动手写http服务器---java版
- 自己动手写http服务器---java版
- 自己写浏览器和web服务器的分析!
- 学习笔记之自己动手写WEB服务器
- 自己动手写web服务器(上),深入底层了解ASP.NET浏览器与服务器通信原理
- 自己动手写web服务器(下),深入底层了解ASP.NET浏览器与服务器通信原理
- 自己动手写web服务器四(web服务器是如何通过压缩数据,web服务器的gzip模块的实现)
- 《Go语言入门》第一个Go语言Web程序——简单的Web服务器
- 《Go语言入门》第一个Go语言Web程序——简单的Web服务器
- Java基于TCP的简易Web浏览器和服务器
- mootools异步提交
- 类对象的复制和拷贝问题
- 3G培训
- 检索 COM 类工厂中 CLSID 为{00024500-0000-0000-C000-000000000046} 的组件时失败,原因是出现以下错误: 80070005。
- 摩根定理
- 自己动手,写个Web服务器(Java版)——第一篇、浏览器和Web服务器的语言Http
- DataSet 添加数据集、行、列、主键和外键等操作示例
- Makefile
- 在RHEL5 上安装流媒体软件Helix Server for linux
- 用while实现sql语句中循环为某字段赋值
- 第一步 即日启程
- C# TextBox中只允许输入数字的解决方法
- BGP的local-preference试验
- C#操作 PDF文件