了解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协议详解之响应篇)
首先写一个html的helloworld
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++在这一方面又没有具体的标准。所以会有linux和windows下的不同,不过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 }
四、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>
然后部署在tomcat中,在浏览器中访问。
我们可以在tomcat的work目录(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 }
该代码还没有实现判断后缀文件,多用户连接,返回的状态码等问题。这个只是一个简单的服务器。如果你对服务器有兴趣可以查看服务器源代码。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
资料下载: https://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
作者:无脑仔的小明 出处:http://www.cnblogs.com/wunaozai/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 如果文中有什么错误,欢迎指出。以免更多的人被误导。有需要沟通的,可以站内私信,文章留言,或者关注“无脑仔的小明”公众号私信我。一定尽力回答。 |