Socket网络编程--简单Web服务器(2)
2014-08-28 23:36
656 查看
上一小节通过阅读开源的Web服务器--tinyhttpd。大概知道了一次交互的请求信息和应答信息的具体过程。接下来我就自己简单的实现一个Web服务器。
下面这个程序只是实现一个简单的框架出来。这次先实现能够Accept客户端的请求。
简单创建web服务器
webserver.h
webserver.cpp
makefile
下面这个是运行时的截图
增加了几个函数get_line(由于socket的读取方式好像没有一行一行的读取)各种Page信息还有一个ServerRequest函数。
ServerRequest:这个函数里面有一个fork函数创建多进程。一开始我是把fork的创建放在主函数的,然后ServerRequest不用fork函数。但是最后会出现一个问题就是,每次在客户端发出请求后服务器一直没有给出应答,客户端浏览器一直处于加载状态,然后强制性终止程序,浏览器才会有反映。不知道原因,弄了很久。一直在想以前写的那篇HTTP是没有问题的。一查才知道原来我以前用的请求头Connection:close 而浏览器现在这个Connection默认的值是keep-alive。是长连接。所以才会出现这个情况。
get_line:由于socket没有一整行的读取数据,所以这里使用tinyhttpd这个程序里的代码。
Page_200 Page_501 Page_404 ... ...
到这里服务器可以简单的返回一个200ok的页面了。接下来要实现的是实现对第一行请求信息的处理,接下来的处理基本都是在ServerRequest这个函数里进行。
带处理get/post方法的WEB服务器
运行的结果
可以看出只要在浏览器地址栏写上什么就可以在GET后截取到,只是中文就显示成16进制了
还有这个成功获取第一个页面后会有一个获取/favicon.ico这个请求,这个是自动的,我没有在地址栏输入的。如果有学过静态页面HTML编写的就知道,这个是网页的图标,一般在主目录的根目录下。
在这里没有看到图标是由于这个favicon.ico不是通过简单text/html的Content-Type显示的所以这里就没有,等以后实现image发送就可以看到了。好了这一小节就到这里了。
参考资料: http://blog.csdn.net/hanchaoman/article/details/5685582
本文地址: /article/6193142.html
下面这个程序只是实现一个简单的框架出来。这次先实现能够Accept客户端的请求。
简单创建web服务器
webserver.h
#include <iostream> #include <string> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <pthread.h> #include <thread>//使用c++11的多线程 using namespace std; class WebServer { public: WebServer(); ~WebServer(); int ServerInit(u_short port); int ServerError(string str); int ServerAccept(); int ServerClose(); int ServerRequest(int cli_fd); int get_line(int cli_fd,char * buf,int size);//来自tinyhttpd int Page_200(int cli_fd); int Page_501(int cli_fd); private: int httpd; }; int WebServer::ServerRequest(int cli_fd) { char buf[1024]; int size=1024; int i=1; memset(buf,0,sizeof(buf)); while((i>0)&&strcmp("\n",buf)) { i=get_line(cli_fd,buf,sizeof(buf)); cout<<buf; } if(fork()==0) { //处理阶段 execl("/bin/ls","ls","/home/myuser/",NULL); } Page_200(cli_fd); close(cli_fd); return 0; } int WebServer::ServerAccept() { struct sockaddr_in cli_sin; socklen_t cli_len=sizeof(cli_sin); int cli_fd; cli_fd=accept(httpd,(struct sockaddr *)&cli_sin,&cli_len);//阻塞等待连接 if(cli_fd==-1) ServerError("Fail to accept"); cout<<"连接进来的IP: "<<inet_ntoa(cli_sin.sin_addr)<<":"<<ntohs(cli_sin.sin_port)<<endl; return cli_fd; } int WebServer::ServerInit(u_short port) { struct sockaddr_in sin; int on; httpd=socket(PF_INET,SOCK_STREAM,0); if(httpd==-1) ServerError("Fail to Socket"); //init sockaddr_in sin.sin_family=AF_INET; sin.sin_port=htons(port); sin.sin_addr.s_addr=htonl(INADDR_ANY); bzero(&(sin.sin_zero),8); setsockopt(httpd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)); if(::bind(httpd,(struct sockaddr *)&sin,sizeof(struct sockaddr))==-1) ServerError("Fail to bind"); //如果port指定为零那么就随机打开一个端口 if(port==0) { socklen_t len=sizeof(sin); if(getsockname(httpd,(struct sockaddr *)&sin,&len)==-1) ServerError("Fail to getsockname"); port=ntohs(sin.sin_port); } if(listen(httpd,100)<0) ServerError("Fail to listen"); return port; } /////////////// int WebServer::get_line(int cli_fd,char * buf,int size) { int i=0; char c='\0'; int n; while((i<size-1)&&(c!='\n')) { n=recv(cli_fd,&c,1,0); if(n>0) { if(c=='\r') { n=recv(cli_fd,&c,1,MSG_PEEK); if((n>0)&&(c=='\n')) recv(cli_fd,&c,1,0); else c='\n'; } buf[i]=c; i++; } else c='\n'; } buf[i]='\0'; return i; } int WebServer::ServerError(string str) { perror(str.c_str()); exit(-1); } int WebServer::ServerClose() { close(httpd); return 0; } int WebServer::Page_200(int cli_fd) { char buf[1024]; sprintf(buf, "HTTP/1.1 200 OK\r\n"); send(cli_fd, buf, strlen(buf), 0); sprintf(buf, "Server:wunaozai.cnblogs.com\r\n"); send(cli_fd, buf, strlen(buf), 0); sprintf(buf, "Content-Type: text/html\r\n"); send(cli_fd, buf, strlen(buf), 0); sprintf(buf, "\r\n"); send(cli_fd, buf, strlen(buf), 0); sprintf(buf, "<HTML><HEAD><TITLE>Hello World\r\n"); send(cli_fd, buf, strlen(buf), 0); sprintf(buf, "</TITLE></HEAD>\r\n"); send(cli_fd, buf, strlen(buf), 0); sprintf(buf, "<BODY><h1>Hello World</h1>\r\n"); send(cli_fd, buf, strlen(buf), 0); sprintf(buf, "</BODY></HTML>\r\n"); send(cli_fd, buf, strlen(buf), 0); } int WebServer::Page_501(int cli_fd) { char buf[1024]; sprintf(buf, "HTTP/1.1 501 Method Not Implemented\r\n"); send(cli_fd, buf, strlen(buf), 0); sprintf(buf, "Server:wunaozai.cnblogs.com"); send(cli_fd, buf, strlen(buf), 0); sprintf(buf, "Content-Type: text/html\r\n"); send(cli_fd, buf, strlen(buf), 0); sprintf(buf, "\r\n"); send(cli_fd, buf, strlen(buf), 0); sprintf(buf, "<HTML><HEAD><TITLE>Method Not Implemented\r\n"); send(cli_fd, buf, strlen(buf), 0); sprintf(buf, "</TITLE></HEAD>\r\n"); send(cli_fd, buf, strlen(buf), 0); sprintf(buf, "<BODY><P>HTTP request method not supported.\r\n"); send(cli_fd, buf, strlen(buf), 0); sprintf(buf, "</BODY></HTML>\r\n"); send(cli_fd, buf, strlen(buf), 0); } WebServer::~WebServer() { } WebServer::WebServer() { }
webserver.cpp
#include "webserver.h" int main(int argc,char **argv) { WebServer ws;//实例化web服务器 ws.ServerInit(8080);//打开8080端口 pid_t pid; int cli_fd; while(1) { cli_fd=ws.ServerAccept();//程序会在这个函数阻塞 ws.ServerRequest(cli_fd);//这个函数会创建一个进程对请求头进行处理并发送应答信息给客户端 } ws.ServerClose();//关闭服务器 return 0; }
makefile
main: g++ webserver.cpp -std=c++0x -g -o webserver run: ./webserver
下面这个是运行时的截图
增加了几个函数get_line(由于socket的读取方式好像没有一行一行的读取)各种Page信息还有一个ServerRequest函数。
ServerRequest:这个函数里面有一个fork函数创建多进程。一开始我是把fork的创建放在主函数的,然后ServerRequest不用fork函数。但是最后会出现一个问题就是,每次在客户端发出请求后服务器一直没有给出应答,客户端浏览器一直处于加载状态,然后强制性终止程序,浏览器才会有反映。不知道原因,弄了很久。一直在想以前写的那篇HTTP是没有问题的。一查才知道原来我以前用的请求头Connection:close 而浏览器现在这个Connection默认的值是keep-alive。是长连接。所以才会出现这个情况。
get_line:由于socket没有一整行的读取数据,所以这里使用tinyhttpd这个程序里的代码。
Page_200 Page_501 Page_404 ... ...
到这里服务器可以简单的返回一个200ok的页面了。接下来要实现的是实现对第一行请求信息的处理,接下来的处理基本都是在ServerRequest这个函数里进行。
带处理get/post方法的WEB服务器
int WebServer::ServerRequest(int cli_fd) { char buf[1024]; int size=1024; int i,j; char method[255];//用于保存请求方式 char url[512]; memset(buf,0,sizeof(buf)); //获取第一行请求信息 一般格式为: GET / HTTP/1.1 // POST / HTTP/1.1 size=get_line(cli_fd,buf,sizeof(buf)); cout<<"\t\t"<<buf<<endl; i=0,j=0; //截取第一个单词 while(!isspace(buf[j]) && (i<sizeof(method)-1)) { method[i]=buf[j]; i++;j++; } method[i]='\0'; //取第一个与第二个单词之间的空格 while(isspace(buf[j]) && (j<sizeof(buf))) j++; //截取第二个单词 i=0; while(!isspace(buf[j]) && (i<sizeof(url)-1) && (j<sizeof(buf))) { url[i]=buf[j]; i++;j++; } url[i]='\0'; if(strcasecmp(method,"GET") && strcasecmp(method,"POST")) { Page_501(cli_fd); return -1; } if(strcasecmp(method,"GET")==0) { cout<<"此次请求的方式是GET方法"<<endl; } else if(strcasecmp(method,"POST")==0) { cout<<"此次请求的方式是POST方法"<<endl; } cout<<"此次请求的地址为:"<<url<<endl; while((size>0)&&strcmp("\n",buf)) { size=get_line(cli_fd,buf,sizeof(buf)); } if(fork()==0) { //处理阶段 //execl("/bin/ls","ls","/home/myuser/",NULL); Page_200(cli_fd); } close(cli_fd); return 0; }
运行的结果
可以看出只要在浏览器地址栏写上什么就可以在GET后截取到,只是中文就显示成16进制了
还有这个成功获取第一个页面后会有一个获取/favicon.ico这个请求,这个是自动的,我没有在地址栏输入的。如果有学过静态页面HTML编写的就知道,这个是网页的图标,一般在主目录的根目录下。
在这里没有看到图标是由于这个favicon.ico不是通过简单text/html的Content-Type显示的所以这里就没有,等以后实现image发送就可以看到了。好了这一小节就到这里了。
参考资料: http://blog.csdn.net/hanchaoman/article/details/5685582
本文地址: /article/6193142.html
相关文章推荐
- Socket网络编程--简单Web服务器(3)
- Socket网络编程--简单Web服务器(6)
- Socket网络编程--简单Web服务器(5)
- Socket网络编程--简单Web服务器(4)
- Socket网络编程--简单Web服务器(1)
- socket编程实验-简单的Web服务器
- Java Socket编程(五) 简单的WEB服务器
- 网络编程:使用Socket实现简单的服务器和客户端的通信
- 读书笔记-最简单的web服务器:网络插座Socket
- 基于Socket编程实现一个简单的Web服务器
- 【网络编程笔记】简单的TCP协议 socket编程(C语言版服务器和客户端)
- 【tcp网络编程】用Socket建立一个简单的文本转换服务器
- Linux网络服务器socket编程
- 【转】【简单Web服务器搭建】基于Socket实现的最简单的Web服务器【ASP.NET原理分析】
- java网络编程一:Socket用法,简单模拟一对一聊天
- 简单的TCP协议 socket编程(C语言版服务器和客户端)
- Linux socket编程-最简单的服务器和客户端程序
- 【简单Web服务器搭建】基于Socket实现的最简单的Web服务器【ASP.NET原理分析】
- Linux网络编程:一个简单的正向代理服务器的实现
- Ubuntu下c语言实现并发服务器简单socket编程实例