科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道Java2 参考大全:第18章 网络 (6)

Java2 参考大全:第18章 网络 (6)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

Java2 参考大全:第18章 网络 (6)

作者:Herbert Schildt 著 张玉清 吴溥峰等 译 来源:清华大学出版社 2007年10月30日

关键字: 网络 java

  • 评论
  • 分享微博
  • 分享邮件

18.8.1 源代码
HTTP服务器是通过5个类和一个接口实现的。更完善的实现方案可能在主类httpd外分裂很多的方法,以使组成结构更抽象。考虑本书的容量,多数功能是在单个类中实现的,小的支持类仅作为数据结构。我们仔细学习每一个类和方法来了解该服务器怎样工作,由支持类开始,终止于主程序。
MimeHeader.java
MIME是通过电子邮件系统传达多媒体内容的一个Internet标准。该标准是由NatBorenstein在1992年创建的。HTTP协议运用并扩展了MIME标头的概念,在HTTP客户和服务器之间传输常规的属性/值对。
构造函数 该类是Hashtable 的一个子类,所以它能方便的存储和检索与MIME标头有关的关键字/值对。它有两个构造函数。一个创建一个不含关键字的空的MimeHeader。另一个以一个格式化的字符串作为MIME标头,然后把它解析为对象的初始内容。参看下面的parse( )。parse( ) parse( )方法用来获取一个原始MIME格式的字符串,并使它的关键字/值对进入一个给定的MimeHeader实例。它用StringTokenizer 把输入数据分解成独立的由CRLF(\r\n)序列标记的行。然后用规范的while... hasMoreTokens( ) ... nextToken( ) 序列遍历每一行。对于MIME标头的每一行,parse( )通过冒号(:)把该行分解成两个字符串。两个变量key和val由substring( )方法设置,用来提取冒号前后的字符及后面的空隔。当两个字符串被提取后,使用put( )方法存储Hashtable中的关键字和值之间的关联。toString( ) toString( )方法(用于String 串联操作,+)只是parse( )的反方法。它获取当前存储在MimeHeader 中的关键字/值对,返回一个MIME格式的字符串描述,然后打印关键字,跟着是冒号和空隔,然后是值,最后是CRLF。put( ), get( ), AND fix( ) 如果不是特殊的任务,Hashtable中的put( )和get( )方法将运行良好。MIME规范定义了几个重要的关键字例如Content-Type和Content-Length。一些早期的MIME 系统设备,特别是网络浏览器,对这些成员的大小写是自由的。一些用Content-type,另一些用content-type。为避免灾祸,我们的HTTP服务器努力将所有的输入和输出的MimeHeader关键字转换成规范形式Content-Type。因此,我们在它们进入Hashtable和寻找给定关键字之前用fix()方法重载put( )和get( ),转变值的大小写。
代码 下面是MimeHeader的源代码:
import java.util.*;
class MimeHeader extends Hashtable {
void parse(String data) {
StringTokenizer st = new StringTokenizer(data, "\r\n");
while (st.hasMoreTokens()) {
String s = st.nextToken();
int colon = s.indexOf(':');
String key = s.substring(0, colon);
String val = s.substring(colon + 2); // skip ": "
put(key, val);
}
}
MimeHeader() {}
MimeHeader(String d) {
parse(d);
}
public String toString() {
String ret = "";
Enumeration e = keys();
while(e.hasMoreElements()) {
String key = (String) e.nextElement();
String val = (String) get(key);
ret += key + ": " + val + "\r\n";
}
return ret;
}
// This simple function converts a mime string from
// any variant of capitalization to a canonical form.
// For example: CONTENT-TYPE or content-type to Content-Type,
// or Content-length or CoNTeNT-LENgth to Content-Length.
private String fix(String ms) {
char chars[] = ms.toLowerCase().toCharArray();
boolean upcaseNext = true;
for (int i = 0; i < chars.length - 1; i++) {
char ch = chars[i];
if (upcaseNext && 'a' <= ch && ch <= 'z') {
chars[i] = (char) (ch - ('a' - 'A'));
}
upcaseNext = ch == '-';
}
return new String(chars);
}
public String get(String key) {
return (String) super.get(fix(key));
}
public void put(String key, String val) {
super.put(fix(key), val);
}
}
HttpResponse.java
HttpResponse类是所有与HTTP服务器应答有关的事物的包装程序。它被httpd类的代理部分使用。当你向一个HTTP服务器发送一个请求时,它以一个存储在statusCode中的整数形式的代码以及一个存储在reasonPhrase中的文本应答(这些变量名在正式的HTTP规范中规定)。这个单行的响应后面跟随着一个包含进一步应答信息的MIME头。我们用以前解释过的MimeHeader对象来解析这个字符串。MimeHeader对象存储在HttpResponse类的mh变量中。这些变量不是私有的,所以httpd可以直接使用它们。构造函数 如果用一个字符串参数创建一个HttpResponse类对象,它被用来作为一个HTTP服务器的原始响应,并传向下面描述的parse( )来初始化对象。你还可以传入一个预计算的状态码,原因语句以及MIME标头。parse( ) parse( )方法获得从HTTP服务器上读取的原始数据,从第一行解析出statusCode 和reasonPhrase ,然后在剩下的行外部创建一个MimeHeader 。toString( ) toString( )方法是parse( )的逆方法。它获取HttpResponse对象的当前值并返回一个字符串,HTTP客户希望从服务器读回该字符串。
代码 下面是HttpResponse 的源代码:
import java.io.*;
/*
* HttpResponse
* Parse a return message and MIME header from a server.
* HTTP/1.0 302 Found = redirection, check Location for where.
* HTTP/1.0 200 OK = file data comes after mime header.
*/
class HttpResponse
{
int statusCode; // Status-Code in spec
String reasonPhrase; // Reason-Phrase in spec
MimeHeader mh;
static String CRLF = "\r\n";
void parse(String request) {
int fsp = request.indexOf(' ');
int nsp = request.indexOf(' ', fsp+1);
int eol = request.indexOf('\n');
String protocol = request.substring(0, fsp);
statusCode = Integer.parseInt(request.substring(fsp+1, nsp));
reasonPhrase = request.substring(nsp+1, eol);
String raw_mime_header = request.substring(eol + 1);
mh = new MimeHeader(raw_mime_header);
}
HttpResponse(String request) {
parse(request);
}
HttpResponse(int code, String reason, MimeHeader m) {
statusCode = code;
reasonPhrase = reason;
mh = m;
}
public String toString() {
return "HTTP/1.0 " + statusCode + " " + reasonPhrase + CRLF +
mh + CRLF;
}
}
UrlCacheEntry.java
为在服务器上保存文档的内容,必须在用于找回文档的URL和文档自身描述之间建立联系。一个文档由它的MimeHeader和原始数据描述。例如一副图像可以被一个Content-Type:image/gif样式的MimeHeader描述,而原始图像数据就是一个字节数组。同样,一个网页在它的MimeHeader中有Content-Type:text/html关键字/值对,而原始数据就是HTML页的内容。再次申明,实例变量不是私有的,所以httpd可以自由的访问它们。
构造函数 UrlCacheEntry 对象的构造函数需要用URL作为关键字以及一个与之相关的MimeHeader。如果MimeHeader内部有一个名为Content-Length成员(大多数情况下如此),数据区域被预先分配足够大的空间来保存它的内容。append( ) append( ) 方法用来给UrlCacheEntry对象增添数据的。它不是一个简单的setData( )方法,原因是数据可能流经网络且需要在一定时间被存储成块。append( )方法处理三种情形。第一种,数据缓冲区根本没有分配。第二种情形,数据缓冲区对于引入的数据来说太小,所以它被重新分配。最后一种情况,引入的数据正好可以插入缓冲区。在任何时候,length成员变量保存数据缓冲区当前的有效大小值。代码 下面是UrlCacheEntry的源代码:
class UrlCacheEntry
{
String url;
MimeHeader mh;
byte data[];
int length = 0;
public UrlCacheEntry(String u, MimeHeader m) {
url = u;
mh = m;
String cl = mh.get("Content-Length");
if (cl != null) {
data = new byte[Integer.parseInt(cl)];
}
}
void append(byte d[], int n) {
if (data == null) {
data = new byte[n];
System.arraycopy(d, 0, data, 0, n);
length = n;
} else if (length + n > data.length) {
byte old[] = data;
data = new byte[old.length + n];
System.arraycopy(old, 0, data, 0, old.length);
System.arraycopy(d, 0, data, old.length, n);
} else {
System.arraycopy(d, 0, data, length, n);
length += n;
}
}
}
查看本文来源
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章