了解HTTP協議棧(實踐篇)


  關於http協議的理論知識,我在這里就不詳細說明了,具體下面給出的鏈接有。接下來都是用具體的操作顯示的,各位可以結合起來看。

  一、使用nc打開端口,並使用瀏覽器進行訪問 (對應文章中的HTTP協議詳解之請求篇)

  nc -lp 8888      #使用nc打開本地的8888端口

  使用瀏覽器,在地址欄上輸入http://localhost:8888 進行訪問(提出請求),此時nc界面上就會有得到一個請求的HTTP協議,具體的請求信息如下:

GET / HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/33.0.1750.154 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6

  

  

  請求后nc沒有給出回應的話,瀏覽器會一直在該頁面進行等待。如果手動結束nc程序的話,由於沒有給出回應信息,瀏覽器會給出無法訪問該頁面。

 

  二、nc后面接着一個資源文件(對應文章中的HTTP協議詳解之響應篇)

  首先寫一個htmlhelloworld

1 <html>
2 <head>
3 <title>welcome</title>
4 <head>
5 <body>
6 <h1>Hello World</h1>
7 </body>
8 </html>

  然后再命令行中輸入

 nc -lp 8888 < helloworld.html

  再瀏覽器中進行訪問就可以得到一個頁面了

   

  我們打開瀏覽器的開發工具,chrome瀏覽器的快捷鍵是F12,再network中可以看到下面信息

   

  可以看到里面有200 OK這個響應類別號

 

  三、代碼實現一個簡單的服務器(這里給出一個網上的java實現)

  沒有辦法,http服務器,就要用到Socket編程,而c++在這一方面又沒有具體的標准。所以會有linuxwindows下的不同,不過java在這方面就沒有問題了,先給出個java版的嘗嘗鮮。代碼雖然多,但是具體不難理解。

  1 import java.io.*;
  2 import java.net.ServerSocket;
  3 import java.net.Socket;
  4 
  5 
  6 public class SingleFileHTTPServer extends Thread {
  7     
  8     private byte[] content;
  9     private byte[] header;
 10     private int port=80;
 11     
 12     private SingleFileHTTPServer(String data, String encoding,
 13                 String MIMEType, int port) throws UnsupportedEncodingException {
 14         this(data.getBytes(encoding), encoding, MIMEType, port);
 15     }
 16     
 17     public SingleFileHTTPServer(byte[] data, String encoding, String MIMEType, int port)throws UnsupportedEncodingException {
 18         this.content=data;
 19         this.port=port;
 20         String header="HTTP/1.0 200 OK\r\n"+
 21             "Server: OneFile 1.0\r\n"+
 22             "Content-length: "+this.content.length+"\r\n"+
 23             "Content-type: "+MIMEType+"\r\n\r\n";
 24         this.header=header.getBytes("ASCII");
 25     }
 26     
 27     public void run() {
 28         try {
 29             ServerSocket server=new ServerSocket(this.port);
 30             System.out.println("Accepting connections on port "+server.getLocalPort());
 31             System.out.println("Data to be sent:");
 32             System.out.write(this.content);
 33             
 34             while (true) {
 35                 Socket connection=null;
 36                 try {
 37                     connection=server.accept();
 38                     OutputStream out=new BufferedOutputStream(connection.getOutputStream());
 39                     InputStream in=new BufferedInputStream(connection.getInputStream());
 40                     
 41                     StringBuffer request=new StringBuffer();
 42                     while (true) {
 43                         int c=in.read();
 44                         if (c=='\r'||c=='\n'||c==-1) {
 45                             break;
 46                         }
 47                         request.append((char)c);
 48                         
 49                     }
 50                         
 51                         //如果檢測到是HTTP/1.0及以后的協議,按照規范,需要發送一個MIME首部
 52                         if (request.toString().indexOf("HTTP/")!=-1) {
 53                             out.write(this.header);
 54                         }
 55                         
 56                         out.write(this.content);
 57                         out.flush();
 58                     
 59                 } catch (IOException e) {
 60                     // TODO: handle exception
 61                 }finally{
 62                     if (connection!=null) {
 63                         connection.close();
 64                     }
 65                 }
 66             }
 67             
 68         } catch (IOException e) {
 69             System.err.println("Could not start server. Port Occupied");
 70         }
 71     }
 72     
 73     public static void main(String[] args) {
 74         try {
 75             String contentType="text/plain";
 76             if (args[0].endsWith(".html")||args[0].endsWith(".htm")) {
 77                 contentType="text/html";
 78             }
 79             
 80             InputStream in=new FileInputStream(args[0]);
 81             ByteArrayOutputStream out=new ByteArrayOutputStream();
 82             int b;
 83             while ((b=in.read())!=-1) {
 84                 out.write(b);
 85             }
 86             byte[] data=out.toByteArray();
 87             
 88             //設置監聽端口
 89             int port;
 90             try {
 91                 port=Integer.parseInt(args[1]);
 92                 if (port<1||port>65535) {
 93                     port=80;
 94                 }
 95             } catch (Exception e) {
 96                 port=80;
 97             }
 98             
 99             String encoding="ASCII";
100             if (args.length>2) {
101                 encoding=args[2];
102             }
103             
104             Thread t=new SingleFileHTTPServer(data, encoding, contentType, port);
105             t.start();
106             
107         } catch (ArrayIndexOutOfBoundsException e) {
108              System.out.println("Usage:java SingleFileHTTPServer filename port encoding");
109         }catch (Exception e) {
110             System.err.println(e);// TODO: handle exception
111         }
112     }
113 }
View Code

 

  四、jsp等動態網站的問題

  在myeclipse中創建一個web工程,然后創建一個index.jsp文件

 1 <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 3 <html>
 4   <head>
 5    <title>welcome</title>
 6   </head>
 7   <body>
 8     <% String str="<h1>Hello JSP</h1>"; %>
 9     <% out.println(str); %>
10   </body>
11 </html>
View Code

  然后部署在tomcat中,在瀏覽器中訪問。

   

  我們可以在tomcatwork目錄(D:\tomcat-6.0.18\work\Catalina\localhost\test\org\apache\jsp)下找到一個名字為index_jsp.java的文件。

   

  使用servlet,對jsp文件進行打印輸出。具體的原理我也不是很懂,可以看《How Tomcat Works》。不過我想最后還是輸出成一個html文件不然在客戶端查看源代碼怎么會是html呢。

   

  其他的動態語言應該也是這個思路了。

 

  五、圖解服務器-客戶端連接過程(單服務器)

  

 

六、C++版的Http服務器(Linux Socket)

  在centos 6.4 g++/gcc4.4.7

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/socket.h>
 4 #include <netinet/in.h>
 5 #include <string.h>
 6 #include <arpa/inet.h>
 7 #include <stdlib.h>
 8 #include <unistd.h>
 9 
10 int main(int argc,char * argv[])
11 {
12     int server_sockfd;
13     int client_sockfd;
14     int len;
15     struct sockaddr_in my_addr;
16     struct sockaddr_in remote_addr;
17     socklen_t sin_size;
18     char buf[BUFSIZ];
19     memset(&my_addr,0,sizeof(my_addr));
20     my_addr.sin_family=AF_INET;
21     my_addr.sin_addr.s_addr=INADDR_ANY;
22     my_addr.sin_port=htons(8888);
23 
24     if((server_sockfd=socket(PF_INET,SOCK_STREAM,0))<0)
25     {
26         perror("socket");
27         return -1;
28     }
29     if(bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))<0)
30     {
31         perror("bind");
32         return -1;
33     }
34 
35     listen(server_sockfd,5);
36     sin_size=sizeof(struct sockaddr_in);
37 
38     if((client_sockfd=accept(server_sockfd,(struct sockaddr *)&remote_addr,&sin_size))<0)
39     {
40         perror("accept");
41         return -1;
42     }
43 
44     printf("accept client %s\n",inet_ntoa(remote_addr.sin_addr));
45     char *pch="<html><h1>Hello World</h1></html>";
46     len=send(client_sockfd,pch,strlen(pch),0);
47 
48     while((len=recv(client_sockfd,buf,BUFSIZ,0))>0)
49     {
50         buf[len]='\0';
51         printf("%s\n",buf);
52         /*
53         if(send(client_sockfd,buf,len,0)<0)
54         {
55             perror("write");
56             return -1;
57         }
58         */
59     }
60     close(client_sockfd);
61     close(server_sockfd);
62 
63     return 0;
64 }
View Code

  該代碼還沒有實現判斷后綴文件,多用戶連接,返回的狀態碼等問題。這個只是一個簡單的服務器。如果你對服務器有興趣可以查看服務器源代碼。apache我們看不懂。一個小一點的http總能看懂吧。

  

  參考資料:

    Nc 下載http://joncraton.org/blog/46/netcat-for-windows/ 

    Nc 的使用http://freetstar.com/use-nc-in-the-linux/ 

    Http 協議詳解http://blog.csdn.net/gueter/article/details/1524447 

    Java版的http服務器http://blog.csdn.net/yanghua_kobe/article/details/7296156 

    C++版的Http服務器http://www.cppblog.com/kevinlynx/archive/2008/07/30/57521.html 

    TCP Socket linux: http://blog.csdn.net/wangyf101/article/details/9790807 

  資料下載: http://files.cnblogs.com/wunaozai/%E4%BA%86%E8%A7%A3HTTP%E5%8D%8F%E8%AE%AE%E6%A0%88.zip

  本文鏈接: http://www.cnblogs.com/wunaozai/p/3733432.html 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM