上一小节通过阅读开源的Web服务器--tinyhttpd。大概知道了一次交互的请求信息和应答信息的具体过程。接下来我就自己简单的实现一个Web服务器。

  下面这个程序只是实现一个简单的框架出来。这次先实现能够Accept客户端的请求。

  简单创建web服务器

  webserver.h

  1 #include <iostream>
  2 #include <string>
  3 #include <string.h>
  4 #include <stdio.h>
  5 #include <stdlib.h>
  6 #include <errno.h>
  7 #include <sys/types.h>
  8 #include <sys/socket.h>
  9 #include <netinet/in.h>
 10 #include <arpa/inet.h>
 11 #include <unistd.h>
 12 #include <pthread.h>
 13 #include <thread>//使用c++11的多线程
 14
 15 using namespace std;
 16
 17 class WebServer
 18 {
 19     public:
 20         WebServer();
 21         ~WebServer();
 22         int ServerInit(u_short port);
 23         int ServerError(string str);
 24         int ServerAccept();
 25         int ServerClose();
 26         int ServerRequest(int cli_fd);
 27         int get_line(int cli_fd,char * buf,int size);//来自tinyhttpd
 28
 29         int Page_200(int cli_fd);
 30         int Page_501(int cli_fd);
 31     private:
 32         int httpd;
 33 };
 34
 35 int WebServer::ServerRequest(int cli_fd)
 36 {
 37     char buf[1024];
 38     int size=1024;
 39     int i=1;
 40     memset(buf,0,sizeof(buf));
 41     while((i>0)&&strcmp("\n",buf))
 42     {
 43         i=get_line(cli_fd,buf,sizeof(buf));
 44         cout<<buf;
 45     }
 46     if(fork()==0)
 47     {
 48         //处理阶段
 49         execl("/bin/ls","ls","/home/myuser/",NULL);
 50     }
 51     Page_200(cli_fd);
 52     close(cli_fd);
 53     return 0;
 54 }
 55 int WebServer::ServerAccept()
 56 {
 57     struct sockaddr_in cli_sin;
 58     socklen_t cli_len=sizeof(cli_sin);
 59     int cli_fd;
 60     cli_fd=accept(httpd,(struct sockaddr *)&cli_sin,&cli_len);//阻塞等待连接
 61     if(cli_fd==-1)
 62         ServerError("Fail to accept");
 63     cout<<"连接进来的IP: "<<inet_ntoa(cli_sin.sin_addr)<<":"<<ntohs(cli_sin.sin_port)<<endl;
 64     return cli_fd;
 65 }
 66 int WebServer::ServerInit(u_short port)
 67 {
 68     struct sockaddr_in sin;
 69     int on;
 70     httpd=socket(PF_INET,SOCK_STREAM,0);
 71     if(httpd==-1)
 72         ServerError("Fail to Socket");
 73     //init sockaddr_in
 74     sin.sin_family=AF_INET;
 75     sin.sin_port=htons(port);
 76     sin.sin_addr.s_addr=htonl(INADDR_ANY);
 77     bzero(&(sin.sin_zero),8);
 78     setsockopt(httpd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
 79     if(::bind(httpd,(struct sockaddr *)&sin,sizeof(struct sockaddr))==-1)
 80         ServerError("Fail to bind");
 81     //如果port指定为零那么就随机打开一个端口
 82     if(port==0)
 83     {
 84         socklen_t len=sizeof(sin);
 85         if(getsockname(httpd,(struct sockaddr *)&sin,&len)==-1)
 86             ServerError("Fail to getsockname");
 87         port=ntohs(sin.sin_port);
 88     }
 89     if(listen(httpd,100)<0)
 90         ServerError("Fail to listen");
 91     return port;
 92 }
 93 ///
 94 int WebServer::get_line(int cli_fd,char * buf,int size)
 95 {
 96     int i=0;
 97     char c='\0';
 98     int n;
 99     while((i<size-1)&&(c!='\n'))
100     {
101         n=recv(cli_fd,&c,1,0);
102         if(n>0)
103         {
104             if(c=='\r')
105             {
106                 n=recv(cli_fd,&c,1,MSG_PEEK);
107                 if((n>0)&&(c=='\n'))
108                     recv(cli_fd,&c,1,0);
109                 else
110                     c='\n';
111             }
112             buf[i]=c;
113             i++;
114         }
115         else
116             c='\n';
117     }
118     buf[i]='\0';
119     return i;
120 }
121 int WebServer::ServerError(string str)
122 {
123     perror(str.c_str());
124     exit(-1);
125 }
126 int WebServer::ServerClose()
127 {
128     close(httpd);
129     return 0;
130 }
131 int WebServer::Page_200(int cli_fd)
132 {
133     char buf[1024];
134     sprintf(buf, "HTTP/1.1 200 OK\r\n");
135     send(cli_fd, buf, strlen(buf), 0);
136     sprintf(buf, "Server:wunaozai.cnblogs.com\r\n");
137     send(cli_fd, buf, strlen(buf), 0);
138     sprintf(buf, "Content-Type: text/html\r\n");
139     send(cli_fd, buf, strlen(buf), 0);
140     sprintf(buf, "\r\n");
141     send(cli_fd, buf, strlen(buf), 0);
142     sprintf(buf, "<HTML><HEAD><TITLE>Hello World\r\n");
143     send(cli_fd, buf, strlen(buf), 0);
144     sprintf(buf, "</TITLE></HEAD>\r\n");
145     send(cli_fd, buf, strlen(buf), 0);
146     sprintf(buf, "<BODY><h1>Hello World</h1>\r\n");
147     send(cli_fd, buf, strlen(buf), 0);
148     sprintf(buf, "</BODY></HTML>\r\n");
149     send(cli_fd, buf, strlen(buf), 0);
150 }
151 int WebServer::Page_501(int cli_fd)
152 {
153     char buf[1024];
154     sprintf(buf, "HTTP/1.1 501 Method Not Implemented\r\n");
155     send(cli_fd, buf, strlen(buf), 0);
156     sprintf(buf, "Server:wunaozai.cnblogs.com");
157     send(cli_fd, buf, strlen(buf), 0);
158     sprintf(buf, "Content-Type: text/html\r\n");
159     send(cli_fd, buf, strlen(buf), 0);
160     sprintf(buf, "\r\n");
161     send(cli_fd, buf, strlen(buf), 0);
162     sprintf(buf, "<HTML><HEAD><TITLE>Method Not Implemented\r\n");
163     send(cli_fd, buf, strlen(buf), 0);
164     sprintf(buf, "</TITLE></HEAD>\r\n");
165     send(cli_fd, buf, strlen(buf), 0);
166     sprintf(buf, "<BODY><P>HTTP request method not supported.\r\n");
167     send(cli_fd, buf, strlen(buf), 0);
168     sprintf(buf, "</BODY></HTML>\r\n");
169     send(cli_fd, buf, strlen(buf), 0);
170 }
171 WebServer::~WebServer()
172 {
173 }
174 WebServer::WebServer()
175 {
176 }

  webserver.cpp

 1 #include "webserver.h"
 2
 3 int main(int argc,char **argv)
 4 {
 5     WebServer ws;//实例化web服务器
 6     ws.ServerInit(8080);//打开8080端口
 7     pid_t pid;
 8     int cli_fd;
 9     while(1)
10     {
11         cli_fd=ws.ServerAccept();//程序会在这个函数阻塞
12         ws.ServerRequest(cli_fd);//这个函数会创建一个进程对请求头进行处理并发送应答信息给客户端
13     }
14     ws.ServerClose();//关闭服务器
15
16     return 0;
17 }

  makefile

1 main:
2         g++ webserver.cpp -std=c++0x -g -o webserver
3 run:
4         ./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服务器

 1 int WebServer::ServerRequest(int cli_fd)
 2 {
 3     char buf[1024];
 4     int size=1024;
 5     int i,j;
 6     char method[255];//用于保存请求方式
 7     char url[512];
 8     memset(buf,0,sizeof(buf));
 9     //获取第一行请求信息 一般格式为: GET / HTTP/1.1
10     //                               POST / HTTP/1.1
11     size=get_line(cli_fd,buf,sizeof(buf));
12     cout<<"\t\t"<<buf<<endl;
13     i=0,j=0;
14     //截取第一个单词
15     while(!isspace(buf[j]) && (i<sizeof(method)-1))
16     {
17         method[i]=buf[j];
18         i++;j++;
19     }
20     method[i]='\0';
21     //取第一个与第二个单词之间的空格
22     while(isspace(buf[j]) && (j<sizeof(buf)))
23         j++;
24     //截取第二个单词
25     i=0;
26     while(!isspace(buf[j]) && (i<sizeof(url)-1) && (j<sizeof(buf)))
27     {
28         url[i]=buf[j];
29         i++;j++;
30     }
31     url[i]='\0';
32
33     if(strcasecmp(method,"GET") && strcasecmp(method,"POST"))
34     {
35         Page_501(cli_fd);
36         return -1;
37     }
38
39     if(strcasecmp(method,"GET")==0)
40     {
41         cout<<"此次请求的方式是GET方法"<<endl;
42     }
43     else if(strcasecmp(method,"POST")==0)
44     {
45         cout<<"此次请求的方式是POST方法"<<endl;
46     }
47     cout<<"此次请求的地址为:"<<url<<endl;
48
49     while((size>0)&&strcmp("\n",buf))
50     {
51         size=get_line(cli_fd,buf,sizeof(buf));
52     }
53
54     if(fork()==0)
55     {
56         //处理阶段
57         //execl("/bin/ls","ls","/home/myuser/",NULL);
58         Page_200(cli_fd);
59     }
60     close(cli_fd);
61     return 0;
62 }

  运行的结果

  可以看出只要在浏览器地址栏写上什么就可以在GET后截取到,只是中文就显示成16进制了

  还有这个成功获取第一个页面后会有一个获取/favicon.ico这个请求,这个是自动的,我没有在地址栏输入的。如果有学过静态页面HTML编写的就知道,这个是网页的图标,一般在主目录的根目录下。

  在这里没有看到图标是由于这个favicon.ico不是通过简单text/html的Content-Type显示的所以这里就没有,等以后实现image发送就可以看到了。好了这一小节就到这里了。

  参考资料: http://blog.csdn.net/hanchaoman/article/details/5685582

  本文地址: http://www.cnblogs.com/wunaozai/p/3936295.html

转载于:https://www.cnblogs.com/wunaozai/p/3936295.html

Socket网络编程--简单Web服务器(2)相关推荐

  1. Socket网络编程--简单Web服务器(6)

    本来是想实现ssl连接的,但是弄了好久都不成功,就索性不做了,等以后有能力再做了.所以这一小节就是本次的最后一节了.就简单的说几个注意点. 1.加个配置文件 使用单例模式,使用一个类,该类保存一些信息 ...

  2. Socket网络编程--简单Web服务器(3)

    上一小节已经实现了浏览器发送请求,然后服务器给出应答信息,然后浏览器显示出服务器发送过来的网页.一切看起来都是那么的美好.这一小节就准备实现可以根据地址栏url的不同来返回指定的网页.目前还不考虑带参 ...

  3. socket网络编程 java_Java Web 基础(一) 基于TCP的Socket网络编程

    一.Socket简单介绍 Socket通信作为Java网络通讯的基础内容,集中了异常.I/O流模式等众多知识点.学习Socket通信,既能够了解真正的网络通讯原理,也能够增强对I/O流模式的理解. 1 ...

  4. C# Socket网络编程入门(服务器与客户端通信,客户端与客户端通信)

    WebSocket全双工通讯链接,用于前台和后台自由发送信息 一.效果展示: 效果描述: 1.服务器充当管理员,给所有人发送信息,除服务器以外其他人都能接受到. 2.其他用户发送信息除自己以外其他用户 ...

  5. Linux socket网络编程实现FTP服务器

      服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接.在这时如果有个客户端初始化一个Socket,然后连接服务器(conn ...

  6. 网络编程多人聊天c语言,socket网络编程--简单的多人聊天

    //本代码参考于马士兵的代码,做了一些简单的改动,例如获取主机名称好让用户知道那句话是谁发的,Swing方面基本上全改了,关键地方加了我所理解的注释,关键线程方面的代码基本上用马老师的 //服务器端代 ...

  7. Linux C++/Java/Web/OC Socket网络编程

    一,Linux C++ Socket网络编程 1.什么是TCP/IP.UDP? TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制 ...

  8. 视频教程-C++socket网络编程--http服务器(支持php)实战教学视频-C/C++

    C++socket网络编程--http服务器(支持php)实战教学视频 夏曹俊:南京捷帝科技有限公司创始人,南京大学计算机硕士毕业,有15年c++跨平台项目研发的经验,领导开发过大量的c++虚拟仿真, ...

  9. 【Linux】socket网络编程之服务器与客户端的数据交互

    [Linux]socket网络编程之服务器与客户端的数据交互 前言参考 argc !=2是什么意思 inet pton函数 对stdin,stdout 和STDOUT_FILENO,STDIN_FIL ...

最新文章

  1. JVM调优:对象进入老年代的两个条件
  2. TCP、UDP数据包大小的限制
  3. 基于间隔推送全量更新数据状态的设计方法
  4. SpringCloud Greenwich(三)注册中心之zookeeper、Zuul和 gateway网关配置
  5. nextcloud如何填写数据库_NextCloud安装使用心得记录
  6. php实现开关效果代码,JavaScript实现开关效果的代码分享
  7. 20200301:快乐数(leetcode202)
  8. 暴力破解sshd服务的密码的小技巧
  9. mockwebserver java_在Java中使用WireMock和SOAP Web服务
  10. 解决unity3d发布的网页游戏放到服务器上无法使用的问题
  11. dw生日祝福网页制作教程_怎样制作生日祝福网页
  12. 关于DSP数字信号处理技术
  13. mysql语句alter table_sql语句中ALTER TABLE MODIFY和ALTER TABLE CHANGE的区别?
  14. iOS从零开始,使用Swift:探索基础框架
  15. 电脑服务器至强cpu性能排行,至强CPU性能排行榜,至强系列cpu天梯图2020.06
  16. 单片机成长之路(51基础篇) - 023 N76e003 系统时钟切换到外部时钟
  17. 《Game说》| 揭秘百万DAU抖音现象级小游戏背后的故事
  18. 【安全牛学习笔记】Kali Linux基本工具
  19. Typora+PicGo+坚果云搭建个人云笔记系统
  20. 修复Pubwin EP置疑数据库

热门文章

  1. 倒水问题(Java)
  2. Rabbit MQ 学习笔记(3)角色列表
  3. Ubuntu中设置静态IP和DNS
  4. [锋利JQ]-图片提示效果
  5. 作为软件工程师,你必须知道的20个常识
  6. 访问IIS元数据库失败
  7. Visual Basic 9.0 前沿播报·静态篇(一)局部变量类型推测和数组初始化器
  8. java对象关系映射ROM
  9. python简单的web服务器
  10. URAL 1721 Two Sides of the Same Coin(二分图匹配,输出匹配对象)