Heim  >  Artikel  >  Java  >  Tomcat-Studiennotizen (1) Ein einfacher Webserver

Tomcat-Studiennotizen (1) Ein einfacher Webserver

PHP中文网
PHP中文网Original
2017-07-07 18:12:481030Durchsuche
Der Inhalt besteht aus den Kernpunkten des ersten Kapitels von „Eingehende Analyse von Tomcat“ und meiner eigenen Zusammenfassung. Wenn die Beschreibung unklar ist, können Sie das Originalbuch überprüfen.
1. HTTP-Protokoll:
1. Definition: Ein Protokoll zur Kommunikation zwischen Servern und Clients, das es Webservern und Browsern ermöglicht, Daten über das Internet zu senden und zu empfangen. Es handelt sich um ein Anforderungs- und Antwortprotokoll, das das zuverlässige TCP-Protokoll verwendet. Der Port des TCP-Protokolls ist 80 und ein verbindungsorientiertes Protokoll.
2. Drei Komponenten der HTTP-Protokollanforderung: Diese drei Teile werden durch Wagenrücklauf und Zeilenvorschub (CRLF) getrennt
Anforderungsteil: Methode (7 Typen, einschließlich GET/POST, andere werden selten verwendet und im Buch vorgestellt) [Leerzeichen, dieser Teil des Inhalts wird durch Leerzeichen getrennt] Uniform Resource Identifier URI [Leerzeichen, dieser Teil des Inhalt wird durch Leerzeichen getrennt] Protokoll/Protokollversion
URLs beziehen sich normalerweise auf das Stammverzeichnis des Servers und beginnen daher mit „/“.
Anforderungsheader: Der Anforderungsheader enthält nützliche Informationen über die Clientumgebung und den Hauptinhalt der Anforderung. Dies kann beispielsweise die Sprache der Browsereinstellungen, die Länge des Hauptinhalts usw. umfassen. Jeder Header wird durch ein CRLF-Zeichen (Carriage Return Line Feed) getrennt.
Inhalt des Anforderungstexts: Für das HTTP-Anforderungsformat ist es sehr wichtig, zwischen dem Header und dem Inhalt des Texts einen Zeilenvorschub mit Wagenrücklauf (CRLF) zu haben. CRLF teilt dem HTTP-Server mit, wo der Textinhalt beginnt. In einigen Internet-Programmierbüchern wird CRLF auch als vierter Teil von HTTP-Anfragen betrachtet.
3. Die HTTP-Antwort besteht außerdem aus drei Teilen:
·Methode – Uniform Resource Identifier (URI) – Protokoll/Version
· Antwortheader
· Hauptinhalt
2. Kommunikation zwischen Server und Client
1. Die Kommunikation zwischen dem Server und dem Client erfordert zwei Teile: Socket (Client) und ServerSocket (Server)
(1) ServerSocket (java.net.ServerSocket, serverseitiger Socket). Um einen Server-Socket zu erstellen, müssen Sie eine der vier von der ServerSocket-Klasse bereitgestellten Konstruktionsmethoden verwenden. Sie müssen die IP-Adresse und die Portnummer angeben, die der Server-Socket abhört. Normalerweise lautet die IP-Adresse 127.0.0.1, was bedeutet, dass der Server-Socket den lokalen Computer überwacht. Die IP-Adresse, die der Server-Socket überwacht, wird als Bindungsadresse bezeichnet. Ein weiteres wichtiges Attribut des Server-Sockets ist der Rückstand. Dies ist die maximale Warteschlangenlänge eingehender Verbindungsanforderungen, bevor der Server-Socket beginnt, eingehende Anforderungen abzulehnen. Die vier Konstruktionsmethoden sind:
ServerSocket ss = new ServerSocket();//Erstelle einen ungebundenen ServerSocket
ServerSocket ss = new ServerSocket(int port);//Erstelle einen ServerSocket, der an einen bestimmten Port gebunden ist
ServerSocket ss = new ServerSocket(int port, int log);//Erstellen Sie einen ServerSocket, der an einen bestimmten Port gebunden ist, und legen Sie die maximale Warteschlangenlänge fest.
ServerSocket ss = new ServerSocket(int port, int log, InetAddress address);//Erstellen Sie einen ServerSocket, der an eine bestimmte Adresse und einen bestimmten Port gebunden ist, und legen Sie die maximale Warteschlangenlänge fest.
Für den vierten Konstruktor muss die Bindungsadresse eine Instanz von InetAddress sein. Eine einfache Möglichkeit, ein InetAddress-Objekt zu erstellen, besteht darin, seine statische Methode getByName aufzurufen und eine Zeichenfolge mit dem Hostnamen zu übergeben, wie unten. Der Code ist derselbe .
InetAddress.getByName("127.0.0.1");
Gängige Methoden zum Erstellen von ServerSocket:
new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));
Der Code erstellt einen ServletSocket, der Port 8080 des lokalen Computers überwacht und dessen Warteschlangenlänge 1 beträgt.
Nachdem der Server erstellt wurde, bleibt er im Wartezustand (das TCP-Protokoll, ein zuverlässiges Übertragungsprotokoll, ist ein synchrones Protokoll, das heißt, es wartet, bis keine Antwort erfolgt)
(2) Socket (java.net.Socket-Klasse, Client-Socket): Sie müssen den IP-/Hostnamen und die Portnummer des Servers kennen, auf den Sie zugreifen möchten, und können dann eine Anfrage an den Server senden. Sie können eine der vielen Konstruktionsmethoden von Socket verwenden, um einen Socket
zu erstellen
neuer Socket ("yahoo.com", 80);
Sobald Sie erfolgreich eine Instanz der Socket-Klasse erstellt haben, können Sie diese zum Senden und Empfangen von Bytestreams verwenden. Um einen Bytestream zu senden, müssen Sie zunächst die getOutputStream-Methode der Socket-Klasse aufrufen, um ein java.io.OutputStream-Objekt abzurufen. Um Text an eine Remoteanwendung zu senden, erstellen Sie häufig ein java.io.PrintWriter-Objekt aus dem zurückgegebenen OutputStream-Objekt. Um einen Bytestream vom anderen Ende der Verbindung zu empfangen, können Sie die Methode getInputStream der Socket-Klasse aufrufen, um ein java.io.InputStream-Objekt zurückzugeben.
(3) Der Server empfängt die Verbindungsanforderung des Clients über die Methode „accept()“, stellt eine Verbindung mit dem Client her und gibt einen Socket zurück
Socket s = ss akzeptieren();
(4) Über Socket können ein Eingabestream und ein Ausgabestream abgerufen werden. Der Eingabestream wird zum Lesen der Client-Anforderungsdaten und der Ausgabestream zum Zurückgeben von Antwortinformationen an den Client verwendet.
Zum Beispiel: InputStream input = s.getInputStream();
OutputStream-Ausgabe = s.getOutputStream();
3. Einfaches Webserver-Kommunikationsbeispiel (es wird empfohlen, es zur Ansicht und Ausführung nach MyEclipse zu kopieren)
1. Serverklasse
package com.socket.httpservertest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class HttpServer {
     public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";
     // shutdown command
     private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
     // the shutdown command received
     private boolean shutdown = false;
     public static void main(String[] args)
     {
           HttpServer server = new HttpServer();
           server.await();
           
     }
     public void await() {
     //   System.out.println(System.getProperty("user.dir"));
           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 (!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;
                }
           }
    }
}
2. Kurs anfordern
package com.socket.httpservertest;
import java.io.IOException;
import java.io.InputStream;
public class Request {
     private InputStream input;
     private String uri;
     public Request(InputStream input)
     {
           this.input = input;
     }
     
     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); //将从输入流取2048长度的内容存到buffer字节数组中,如果内容不到2048,数组其他空间剩余空着
           } 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(' ');
           /*
            * http请求行的结构:方法 统一资源标识符(URI) 协议/版本(它们之间以空格分隔)
            * 例如:POST //examples/default.jsp HTTP/1.1
            */
           if (index1 != -1) {// index1 == -1表示没找到
                     index2 = requestString.indexOf(' ', index1 + 1);//从index+1位置开始寻找‘ ’
                     if (index2 > index1)
                     return requestString.substring(index1 + 1, index2);
                }
           return null;
     }
     
     public String getUri()
     {
           return uri;
     }
}
3. Antwortklasse
package com.socket.httpservertest;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
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;
     }
     
     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) { //ch==-1表示读到末尾了
                           output.write(bytes, 0, ch); //写出到浏览器
                           ch = fis.read(bytes, 0, BUFFER_SIZE);//再读会接上一次读的位置往下读,如果读到末尾就会返回-1,终止输出
                     }
                } 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</h1>";
                     output.write(errorMessage.getBytes());
                }
           }catch (Exception e) {
                // thrown if cannot instantiate a File object
                System.out.println(e.toString() );
           } finally {
                if (fis!=null)
                     fis.close();
           }
     }
}
4. Beispielcode-Funktionsbeschreibung: Der Browser gibt eine http-Anfrage ein, z. B. http://localhost:8080/MyHtml.html. Nach Erhalt der Anfrage liest der Server den Inhalt der Anfrage Dateispeicherort und verwendet dann den Dateieingabestream, um den Inhalt der Datei zu lesen. Geben Sie schließlich eine Antwort an den Browser-Client zurück und zeigen Sie den Inhalt in der HTML-Datei im Browser an, wie in der Abbildung gezeigt:
5. Beispielcode für ein funktionsübergreifendes Flussdiagramm:

Das obige ist der detaillierte Inhalt vonTomcat-Studiennotizen (1) Ein einfacher Webserver. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn