1.一个简单的 Web 服务器
Web服务器也称为超文本传输协议(HyperText Transfer Protocol,HTTP)服务器,因为它使用HTTP与其客户端(通常是Web浏览器)进行通信。基于java的web服务器,会使用两个重要的类:java.net.Socket 和java.net.ServerSocket,并通过发送 HTTP 消息进行通信。
1.1.超文本传输协议(HTTP)
HTTP 是一种协议,允许 web 服务器和浏览器通过互联网发送和接收数据,是一种“请求 — 响应”的协议。客户端请求一个文件,服务器对该请求进行响应。HTTP使用可靠的TCP连接--TCP默认使用 80 端口。
在HTTP中,始终都是客户端通过建立连接并发送一个HTTP请求来初始化一个事务的。web服务器端并不负责联系客户端或建立一个到客户端回调连接。无论是客户端或者服务器都可以提前终止连接。
1.2.HTTP 请求
一个HTTP请求包括三个组成部分:
· 请求方法——统一资源标识符(URI)—协议/版本
· 请求的头部
· 实体
方法——统一资源标识符(URI)——协议/版本出现在请求的第一行。
POST /examples/default.jsp HTTP/1.1
这里POST是请求方法,/examples/default.jsp是URI,而HTTP/1.1是协议/版本部分。
每个 HTTP 请求可以使用 HTTP 标准里边提到的多种方法之一。HTTP 1.1 支持 7 种类型的请求:GET, POST, HEAD, OPTIONS, PUT, DELETE和TRACE。GET和POST在互联网应用里边最普遍使用的两种请求方法。
URI指定Internet资源的完整路径。
URI通常会被解释为相对于服务器根目录的相对路径。因此,它总是以“/”开头的。统一资源定位符(Uniform Resource Locator,URL)实际上是URL一种类型。协议版本指明了当前请求使用的HTTP协议的版本。
请求头包含客户端环境和请求实体正文的相关信息。
对于HTTP请求格式来说,头部和主体内容之间有一个回车换行符(CRLF)是相当重要的。 CRLF告诉HTTP服务器主体内容是在什么地方开始的。在一些互联网编程书籍中, CRLF还被认为是HTTP请求的第四部分。
1.3.Socket 类
套接字是网络连接的一个端点。套接字使得一个应用可以从网络中读取和写入数据。放在两个不同计算机上的两个应用可以通过连接发送和接受字节流。为了从你的应用发送一条信息到另一个应用,你需要知道另一个应用的 IP 地址和套接字端口。在 Java 里边,套接字指的是java.net.Socket类。
要创建一个套接字,你可以使用Socket类众多构造方法中的一个。其中一个接收主机名称和端口号:
public Socket (java.lang.String host, int port)
在这里主机是指远程机器名称或者 IP 地址,端口是指远程应用的端口号。
一旦你成功创建了一个 Socket 类的实例,你可以使用它来发送和接受字节流。要发送字节流,你首先必须调用Socket类的getOutputStream方法来获取一个java.io.OutputStream对象。
要发送文本到一个远程应用,你经常要从返回的 OutputStream 对象中构造一个
java.io.PrintWriter 对象。要从连接的另一端接受字节流,你可以调用Socket 类的getInputStream方法用来返回一个java.io.InputStream对象。
1.4.ServerSocket 类
Socket 类代表一个客户端套接字,即任何时候你想连接到一个远程服务器应用的时候你构造的套接字,现在,假如你想实施一个服务器应用,例如一个 HTTP服务器或者 FTP 服务器,你需要一种不同的做法。这是因为你的服务器必须随时待命,因为它不知道一个客户端应用什么时候会尝试去连接它。为了让你的应用能随时待命,你需要使用java.net.ServerSocket类。这是服务器套接字的实现。
ServerSocket和Socket不同,服务器套接字的角色是等待来自客户端的连接请求。一旦服务器套接字获得一个连接请求,它创建一个Socket实例来与客户端进行通信。
要创建一个服务器套接字,你需要使用ServerSocket 类提供的四个构造方法中的一个。你需要指定 IP地址和服务器套接字将要进行监听的端口号。通常,IP 地址将会是 127.0.0.1,也就是说,服务器套接字将会监听本地机器。服务器套接字正在监听的 IP地址被称为是绑定地址。
服务器套接字的另一个重要的属性是backlog,这是服务器套接字开始拒绝传入的请求之前,传入的连接请求的最大队列长度。
其中一个ServerSocket类的构造方法如下所示:
public ServerSocket(int port, int backLog, InetAddress bindingAddress);
对于这个构造方法,绑定地址必须是 java.net.InetAddress 的一个实例。一种构造InetAddress 对象的简单的方法是调用它的静态方法 getByName,传入一个包含主机名称的字符串,就像下面的代码一样。
InetAddress.getByName("127.0.0.1");
下面一行代码构造了一个监听的本地机器8080端口的ServerSocket,它的backlog为1。
new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));
一旦你有一个 ServerSocket 实例,你可以让它在绑定地址和服务器套接字正在监听的端口上等待传入的连接请求。你可以通过调用ServerSocket类的accept方法做到这点。这个方法只会在有连接请求时才会返回,并且返回值是一个Socket类的实例。Socket对象接下去可以发送字节流并从客户端应用中接受字节流。