温情晴雨表(项目)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37964547/article/details/81569992

一、项目简介

该项目主要是利用服务器暴露出来的外部接口,用户通过访问浏览器进行信息注册或者登录,注册成功之后,用户可以通过浏览器添加好友列表,再由服务器将这些信息保存到远端数据库中。服务器每天定时爬取全国天气信息并以邮件的形式发送给用户的所有好友的过程。
一张图解释整个项目实现过程:
这里写图片描述
通过这张图我们可以看出,温情晴雨表这个项目主要实现有以下几个部分:

  • HTTP/1.0服务器的搭建
  • 处理参数的CGI编程技术
  • 连接数据库并保存用户注册信息
  • 利用Python语言编写脚本爬取全国的实时天气信息并保存到数据库中
  • 根据城市对应关系向好友发送所在城市天气信息
    接下来我们一起分析各个模块的具体实现过程:

二、项目实现过程

1、HTTP/1.0 服务器的搭建

搭建一个单进程,多线程的服务器,为了更好地理解HTTP服务器程序,我们需要先了解以下几个方面的知识:
(1)实现HTTP服务器的基础知识
(2)模式处理(主要是CGI模式)
(3)http多线程方法的工作流程
(4)具体代码设计

(1)http基础知识了解

在学习编写http服务器之前我们首先要了解http协议,http协议是hypertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据的过程。客户端连上web服务器后,若想获得web服务器中的某个web资源,需遵守一定的通讯格式,HTTP协议用于定义客户端与web服务器通迅的格式。
为了更加深入理解http协议的相关知识,可以参考下面这篇博客:
http://www.cnblogs.com/EricaMIN1987_IT/p/3837436.html
内容讲解的很细,可以好好看看。

(2)CGI机制和CGI程序

CGI机制:
通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口。

通过CGI接口,Web服务器就能够获取客户端提交的信息,转交给服务器端的CGI程序进行处理,最后返回结果给客户端。

一个简单的例子帮助我们理解CGI模式

在我们使用的聊天软件QQ上有这样一个功能,我们可以去到好友的主页,进入留言板模块给好友留言:当用户在客户端编写一些文字或者添加一些图片之类的东西,然后点击“发表”按钮(这部分之前的所有动作都在客户端实现),然后浏览器把这些信息传送给服务器的CGI目录下指定的CGI程序中,然后CGI程序按照服务器上预定的方法进行处理。
在本例中就是把用户提交的信息存入指定的文件中。然后CGI程序给客户端发送一个信息,表示请求的任务已经结束。此时用户在浏览器里将看到“留言结束”的字样。整个过程结束。

CGI程序:
(1)、CGI程序就是基于CGI标准所编写的程序,CGI程序必须按照CGI接口规范来写。

(2)、CGI 程序用来处理客户端提交的数据,比如做math,插入数据库等。

(3)、CGI程序可以用各种主流语言编写,比如:C语言,Java,PHP等。

CGI运行流程:

(1)、用户在浏览器表单内输入数据并提交。

(2)、浏览器通过Internet把用户数据送到服务器端触发一个请求。

(3)、服务器接收用户请求,激活CGI程序并为该CGI程序设置一些传递信息所需的环境变量。

(4)、CGI程序获取服务器传递过来的数据进行处理并把处理结果反馈给服务器。

(5)、服务器把结果传递到客户端浏览器。

(6)、Web服务喊叫中断和客户端浏览器的连接。

(7)、Web浏览器将CGI程序的输出显示在浏览器的窗体上。

CGI编程的特点:

CGI是HTTP服务器与你的或其它机器上的程序进行“交谈”的一种工具,其程序须运行在网络服务器上,主要有以下特点:

(1)、CGI程序获取信息和输出信息的方式和普通程序不一样。在编写CGI程序前,你必须了解Web页面中的超文本链接或表单中的数据是如何被传递给CGI程序的,在设计CGI时首先要设计好Web页面上的客户端界面,并需要你对数据传递的两种方法(POST/GET)及其优点有所了解。

(2)、CGI程序必须考虑程序运行时的安全性。因为我们的CGI程序是准备放在Web服务器上供大家使用的,很多人在使用这个程序,这样就会导致一些软件工作者查找出安全漏洞并对我们的系统进行攻击,我们唯一能做的就是在CGI程序中消除这些漏洞。

(3)、CGI程序工作在无状态的运行环境中,这种无状态的运行环境有两个特征: a、不提供永久的上下文信息,即在会话连接期间不保存上下文信息;
b、系统可能会拥有同一个CGI程序的多个进程,这样一旦Web服务器响应了客户端一个运行CGI程序 的请求,运行结束后连接立刻被切断,当新的请求到来时会重建连接,并且上一次连接的状态信息彻底清除。

(3)模式处理

根据请求方法和传参情况根据主要分为两个模式:
非CGI模式:
非CGI模式就很简单了,服务器直接返回浏览器的资源就好了

CGI模式:
因为我要实现的http暂且只支持GET/POST请求方法,所以就有以下两种情况会运行CGI程序:

  • GET方法带参数
  • POST 方法

下面我们通过一张web框架图来理解一下CGI模式的运行流程:
这里写图片描述
在上图中,我们可以看到CGI程序是在web框架下运行,此时浏览器就相当于CGI程序的输入端和输出终端

在这里很重要的一点就是解决父子进程间通信的问题,在这里我们使用管道的方式实现,因此我们创建出入管道和输出管道:input[2]和output[2];
对于父进程:

父进程主要是将socket中的内容写出来,所以要关闭读端,close(input[0])
将结果输出到浏览器端,所以需要关闭写端,close(output[1])

对于子进程:

close(input[1]):子进程要读取父进程写入的数据,所以要关闭写端
close(output[0]):子进程需要将结果返回给父进程,所以关闭读端

当子进程执行完CGI程序后,父进程此时也得到了程序执行的结果,此时,要将管道和标准输入和标准输出联系起来,才能正确返回浏览器想要的结果,所以这里就需要用到输入输出重定向:
主要方法如下:

dup2(input[0],0) //将stdin重定向到input[0]
dup2(output[1],1) //将stdout重定向到output[1]

讲到这里,我们的CGI模式在HTTP服务器中的运行过程就差不多讲完了,还想深入理解的话,可以参考这两本书:

(4)http多线程工作过程

工作流程图如下图所示:
这里写图片描述
需要注意的是:

  • GET方法:参数存放在URL路径中,以’?’开始,‘#’结束,这之间都是参数部分,并且参数之间以‘&’分开;如果带参数,则参数存放在query_string中,没有参数,就返回资源
  • POST方法:POST方法的参数都在请求报文正文中,所以要得到参数部分,我们需要先获得content_length的大小,再根据content_length从正文中读取参数内容,并且以CGI模式运行

总之,带参数的GET方法和POST方法都是以CGI模式运行的。

(5)代码实现

整个服务器搭建采取了B/S(浏览器/服务器)模式,为了实现并发,我们采取了多线程模式。根据浏览器的GET/POST方法,服务器相应回相应的HTML界面:
(1)创建监听套接字
创建步骤:socket—>bind—>listen
(2)accept进行多线程建立
我们使用accept接收客户端的connect请求。

这个过程实际上是对backlog队列的一个操作。
在accept前,内核接收到connect请求首先把socket放入未完成队列,然后accept的时候,需要把socket放入已完成队列当中去,然后accept成功以后从已完成的队列中取出。

accept成功之后,创建线程管理socket

accept成功以后,我们使用pthread_create创建线程,把socket托付给线程来进行操作。
在线程处理的过程中需要线程等待,为了解决这个问题,我们可以使用线程分离,将线程作为孤儿进程托管给1号进程,当执行完毕之后,由1号进程来进行资源的回收。

(3)线程处理过程
线程处理函数中,其实就是对HTTP请求进行分析,通过对其参数的分析进行相应的处理,处理过程从以下几个方面进行:

* GET方法,是否带参数
* POST方法

在处理请求报文的时候,我们是采取按行读取的方式,HTTP的请求报头的第一行由三个字段组成:请求方法、URL、版本号,并且这三个字段间以空格隔开,所以我们可以通过第一行读取获得method和URL。

通过method,我们可以选择执行模式,如果是GET方法,则分析其URL中是否有参数,如果有参数,则执行CGI程序,没有的话,服务器就返回其请求资源即可
如果是POST方法,则执行需要继续读取请求报文,直到读到content_length字段,并获取content_length的值,根据值读取请求正文中的参数,进入CGI程序执行数据。
以上就是关于HTTP搭建的简单总结了。

2、数据库连接

因为需要将一些数据保存到数据库中,所以我们要与本地数据库建立远程连接.
首先要在我们的项目中引入mysql库:mysql.h和mysqlclient库
mysql.h
如果你的linux中已经安装好mysql,就可以按照以下路径进行查找:
这里写图片描述
这里面包含所有的方法声明,为了方便我们使用,我们可以将mysql.h 放到项目文件下,在CGI程序编译中,makefile需要做如下处理:

这里写图片描述
-I (大写的i):告诉我们要从哪里找头文件
-L :告诉我们去哪里找库文件
-l(小写L):指明是静态库还是动态库

3、爬取全国天气

使用scrapy框架,爬取全国的天气,将爬取的结果直接存入到数据库中的weather表中。关于scrapy框架介绍可以参考下面这篇博客
Scrapy抓取框架的介绍 http://www.360doc.com/content/14/0325/22/9482_363730690.shtml

4、天气邮件发送

在天气邮件发送模块,我们需要考虑以下几个问题:
如何获得天气?发送给谁?怎么发送?这几个问题

关于天气获取部分:编写脚本从15tianqi.com这个网站进行爬取天气
我们看一下爬取部分代码:
这里写图片描述
init.py:说明weather是一个目录
items.py:里面定制要爬取的数据
pipelines.py:定制保存数据的方式
settings.py:设置一些爬虫的选项
spiders:说明它是一个目录
因为每天的天气都会改变,所以这个可以设置定时爬取

发送给谁:我们主要是用户将天气邮件发送给该用户的所有好友。根据好友信息表中好友对应的城市发送天气表中相对应的城市的天气。

邮件发送:当好友信息中的城市和天气表中的城市对应之后,fork出一个子进程,让她去执行天气邮件发送的脚本代码。

三、总结

在这个项目的运行过程中,出现了很多问题:
(1)服务器应答时,没有将html格式的页面发送,而是将底层的实现代码展示在浏览器,并且在调试时将本来要打印的调试信息会打印到网页上(在回应空行时将send期望发送的数值写的太大,本来只需要发送两个字节的内容)
解决:先检查代码,思路正确,在容易出现问题的地方加入调试信息,最后将问题定位在echo_www()函数内 ,
(2)当一个用户信息注册页面提交之后,页面就显示出错了,没有显示我们预期的界面,最后通过调试,发现CGI程序那部分逻辑出错了,导致没有进入CGI程序中执行。

猜你喜欢

转载自blog.csdn.net/qq_37964547/article/details/81569992