1. First, let’s take a look at the message structure of http.
1. Request message
An HTTP request message consists of four parts: request line, request header, blank line and request data. The following figure shows the general format of the request message.
(1) Request line
The request line consists of three fields: the request method field, the URL field, and the HTTP protocol version field, which are separated by spaces. For example, GET /index.html HTTP/1.1.
The request methods of the HTTP protocol include GET, POST, HEAD, PUT, DELETE, OPTIONS, TRACE, and CONNECT. Here we introduce the most commonly used GET method and POST method.
GET: The GET method is used when the client wants to read a document from the server. The GET method requires the server to put the resource located by the URL in the data part of the response message and send it back to the client. When using the GET method, the request parameters and corresponding values are appended to the URL. A question mark ("?") is used to represent the end of the URL and the beginning of the request parameters. The length of the passed parameters is limited. For example, /index.jsp?id=100&op=bind.
POST: The POST method can be used when the client provides a lot of information to the server. The POST method encapsulates request parameters in HTTP request data, appearing in the form of name/value, and can transmit large amounts of data.
(2)Request header
The request header consists of keyword/value pairs, one pair per line, and the keywords and values are separated by English colon ":". The request header informs the server about the client's request. Typical request headers are:
User-Agent: The browser type that generated the request.
Accept: List of content types recognized by the client.
Host: The requested host name, allowing multiple domain names to be at the same IP address, that is, a virtual host.
(3) Blank line
The last request header is followed by a blank line, carriage return and line feed characters are sent to notify the server that there are no more request headers to follow.
(4)Request data
The request data is not used in the GET method, but in the POST method. The POST method is suitable for situations where customers are required to fill out a form. The most commonly used request headers related to request data are Content-Type and Content-Length.
2. Response message
The format of the response message is generally similar to the request message, except that the first line is different. Readers can find the introduction to this aspect on the Internet and will not go into details here.
2. Implementation of program
The steps to implement the program are as follows:
1. Receive the request from the client browser;
2. Create a new thread to handle the request;
3. Read the message data, determine whether the message is correct, and analyze the message content;
4. Create a response message and send it to the client;
5. End the processing thread and process other customer requests;
The program code is as follows:
view plaincopy to clipboardprint?
import java.net.*;
import java.io.*;
import java.util.*;
import java.lang.*;
public class WebServer {
public static void main(String [] args){
int port;
ServerSocket server_socket;
try{
port=Integer.parseInt(args[0]);
}
catch (Exception e){
port=8080;
}
try{
server_socket=new ServerSocket(port);
System.out.println("WebServer running on port"+server_socket.getLocalPort());
while(true){
Socket socket=server_socket.accept();
System.out.println("New connection accepted"+socket.getInetAddress()+":"+socket.getPort());
//Create a thread for a specific request to handle the request
try{
httpRequestHandler request=new httpRequestHandler(socket);
Thread thread=new Thread(request);
thread.start();
}
catch(Exception e){
System.out.println(e);
}
}
}
catch(IOException e){
System.out.println(e);
}
}
}
//Thread class for processing requests
class httpRequestHandler implements Runnable{
final static String CRLF="rn";
Socket socket;
InputStream input;
OutputStream output;
BufferedReader br;
//Determine whether the requested file type is correct
boolean fileType=true;
//Initialization parameters
public httpRequestHandler(Socket socket) throws Exception{
this.socket=socket;
this.input=socket.getInputStream();
this.output=socket.getOutputStream();
this.br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
//Start the thread
public void run(){
try{
processRequest();
}
catch(Exception e){
System.out.println(e);
}
}
//Core function for processing requests
private void processRequest() throws Exception{
while(true){
String headerLine=br.readLine();
System.out.println("the client request is"+headerLine);
if(headerLine.equals(CRLF)||headerLine.equals(""))
break;
StringTokenizer s=new StringTokenizer(headerLine);
String temp=s.nextToken();
if(temp.equals("GET")){
String fileName=s.nextToken();
fileName="."+fileName;
FileInputStream fis=null;
boolean fileExists=true;
if(!(fileName.endsWith(".htm")||fileName.endsWith(".html")))
{
this.fileType=false;
try{
fis=new FileInputStream("error.html");
}
catch(FileNotFoundException e){
fileExists=false;
}
}
else{
try{
fis=new FileInputStream(fileName);
}
catch(FileNotFoundException e){
fileExists=false;
}
}
String serverLine="Server:a simple java WebServer";
String statusLine=null;
String contentTypeLine=null;
String entityBody=null;
String contentLengthLine="error";
if(fileExists&&this.fileType){
statusLine="HTTP/1.0 200 OK"+CRLF;
contentTypeLine="Content-type:"+this.contentType(fileName)+CRLF;
contentLengthLine="Content-Length:"+(new Integer(fis.available())).toString()+CRLF;
}
else{
if(fileExists&&this.fileType==false){
statusLine="HTTP/1.0 400 BadRequest"+CRLF;
contentTypeLine="text/html";
entityBody="<HTML>400 Not BadRequest</TITLE></HEAD>"+
"<BODY>400 BadRequest"+
"<br>usage:http://yourHostName:port/"+
"fileName.html</BODY></HTML>";
}
else if(fileExists==false){
statusLine="HTTP/1.0 404 Not Found"+CRLF;
contentTypeLine="text/html";
entityBody="<HTML>404 Not Found</TITLE></HEAD>"+
"<BODY>404 Not Found"+
"<br>usage:http://yourHostName:port/"+
"fileName.html</BODY></HTML>";
}
}
output.write(statusLine.getBytes());
output.write(serverLine.getBytes());
output.write(contentTypeLine.getBytes());
output.write(contentLengthLine.getBytes());
output.write(CRLF.getBytes());
if(fileExists&&this.fileType){
sendBytes(fis,output);
fis.close();
}
else{
output.write(entityBody.getBytes());
}
}
}
try{
output.close();
br.close();
socket.close();
}
catch(Exception e){}
}
//Send the page requested by the client
private static void sendBytes(FileInputStream fis,OutputStream os) throws Exception{
byte[] buffer=new byte[1024];
int bytes=0;
while((bytes=fis.read(buffer))!=-1){
os.write(buffer,0,bytes);
}
}
//Set the content of contentType
private static String contentType(String fileName){
if(fileName.endsWith(".htm")||fileName.endsWith(".html")){
return "text/html";
}
return "fileName";
}