一个基于JAVA的Web服务器主要使用两个重要类:java.net.Socket和java.net.ServerSocket。
因为web服务器使用HTTP与客户端进行通信,所以也称HTTP服务器。
1.1 HTTP
HTTP请求:
Method—Uniform Resource Identifier (URI)—Protocol/Version
Request headers
Entity body
e.g.
POST /examples/default.jsp HTTP/1.1
Accept: text/plain; text/html
Accept-Language: en-gb
Connection: Keep-Alive
Host: localhost
User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)
Content-Length: 33
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
lastName=liang&firstName=jianfeng
HTTP Method 包括 {GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE}
URI 统一资源标识符,一般为相对路径( 项目跟路径)。
Content-Length 内容的长度
消息实体和请求头之间有一个CRLF(回车/换行),告诉HTTP服务器哪里是消息实体的开始。
HTTP响应:
Protocol—Status code—Description
Response headers
Entity body
e.g.
HTTP/1.1 200 OK
Server: Microsoft-IIS/4.0
Date: Mon, 5 Jan 2004 13:13:33 GMT
Content-Type: text/html
Last-Modified: Mon, 5 Jan 2004 13:13:12 GMT
Content-Length: 112 <html>
<head> <title>HTTP Response Example</title> </head>
<body>
Welcome to Brainy Software
</body>
</html>
1.2 Socket类(客户端)
//通过new一个socket出来,与特点IP特点端口的服务器建立TCP连接,相当于一个通道。
Socket socket = new Socket("127.0.0.1", 8080);
OutputStream os = socket.getOutputStream();
boolean autoflush = true;
//通道有了,就可以进行通信了。通过sockket的输出流new一个PrintWriter出来就可以向通道中输入消息了。
PrintWriter out = new PrintWriter(socket.getOutputStream(), autoflush);
//通过socket的输入流new一个BufferedReader出来读取输入流中的消息。
BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//向通道输入请求消息,传递给服务器。
out.println("GET /index.jsp HTTP/1.1");
out.println("Host: localhost:8080");
out.println("Connection: Close");
out.println();
//从通道中读取服务器响应消息
boolean loop = true;
StringBuffer sb = new StringBuffer(8096);
while(loop){
if(in.ready()){
int i=0;
while(i!=-1){
i = in.read();
sb.append((char) i);
}
loop = false;
}
Thread.currentThread().sleep(50);
}
//在控制台打印服务器响应消息
System.out.println(sb.toString());
socket.close();
1.3 SocketServer类(服务端)
//建立一个server监听本机的8080端口
ServerSocket server = new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));
//等待请求的到来。如果请求来了,就返回(生成)一个handleServer来出来客户端的请求。并返回响应。
Socket handleServer = server.accept();
//后续的处理与1.2相同
...
1.4 举个栗子
HttpServer
import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.File;
/**
* 静态Http服务器,动态的在下一章讲解。
**/
public class HttpServer {
public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";
public static void main(String[] args) {
HttpServer server = new HttpServer();
server.await();
}
//等待客户端请求
public void await() {
ServerSocket serverSocket = null;
int port = 8080;
try {
serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
while (true) {
Socket socket = null;
InputStream input = null;
OutputStream output = null;
try {
socket = serverSocket.accept();
input = socket.getInputStream();
output = socket.getOutputStream();
Request request = new Request(input);
//解析并处理请求
request.parse();
//生成响应
Response response = new Response(output);
response.setRequest(request);
response.sendStaticResource();
//关闭通道
socket.close();
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
}
Request.java
import java.io.InputStream;
import java.io.IOException;
/**
*请求对象,封装了输入流和URI
**/
public class Request {
private InputStream input;
private String uri;
public Request(InputStream input) {
this.input = input;
}
public void parse() {
StringBuffer request = new StringBuffer(2048);
int i;
byte[] buffer = new byte[2048];
try {
i = input.read(buffer);
} catch (IOException e) {
e.printStackTrace();
i = -1;
}
for (int j = 0; j < i; j++) {
request.append((char) buffer[j]);
}
System.out.print(request.toString());
uri = parseUri(request.toString());
}
private String parseUri(String requestString) {
int index1, index2;
index1 = requestString.indexOf(' ');
if (index1 != -1) {
index2 = requestString.indexOf(' ', index1 + 1);
if (index2 > index1)
return requestString.substring(index1 + 1, index2);
}
return null;
}
public String getUri() {
return uri;
}
}
Response.java
import java.io.OutputStream;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.File;
/**
*响应对象,封装了请求对象和输出流
**/
public class Response {
private static final int BUFFER_SIZE = 1024;
Request request;
OutputStream output;
public Response(OutputStream output) {
this.output = output;
}
public void setRequest(Request request) {
this.request = request;
}
//把静态资源响应给客户端,如果没有返回404 File Not Found
public void sendStaticResource() throws IOException{
byte[] bytes = new byte[BUFFER_SIZE];
FileInputStream fis = null;
try {
File file = new File(HttpServer.WEB_ROOT, request.getUri());
if (file.exists()) {
fis = new FileInputStream(file);
int ch = fis.read(bytes, 0, BUFFER_SIZE);
while (ch != -1) {
output.write(bytes, 0, ch);
ch = fis.read(bytes, 0, BUFFER_SIZE);
}
} else {
String errorMessage = "HTTP/1.1 404 File Not Found\r\n"
+ "Content-Type: text/html\r\n"
+ "Content-Length: 23\r\n" + "\r\n"
+ "<h1>File Not Found</h1>";
output.write(errorMessage.getBytes());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fis != null)
fis.close();
}
}
}
浏览器输入http://localhost:8080/staticResource 试试看吧。