How Java-based Web servers work 1
A Web server, also known as an HTTP server, communicates with clients over HTTP. This client usually refers to a web browser. A Java-based Web server uses two important classes: java.net. socket and java.net. serversocket, which communicate with each other through HTTP messages. Therefore, this article begins with discussing HTTP and these two classes, and I will explain a simple web application related to this article.
The Hypertext Transfer Protocol (HTTP)
HTTP is a protocol that allows web servers and browsers (clients) to send and receive data over the Internet. It is a request and response protocol-the client sends a request and the server responds to the request. HTTP uses a reliable TCP connection, usually using TCP port 80. Its first version is HTTP/0.9, which is then replaced by HTTP/1.0. The current version is HTTP/1.1, which is defined by rfc2616(scheme.
This section mainly corresponds to HTTP 1.1, which is sufficient for you to fully understand the messages sent by web server programs. If you are interested in more detailed knowledge, refer to rfc2616.
In HTTP, the Client Always initiates a transaction by establishing a connection and sending an HTTP request. The server cannot actively contact the client or send a call back connection to the client. Both the client and the server can interrupt a connection in advance. For example, when you use a browser to download an object, you can click "stop" to interrupt the download of the object and close the HTTP connection to the server.
HTTP Request
An HTTP request consists of three parts:
Method-Uri-Protocol/version method-address-version
Request Header
Entity body Request Entity
The following is an HTTP request instance:
Post/servlet/Default. jsp HTTP/1.1
Accept: text/plain; text/html
Accept-language: En-GB
Connection: keep-alive
HOST: localhost
Referer: http: // localhost/ch8/senddetails.htm
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 = Franks & firstname = Michael
The method-Uri-Protocol/version is in the first line of the request:
Post/servlet/Default. jsp HTTP/1.1
Post is the request type. Each client HTTP request can be one of the many request types specified in the HTTP specification. HTTP 1.1 supports seven types of requests: Get, post, Head, options, put, delete, and trace. Get and post are common request types in Internet applications.
The URI completely specifies Internet resources. A URI is usually parsed to the root directory of the server. In this way, it should always start with a '/' prefix. A URL is actually a type of Uri.
Version refers to the HTTP protocol version used by the HTTP request.
The request header contains some useful information about the client environment and request entity. For example, it contains the language and object length set by the browser. Separate each request header with the carriage return line break (CRLF.
A very important empty line separates the request header from the object, marking the beginning of the object content. Some Internet Development books hold that this CRLF blank line is the fourth part of HTTP requests.
In the preceding HTTP request, the entity is just one line below:
Lastname = Franks & firstname = Michael
In a typical HTTP request, the Request Entity content is much longer.
HTTP Response
Similar to a request, an HTTP response is composed of three parts:
Protocol-status code-Description Protocol status description code
Response Headers Response Header
Entity body response entity
The following is an example of an HTTP response:
HTTP/1.1 200 OK
Server: Microsoft-Microsoft IIS/4.0
Date: Mon, 3 Jan 1998 13:13:33 GMT
Content-Type: text/html
Last-modified: Mon, 11 Jan 1998 13:23:42 GMT
Content-Length: 112
<HTML>
<Head>
<Title> HTTP response example </title> Welcome to brainy Software
</Body>
</Html>
The first line of the response header is similar to the first line of the Request Header, telling you that the protocol used is HTTP 1.1, the request is successful (200 = success), and there is no problem.
A response header similar to a request header also contains some useful information. The HTML content of the response object. The header and the object are separated by the empty line (CRLF) of the carriage return line.
Socket
A socket is the endpoint of a network connection, which enables an application to read and write data from the network. Two applications on different computers can communicate with each other by sending and receiving byte streams. To send a message to another application, you need to know its IP address and its socket port number. In Java, a socket is implemented using java.net. socket.
To create a socket, you can use one of the several construction methods in the socket class. One of them accepts the host name and port number as the parameter:
New socket ("Yahoo.com", 80 );
Once you have successfully created a socket class instance, you can use it to send and receive byte streams. To send a byte stream, you need to call the getoutputstream method of the socket class to obtain a java. Io. outputsteam object. To send text to a remote program, you usually need to create a java. Io. printwriter object from the returned outputstream. To receive byte streams from the other end of the connection, you need to call the getinputstream method of the socket class, which returns a java. Io. inputstream object.
The following code creates a socket (127.0.0.1 indicates a local host) that can communicate with the local HTTP server, sends an HTTP request, and receives the response from the server. It also creates a stringbuffer object to accept the response and print it to the console.
Socket socket = new socket ("127.0.0.1", "8080 ");
Outputstream OS = socket. getoutputstream ();
Boolean autoflush = true;
Printwriter out = new printwriter (socket. getoutputstream (),
Autoflush );
Bufferedreader in = new bufferedreader (
New inputstreamreader (socket. getinputstream ()));
// Send an HTTP request to the Web server
Out. println ("Get/index. jsp HTTP/1.1 ");
Out. println ("Host: localhost: 8080 ");
Out. println ("connection: Close ");
Out. println ();
// Read the response
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 );
}
// Display the response to the out console
System. Out. println (sb. tostring ());
Socket. Close ();
To get the correct response from the Web server, you must send HTTP requests compiled using the HTTP protocol. If you read the HTTP section above, you should be able to understand the HTTP request in the above Code.
Editor's note: This article is excerpted from the book published by Budi itself <Tomcat insider>. You can get more information on his website.
How Java-based Web servers work 2
Author: fajaven translation time: 17:00:38
Serversocket class
The socket class describes the "client" socket, which is used when you need to create a connection with a remote service program. If you want to implement a service program, such as an HTTP server or an FTP server, you need a different method. This is because your server must be served at any time and it does not know when a client program needs to connect to it.
For this purpose, you need to use the java.net. serversocket class, which is an implementation of the server socket. The server socket waits for connection requests from the client. Once it receives a connection request, it creates a socket instance to communicate with the client.
To create a server socket, you must use one of the four construction methods provided by the serversocket class. You need to specify the IP address and port number of the server socket listening. Typically, this IP address can be 127.0.0.1, which means that the server socket listens to a local machine. The IP address that the server socket listens to refers to the binding address. Another important attribute of the server socket is the queue length, that is, the maximum length of the Request queue accepted before the request is rejected.
One of the serversocket class construction methods is as follows:
Public serversocket (INT port, int backlog, inetaddress bindingaddress );
For this build method, the binding address must be an instance of the java.net. inetaddress class. An easy way to create an inetaddress class object is to call its static method getbyname and pass a string containing the host name.
Inetaddress. getbyname ("127.0.0.1 ");
The following code creates a server socket that listens to port 8080 of the Local Machine and limits the queue length to 1.
New serversocket (8080,1, inetaddress. getbyname ("127.0.0.1 "));
Once a serversocket instance is available, you can call its accept method to wait for the incoming link request. This method is returned only when a request is received. It returns a socket-class instance. This socket object can be used to send and receive byte streams from the client application, as said in the previous section. In fact, the accept method is the only method used in this example.
Application Instance
Our web server program is part of the ex01.pyrmont package. It contains three classes: httpserver; request; response.
The entire program entry (static main method) is the httpserver class. It creates an httpserver instance and calls its await method. As the name expresses, await waits for HTTP requests on a specific port, processes them, and returns a response to the client. It waits until it receives the Stop command. (Replace wait with the method name await because there is an important thread-related method in system)
This program only sends static resources from a specific directory, such as HTML and image files. It only supports the absence of file headers (such as dates and cookies. Now let's take a look at the three classes in the following sections.
Httpserver class
Httpserver implements a web server that provides static resources in a specific directory and Its subdirectories. This specific directory is specified by public static final web_root.
Web_root Initialization is as follows:
Public static final string web_root =
System. getproperty ("user. dir") + file. Separator + "webroot ";
The code list contains a directory named webroot, which contains some static resources that you can use to test the application. You can also see a servlet that will be used in my next article: "How does the servlets container work ".
To request a static resource, enter http: // machinename: Port/staticresources in the address bar of the browser.
If you send a request from a different machine to the machine running the application, machinename indicates the machine name or IP address of the machine running the application, and port is 8080, staticresources is the name of the requested file, which must be included in the web_root directory.
For example, if you use the same computer to test this application, you want httpserver to send the file index.html with the following address: http: // localhost: 8080/index.html
To stop the service, you only need to send a shutdown command from the browser, that is, after entering the Host: Port field in the address bar of the browser, add a pre-defined string. In our httpserver class, the Stop command is defined as shutdown, a static final variable.
Private Static final string shutdown_command = "/shutdown ";
Therefore, to stop the service, you can: http: // localhost: 8080/Shutdown
Now, let's take a look at the await method in list 1.1. The code list will be explained later.
Listing 1.1. The httpserver class 'await Method
Public void await (){
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 );
}
// Loop waiting for a request
While (! Shutdown ){
Socket socket = NULL;
Inputstream input = NULL;
Outputstream output = NULL;
Try {
Socket = serversocket. Accept ();
Input = socket. getinputstream ();
Output = socket. getoutputstream ();
// CREATE request object and parse
Request request = new request (input );
Request. parse ();
// Create response object
Response response = new response (output );
Response. setrequest (request );
Response. sendstaticresource ();
// Close the socket
Socket. Close ();
// Check if the previous URI is a shutdown command
Shutdown = request. geturi (). Equals (shutdown_command );
}
Catch (exception e ){
E. printstacktrace ();
Continue;
}
}
}
The await method starts by creating a serversocket instance and then enters a while loop.
Serversocket = new serversocket (
Port, 1, inetaddress. getbyname ("127.0.0.1 "));
...
// Loop waiting for a request
While (! Shutdown ){
...
}
In the while loop code, the accept method that runs to serversocket stops. This method only returns HTTP requests received on port 8080:
Socket = serversocket. Accept ();
After receiving the request, the await method is from the socket instance returned by the accept method to Java. Io. inputstream and Java. Io. outputstream:
Input = socket. getinputstream ();
Output = socket. getoutputstream ();
Then the await method creates a request object and calls its parse method to parse the original HTTP request:
// CREATE request object and parse
Request request = new request (input );
Request. parse ();
Next, the await method creates a response object and sets the request object to it to call its sendstaticresource method:
// Create response object
Response response = new response (output );
Response. setrequest (request );
Response. sendstaticresource ();
Finally, the await method closes the socket and calls the geturi method of the request to check whether the HTTP request address is a stop command. If yes, the shutdown variable is set to true, and the program exits the while loop:
// Close the socket
Socket. Close ();
// Check if the previous URI is a shutdown command
Shutdown = request. geturi (). Equals (shutdown_command );
How Java-based Web servers work 3
Author: fajaven posting time: 2003.09.12 17:11:54
Request class
The request class corresponds to an HTTP request. Create an instance of this class and pass it to the inputstream object obtained from the socket to capture communication with the client. Call one of the read methods of the inputstream object to obtain the original data of the HTTP request.
The request class has two public methods: parse and geturi. The parse method parses the original data of the HTTP request. It does not do much-the only information that makes it valid is the URI of the HTTP request, which is obtained by calling the private method parseuri. The parseuri method uses URI as a variable. Call the geturi method to obtain the HTTP request URI.
To understand how parse and parseuri work, you need to know the HTTP request structure, defined by rfc2616.
An HTTP request consists of three parts: request line, headers, and message body.
Now, we only need to pay attention to the request line, the first part of the HTTP request. The request line starts with a method mark, followed by the request URI and Protocol version, and ends with a line break. The elements of the request line are separated by spaces. For example, the request line for an index.html file using the get method is as follows:
GET/index.html HTTP/1.1
The parse method transmits the inputstream from the socket to the request object to read the byte stream and store the byte array in the buffer. Then, it puts the bytes in the buffer byte array into the stringbuffer object called request, and then replaces stringbuffer with a string and passes it to the parseuri method.
The code of the parse method is shown in list 1.2.
Listing 1.2. The request class 'parse Method
Public void parse (){
// Read a set of characters from the socket
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 ());
}
The parseuri method finds the first and second spaces of the request line, and obtains the URI from the request line. List 1.3 shows the code of the parseuri method.
Listing 1.3. The request class 'parseuri Method
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;
}
Response class
The response class describes the HTTP response. Its construction method accepts the outputstream object, as follows:
Public Response (outputstream output ){
This. Output = output;
}
The response object is created by passing the outputstream object obtained from the socket to the await method of the httpserver class.
The response class has two common methods: setrequest and setstaticresource. Setrequest is used to pass the request object to the response object. It is relatively simple, as shown in list 1.4:
Listing 1.4. The response class 'setrequest Method
Public void setrequest (request ){
This. Request = request;
}
The sendstaticresource method is used to send static resources, such as HTML files. Its implementation is shown in 1.5 in the list:
Listing 1.5. The response class 'sendstaticresource Method
Public void sendstaticresource () throws ioexception {
Byte [] bytes = new byte [buffer_size];
Fileinputstream FCM = NULL;
Try {
File file = new file (httpserver. web_root, request. geturi ());
If (file. exists ()){
FS = new fileinputstream (File );
Int CH = FCM. Read (bytes, 0, buffer_size );
While (Ch! =-1 ){
Output. Write (bytes, 0, CH );
Ch = FCM. Read (bytes, 0, buffer_size );
}
}
Else {
// File not found
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 Output. Write (errormessage. getbytes ());
}
}
Catch (exception e ){
// Thrown if cannot instantiate a file object
System. Out. println (E. tostring ());
}
Finally {
If (FS! = NULL)
FCM. Close ();
}
}
The sendstaticresource method is very simple. It first instantiates the java. Io. File class by passing the parent and sub-directories to the file class construction method.
File file new file (httpserver. web_root, request. geturi ());
Then, check whether the file exists. If yes, the sendstaticresource method passes the file object to create the java. Io. fileinputstream object. Call the read method of fileinputstream and write the byte array to the outputstream object output. In this way, the content of the static resource is sent to the browser as raw data.
If (file. exists ()){
FS = new fileinputstream (File );
Int CH = FCM. Read (bytes, 0, buffer_size );
While (Ch! =-1 ){
Output. Write (bytes, 0, CH );
Ch = FCM. Read (bytes, 0, buffer_size );
}
}
If the file does not exist, sendstaticresource sends an error message to the browser.
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 Output. Write (errormessage. getbytes ());
Compile and run applications
To edit and run the application in this article, you must first decompress the source code zip file. The directory directly decompressed is called a working directory. It has three subdirectories: src/, classes/, and LIB /. To compile the application, enter the following command from the working directory:
Javac-D. src/ex01/pyrmont/*. Java
-D option writes the result to the current directory instead of the src/directory.
To run the application, enter the following command in the current working directory:
Java ex01.pyrmont. httpserver
Test this application. Open your browser and enter the following address in the address bar: http: // localhost: 8080/index.html.
You will see index.html in your browser, as shown in 1.
Figure 1: Web Server output
On the console, you can see the following content:
GET/index.html HTTP/1.1
Accept :*/*
Accept-language: En-US
Accept-encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)
HOST: localhost: 8080
Connection: keep-alive
GET/images/logo.gif HTTP/1.1
Accept :*/*
Referer: http: // localhost: 8080/index.html
Accept-language: En-US
Accept-encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)
HOST: localhost: 8080
Connection: keep-alive
Summary
In this article (divided into three parts), you can see how a simple web server works. The related applications in this article only include three categories with incomplete functions. However, it is still a good learning tool.