文章目录
在前面的步骤中,已经模拟生成了气象站点的气象观测数据,这个就相当于模拟了服务端的数据源(产生气象观测数据)。
接下来要完成的就是,从服务端那里将观测数据采集回来,用的方法就是利用ftp从服务端下载数据。现在就是要设计一个ftp采集模块,从服务端采集数据。
一、ftp 下载服务器数据的流程
在设计 ftp 采集模块之前,先来回顾一下利用ftp从服务端下载数据的大致过程。
(1)登录 ftp 服务器,用户名和密码
(2)选择主动模式或者被动模式,一般是被动模式
(3)找到要下载数据的路径,也就是要切换服务器的工作目录
(4)切换了工作目录,如果有多种数据类型,匹配自己要找的数据类型,比如说我要下载 .txt 类型,就匹配 .txt 类型文件
(5)执行下载命令下载自己想要的数据
(6)指定存放数据的本地目的
(7)检查是否下载成功
二、设计 ftp 采集数据模块
1.设计采集模块的参数
只要是使用ftp协议从服务器获取数据,上面的流程是肯定要执行的,现在就来设计这个模块。
综上,这个模块的参数应该有:
(1)程序运行要记录日志文件
我们可能要利用 ftp 采集模块采集多种数据,现在是采集气象观测数据,所以命名为:
/oracle/qxidc/log/ftpgetfile_surfdata.log
(2)服务器的IP、端口、用户名、密码(要登录ftp服务器)
登录 ftp 服务器要知道 IP地址指定端口,现在把 IP地址和端口(被动模式一般选择21端口)放在一起作为一个参数:
参数名为:host
用户名参数为:username
密码参数为:password
(3)传输模式,pasv和port,可选字段,缺省采用pasv模式。(一般选择被动模式)
传输模式参数名为:mode,传输模式有主被动模式,定义了两个宏,主动模式为 2,被动模式为 1.
(4)本地文件存放的目录。(采集回来的文件放在哪里)
采集回来气象数据放在 /oracle/qxidc/data/surfdata 中,参数名为 :localpath。
(5)远程服务器存放文件的目录。(要采集的文件放在服务器的什么位置)
参数名为:remotepath。数据源是自拟的,之前把模拟生成气象观测数据放在 /oracle/qxidc/data/ftp/surfdata 下,现在去那个目录获取数据即可。
(6)文件采集成功后,远程服务器文件的处理方式:1-什么也不做;2-删除;3-备份,如果为3,还要指定备份的目录。
备份目录是在服务端的,参数名为:remotepathbak,现在设置为:/oracle/qxidc/data/ftp/surdatabak
(7)实现文件的增量采集。已经取过的文件不用再取。缓解网络的压力。
要实现增量采集,要知道哪些文件要采集,哪些文件已经采集回来了。所以在本地还要有这两个文件。
要采集的文件名放在本地的 /oracle/qxidc/list 目录,文件名为:ftpgetfile_surfdata.list 。参数名为:listfilename
已经采集的文件的文件名放在本地的 /oracle/qxidc/list/ftpgetfile_surfdata.xml。参数名为 okfilename
(8)待采集文件匹配的文件名,不匹配的文件不会被采集,本字段尽可能设置精确,不允许用* 匹配全部的文件。(筛选文件)
当服务器中有多种文件时,要能获取指定的文件类型,这个参数名为:matchname
2.处理采集模块的参数
虽然设计了上面的参数,但是会出现一个问题就是参数很多,在调试程序的时候,或者程序中要使用这些参数 argv[i],里面的i的取值就很多,不方便程序的使用。
现在采用将一些参数合并成一个 XML参数(如下图所示),这样总体上减少了模块的参数数量,总体上看只有3个参数。
所以以后遇到参数多的程序,可以采用这种方法。
将一些参数合并了之后,只要利用XML解析函数将这些参数解析出来,就能很方便地使用。
3.设计模块的函数
3.1 模块名称
这个模块是 利用 ftp 从服务器获取文件,所以这个模块就叫做 ftpgetfile
3.2 提示程序
一般程序的提示信息是放在 main 函数中,但是这个模块的提示信息太长了,把它在 main 函数中,会让 main 显得冗长,所以现在把提示信息分离出去。
提示信息一般包括程序所要的参数,如何使用。
函数名为:_help
参数:这个程序是提示使用者如何使用这个的,所以会使用到模块的(上文说的)那些参数。所以 _help 函数的参数为,模块的参数的地址。
返回值:这个函数的作用是用来提示的,可以不用返回值 void
4.设计XML参数解析函数
因为把ftp文件传输的参数合并成一个XML的字符串,要使用里面的参数,需要将参数解析出来
4.1 函数的参数
4.1.1 设计函数
要解析XML字符串参数,要将XML 字符串给解析函数,所以解析函数的参数就是来接收XML字符串。
返回值:bool
函数名:_xmltoarg ,xml解析到参数
bool _xmltoarg(char *strxmlbuffer);
4.1.2 具体实现
(1)因为把ftp文件传输的参数合并成一个XML的字符串,要使用里面的参数,要将参数解析出来。解析出来了放在一个ftp参数结构体中,声明一个结构体,这个结构体的成员变量有可能有多个子程序要使用,所以结构体声明成全局变量
struct st_arg
{
char host[51];
int mode;
char username[31];
char password[31];
char localpath[301];
char remotepath[301];
char matchname[301];
int ptype;
char remotepathbak[301];
char listfilename[301];
char okfilename[301];
} starg;
(2)函数代码
bool _xmltoarg(char *strxmlbuffer)
{
// (1)初始化存放解析出来的参数结构体
memset(&starg,0,sizeof(struct st_arg));
// (2)将 xml 解析出来,并且存放到starg 结构体
GetXMLBuffer(strxmlbuffer,"host",starg.host);
GetXMLBuffer(strxmlbuffer,"mode",&starg.mode);
if ( ( starg.mode != 1 ) && ( starg.mode != 2 ) ) starg.mode = 1;
GetXMLBuffer(strxmlbuffer,"username",starg.username);
GetXMLBuffer(strxmlbuffer,"password",starg.password);
GetXMLBuffer(strxmlbuffer,"localpath",starg.localpath);
GetXMLBuffer(strxmlbuffer,"remotepath",starg.remotepath);
GetXMLBuffer(strxmlbuffer,"listfilename",starg.listfilename);
GetXMLBuffer(strxmlbuffer,"okfilename",starg.okfilename);
return true;
}
4.2 函数解析效果
用gdb调试,在断点设置在解析函数,将结构体的成员变量显示,解析正确。
5.设计模块的业务流程主程序
上面的步骤把所需的参数都解析出来了,接下就是使用这些参数去完成 ftp 文件传输。ftp 文件传输的大致步骤已经在上面陈述过,会发现有很多步骤的。如果每一个步骤设计一个函数去处理,把他们都放在main函数中,就会显得不简洁。
所以可以把 ftp文件传输所涉及的一些步骤函数,放在一个业务流程主函数里面,由业务流程主函数去调用步骤函数,再由main 函数调用业务流程主函数,这样就会很简洁。
现在就来设计这个业务流程主函数:
(1)函数名:
_ftpgetfile——ftp获取文件
(2)函数的参数:
这个函数就是文件传输的过程,要使用的变量就是 参数结构体里面的参数,由于之前是把参数结构体定义为全局变量,所以目前这个函数不用传参。
(3)函数返回值:
bool,成功或失败
5.1 登录ftp 服务器
//3.1 ftp 文件传输的第一步登录,ftp服务器
// 登录ftp 服务器需要的参数:IP地址和端口号,用户名和密码,指定模式
int mode;
if ( starg.mode == 1 ) mode = FTPLIB_PASSIVE; // 被动模式
if ( starg.mode == 2 ) mode = FTPLIB_PORT; // 主动模式
if ( ftp.login(starg.host,starg.username,starg.password,mode) == false )
{
logfile.Write("ftp.login(%s,%s,%s,%d)failed.\n",starg.host,starg.username,\
starg.password,mode);
return false;
}
logfile.Write("ftp.login 成功。\n");
5.2 切换工作目录
登录了服务器之后,要获取文件,先切换到要获取的文件所在目录
if ( ftp.chdir(starg.remotepath) == false )
{
logfile.Write("ftp.chd