扫一扫
关注微信公众号

高层协议POP3与HTTP
2007-09-24   网络

本节是《Java与Internet编程》的第三部分,也是最后一部分。在前面两节中,我们介绍了网络编程的基础知识,如协议、端口、套接字、UDP等,并给出了一些客户程序和服务程序的实现实例。本节我们介绍两个更高级的协议:POP3和HTTP,并给出一个POP3客户程序和一个HTTP服务器的实现。

   ㈠ POP3协议简介

   POP3是一种高级网络协议,它的全称是Post Office Protocol Version 3。使用该协议,客户程序能够动态地、有效地访问服务器上的邮件。简单地说,POP3是一种能够让客户程序提取驻留于服务器的邮件的协议。有关POP3的操作可以概括为:

服务器在端口110监听客户请求。
客户程序发出连接请求并通过身份验证。
客户程序发送命令;服务器处理命令并将结果发送给客户程序;重复这个过程直至客户程序结束或中止连接为止。
   POP3命令都是单行的,它由一个关键字开头,后面加上一个或多个参数,最后为一个回车符加一个换行符(CRLF)。服务器的应答可以由一行或多行组成,开头内容总是命令处理结果(+OK或-ERR),紧接着是其他附加信息,最后是一个CRLF。对于多行应答,最后一行是英文句点(“.")加一个CRLF。

   下表是部分POP3命令的说明:

 

命令 说 明
STAT 获得邮箱的状态信息,即邮件数量及大小。
RETR msg 下载指定的邮件。
DELE msg 将指定的邮件标记为删除。
NOOP 空操作。
RSET 取消所有的删除标记。
QUIT 结束会话。
TOP msg n 下载指定邮件的头信息及前面的n行。
UIDL [msg] 获得所有邮件或指定邮件的唯一标识符。
USER name 标示将要访问的邮箱(即用户名字)。
PASS pw 发送由USER命令指定的用户的密码(以明文发送)。

   ㈡ POP3客户程序实例

   下面的MailStat.java程序演示了POP3协议的基本用法。该程序的功能是检查指定服务器上的邮件状态。

 【MailStat.java】

 public class MailStat{

  private static final int POP3_PORT = 110;

  public static void main(String[] args) {

  String host;

  InetAddress hostAddress;

  String username;

  String password;

  Socket mailSocket;

  BufferedReader socketInput;

  DataOutputStream socketOutput;

  // 检查参数

  if (args.length < 3) {

  System.out.println("用法: MailStat [服务器] [用户名字] [密码]");

  }

  else {

  host = args[0];

  username = args[1];

  password = args[2];


  try {

  hostAddress = InetAddress.getByName(host);

  System.out.println("正在连接服务器" + hostAddress + "...");

  mailSocket = new Socket(host, POP3_PORT);

  try {

  socketInput = new BufferedReader(

  new InputStreamReader(mailSocket.getInputStream()) );

  socketOutput = new DataOutputStream(mailSocket.getOutputStream());

  // 从服务器读入初始应答

  readReply(socketInput);

  // 验证身份

  sendCommand(socketOutput, "USER " + username);

  readReply(socketInput);

  sendCommand(socketOutput, "PASS " + password);

  readReply(socketInput);

  // 获得状态信息

  sendCommand(socketOutput, "STAT");

  readReply(socketInput);

  // 结束会话

  sendCommand(socketOutput, "QUIT");

  readReply(socketInput);

  } finally {


  mailSocket.close();

  }

  }

  catch(Exception theException) {

  System.out.println(theException);

  }

  }

  System.exit(0);

  }

 

  /**

  * sendCommand() 发送一个POP3命令

  */

  private static void sendCommand(DataOutputStream out, String command)

  throws IOException {

  …略…

  }

  /**

  * readReply() 读取并显示POP3服务器的应答

  */

  private static String readReply(BufferedReader reader)

  throws IOException, Exception {

  …略…

  }

 }

   下面是其算法说明:

获得命令行参数,包括邮件主机、用户名称、密码。如果没有指定这些参数,则输出提示信息并退出。
获得邮件服务器的IP地址。
打开与邮件服务器通讯的Socket。
引用Socket的输入、输出流。
读取服务器的初始应答信息。
发送用户名字并读取应答。
发送密码并读取应答。
读取状态信息(邮件总数,邮箱大小)。
结束会话。
关闭Socket并退出。
   为简单计,我们没有为MailStat加上任何“特色”功能。您可以自己修改它使之更为实用,比如增加每隔几分钟检查一次的功能,或同时检查多个邮箱的功能,或一个图形用户界面,等等。

   ㈢ HTTP协议简介

   HTTP协议也是一种高级网络协议,是浏览器与Web服务器通信的标准协议。HTTP 1.1规范可以在RFC 2616找到,HTTP 1.0 规范可以在RFC 1945找到。

   有关HTTP的基本操作为:

服务器在端口80监听。
客户程序(如浏览器)连接到服务器并发送请求信息。
服务器发送应答信息。
由客户程序或服务器关闭连接。
   客户请求的一般格式为:

  < command> /< url> < HTTP-version>CRLF

  [< keyword>: < value>CRLF]

  ...

  [< keyword>: < value>CRLF]

   其中:

 < command> = 请求服务器处理的命令,如

  GET —— 提取文件

  HEAD —— 提取文件头

  POST —— 发送表单数据

  PUT —— 上载文件

 < url> = 要求提取文件的URL

 < HTTP-version> = 客户程序能够理解的HTTP版本,如

  HTTP/1.0、HTTP/1.1等等

 < keyword> = 提供给服务器的附加信息关键词。

  常见的关键词如:

  Accept —— 可以接受的数据类型

  User-Agent —— 用来标识浏览器

   下面是客户请求的几个示例:

 ●GET /foo.html HTTP/1.1

 ●GET /foo.html HTTP/1.1

  Accept: text/html

  Accept: text/plain

  Accept: image/gif

  Accept: image/jpg

  User-Agent: Netscape/4.5

   服务器应答的基本格式如下:

 < HTTP-version> < response-code>CRLF

  Server: < server-identity>CRLF

  MIME-version: < MIME-version>CRLF

  Content-type: < content-type>CRLF

  Content-length: 11160

  CRLF

  < data>

   其中:


 < HTTP-version> = 服务器所使用的HTTP版本号。
 < response-code> = 应答类型。它由两部分组成,即一个编号及文本说明。最常见的应答是“200 OK”和“404 Not Found”。编号为200-299的应答表示成功,300-399表示重定向,400-499表示客户错误,500-599表示服务器错误。
 < server-identity> = 服务器标识。
 < MIME-version> = 服务器所使用的MIME版本号。
 < content-type> = 所发送内容的MIME类型:text/html,image/gif等。
 < content-length> = 以字节计的发送内容长度。
 < data> = 内容。
   下面是服务器应答的一个实例:

  HTTP/1.1 200 OK

  Server: NCSA/1.4.2

  MIME-version: 1.0

  Content-type: text/html

  Content-length: 37756

  < html>


  < head>< title>Foo< /title>< /head>

  < body>Foo< /body>

  < /html>

   ㈣ 一个多线程HTTP服务器的实现

   下面的HttpServer.java给出了一个简单的Web服务器。它仅由两个类构成,只支持HTML、TEXT、GIF和JPEG文件的GET命令。

 【HttpServer.java】

 public class HttpServer {

  private static int DEFAULT_PORT = 80;

  private int serverPort;

  public static void main(String[] args) {

  int port = DEFAULT_PORT;

  // 获取命令行参数

  if (args.length >= 1) {

  try {

  port = Integer.parseInt(args[0]);

  } catch(NumberFormatException ex) {

  System.out.println("Usage: HttpServer [端口]");

  System.exit(0);

  }

  }

  (new HttpServer(port)).go();

  }

  public HttpServer() {

  this(DEFAULT_PORT);

  }

  public HttpServer(int port) {

  super();

  this.serverPort = port;

  }

  /**

  * 启动服务器

  */

  public void go() {

  ServerSocket httpSocket;

  Socket clientSocket;

  HttpRequestThread requestThread;

  try {

  httpSocket = new ServerSocket(serverPort);

  System.out.println("HttpServer在端口" + serverPort + "监听.");

  try {

  while (true) {

  clientSocket = httpSocket.accept();

  requestThread = new HttpRequestThread(clientSocket);

  requestThread.start();

  }

  } finally {

  httpSocket.close();

  }

  } catch(Exception ex) {

  System.out.println(ex.toString());


  }

  System.exit(0);

  }

 }

   下面是它的算法说明:

从命令行获取端口参数。若没有指定,则默认为80。
在指定的端口打开一个服务器Socket。
开始循环:
等待客户程序的连接请求,当请求到达时获得客户Socket的引用。
创建一个新的请求服务线程,并以客户Socket为参数启动该线程。
结束循环。
关闭服务器Socket并退出。
   客户请求的服务线程类实现如下:

 【HttpRequestThread.java】

 public class HttpRequestThread extends Thread {

  private Socket clientSocket;

  public HttpRequestThread(Socket clientSocket) {

  super();

  this.clientSocket = clientSocket;

  }

  /**

  * 启动服务线程

  */


  public void run() {

  OutputStream out;

  BufferedReader in;

  String line;

  StringTokenizer tokenizer;

  String method;

  String url;

  String httpVersion;


  try {

  try {

  // 引用输入、输出流

  out = clientSocket.getOutputStream();

  in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

  // 从客户请求读入一行

  line = in.readLine();

  tokenizer = new StringTokenizer(line);

  if (tokenizer.countTokens() == 3) {

  // 获得命令类型、URL、HTTP版本号

  …略…

  if (method.equalsIgnoreCase("get")) {

  sendResponse(out, url);

  }

  }

  } finally {

  clientSocket.close();

  }

  } catch (Exception ex) {

  System.out.println("RequestThread: " + ex.toString());

  }

  }

  /**

  * 将服务器应答发送给浏览器

  */

  public void sendResponse(OutputStream out, String url) throws IOException {

  …略…

  }

 }

   服务线程的算法说明如下:

引用Socket的输入、输出流。
打印客户请求内容。
如果客户请求命令为GET,则发送应答:若所请求的文件存在,则将该文件作为应答的内容发送;否则,发送“404 Not Found”。
   编译这两个Java类,执行“java HttpServer”之后,就可以用浏览器打开class文件所在目录下的页面文件了。

热词搜索:

上一篇:windows2003权限如何配置
下一篇:Web开发中远程脚本的应用

分享到:           收藏