dc.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /***************************************************************************
  2. * Licensed Materials - Property of IBM
  3. * Copyright IBM Corp. 2013 All rights reserved.
  4. *
  5. * Source filename : dc.c
  6. * Description : Read records from files and send the contain to TO by TTAPI
  7. *
  8. * Parameter :
  9. * 1 start mode: 0- automatic mode, start by crontab; 1- re-run modle;
  10. * 2 DC monitoring target file path;
  11. * 3 DC monitoring target filename;
  12. * 4 servername, on which the program runs
  13. * 5 send log data mode, 1-TTAPI mode 2-Socket mode 3-Mixed mode with TTAPI & Socket
  14. *
  15. * Author : Wang An Nian
  16. *
  17. * Update History
  18. * DATE OWNER DESCRIPTION
  19. * ----------- ------------ -----------
  20. * 2012-11-06 Wang An Nian Generated
  21. * 2013-11-06 Wang An Nian Domestic
  22. * 2014-xx-xx Wang An Nian While list Function added
  23. * 2014-08-18 Wang An Nian MCIS TXN fillter added -p403
  24. * 1 if connect failed then retry socket,if socket send fail then retry socket
  25. * 2 add MCIS white name list filter function
  26. * 3 SIGPIPE ignored
  27. * 4 if monitored file is null, do not exit and wait till life cycle ended
  28. *
  29. * 2014-09-xx Wang An Nian Euro Africa modification
  30. * 5 socket sending for abroad transactions ( have not finished yet)
  31. *
  32. * 2014-12-30 Li Bo Feng Fix problems & Code Formatting
  33. * 1. 调整代码可读性,不改变处理逻辑
  34. * 代码函数分割
  35. * 常量定义,结构定义 dc.h
  36. * 通用函数 dc_code
  37. * 参数处理 dc_args
  38. * 网络直连发送处理 dc_socket
  39. * TT发送处理 dc_ttapi
  40. * 文件缓存处理 dc_file_buffer
  41. * 目标数据处理过程 dc_target
  42. * 主程序 dc.c
  43. * 2. 修改文件监控轮询时间
  44. * 原来检查文件是否存在间隔时间为 2 分钟, 改为 10 秒
  45. * 原来检查文件是否有内容间隔时间为 1 分钟, 改为 10 秒
  46. * 原来检查文件内容是否为当前监控周期内容间隔时间为 1 分钟, 改为 10 秒
  47. * 原来检查文件内容是否有新增内容间隔时间为 5 秒,保持为 5 秒
  48. * 3. 去掉再运行模式 - 从文件尾读取交易流水日志数据
  49. * 因为实际代码已经不支持该模式,参数已经不起作用
  50. * 4. 增加内存释放
  51. * 动态申请的内存,需要释放
  52. *
  53. * 2015-1-6 Li Bo Feng Code structure Formatting & File bufferred reading
  54. * 1. 调整代码结构
  55. * 合并重复代码
  56. * 简化代码逻辑
  57. * 增加函数返回码
  58. * 2. 增加扫描内容控制方式,依据
  59. * 方便测试期间回放旧数据,配置依据环境变量
  60. * SCAN_BEGIN_TIME=1970-1-1 00:00:00
  61. * SCAN_END_TIME=1970-1-1 00:00:00
  62. * 根据起始时间点、结束时间点、数据时间、当前时间决定数据是否发送
  63. * 根据数据交易码白名单决定数据发送目标
  64. * 3. 增加数据回放时间同步功能
  65. * 回放旧数据时,保持数据扫描周期与数据时间一致,精确到 DATA_SCAN_INTERVAL_SECONDS = 10 秒
  66. * 4. 增加文件缓存功能
  67. * 增加 FileBuffer 基础功能
  68. * 一次读入整块内容
  69. * 5. 增加文件变更重读功能
  70. * 文件内容发生变化(非追加变化,内容修改或减少),重新读取文件内容
  71. * 6. 增加文件内容校验功能
  72. * 每次读取内容时,重复读取部分上次缓存内容,比较两次读取内容的重叠区域,以此判定文件内容是否改变
  73. * 7. 增加文件定时刷新功能
  74. * 回放旧数据,系统处于等待数据周期时,及时发现数据变化
  75. *
  76. * 2015-1-13 Li Bo Feng new function & Performance Optimizing
  77. * 1. 增加 Socket 发送心跳功能
  78. * 心跳间隔 NETWORK_IDLE_HEARTBEAT_SECONDS = 10 秒
  79. * 2. 调整程序日志输出内容
  80. * 增加可读性
  81. * 增加日志分类输出: Error Metrics State Detail Flow
  82. * 3. 增加处理状态控制
  83. * 用状态控制取代逻辑控制,简化数据处理逻辑
  84. *
  85. * 2015-1-15 Li Bo Feng new function & Performance Optimizing
  86. * 1. 数据扫描性能优化
  87. * 运行参数集中管理功能
  88. * 通过 key-value Mapping 结构存储配置信息
  89. * 提高白名单及编码转换匹配效率
  90. *
  91. * 2015-1-26 Li Bo Feng
  92. * 1. 调整启动参数
  93. * 第5个启动参数 send_mode, 形式改为下列各参数的16进制数值组合
  94. * 1000 SEND_MODE_ABROAD_SOCKET
  95. * 0100 SEND_MODE_DOMESTIC_SOCKET
  96. * 0010 SEND_MODE_ABROAD_TTAPI
  97. * 0001 SEND_MODE_DOMESTIC_TTAPI
  98. * 对应的服务器(地址:端口)设置关键字改为
  99. * SOCKET_ABROAD_SERVER="地址:端口"
  100. * SOCKET_DOMESTIC_SERVER="地址:端口"
  101. * TTAPI_ABROAD_SERVER="tcp:地址:端口"
  102. * TTAPI_DOMESTIC_SERVER="tcp:地址:端口"
  103. * 2. 功能调整
  104. * 根据配置, 可同时发送 国内/海内 Socket/TTAPI
  105. *
  106. * 2015-2-2 Li Bo Feng
  107. * 1. 增加TTAPI输出字段内容
  108. * ChannelID (Added Field) Channel and its transaction id information, only have this when it's the first hop
  109. * ReturnCode (Added Field) Return code in the application log
  110. * TragetSystem (Added Field) ComponentName(aka. system name) of the target system, only have this for data timetype 02 and 03
  111. * 2. 调整To Socket Server输出字段内容
  112. * TragetTxnID (Added Field) 有目标交易码的系统,在LinkSys后增加","分割的目标交易码
  113. *
  114. *
  115. * 2015-2-10 Li Bo Feng
  116. * 1. 增加调试环境
  117. * windows-cygwin 环境下可编译执行
  118. *
  119. * 2015-3-4 Li Bo Feng
  120. * 1. DC运行日志文件输出
  121. * 原日志输出不能以日期时间分割输出,影响实现程序常驻
  122. * 按指定时间模式分隔,
  123. * 根据当前时间,修正参数给定的文件名中的时间标记 [YYYY] [MM] [DD] [HH] [MI]
  124. * 按指定周期删除旧文件
  125. * 为提高效率进程间需同步删除旧文件
  126. * 2. 文件名时间模式转换功能
  127. * 根据当前时间,修正参数给定的文件名中的时间标记 [YYYY] [MM] [DD] [HH] [MI]
  128. *
  129. * 2015-3-5 Li Bo Feng
  130. * 1. 取消环境变量设置 FILESWITCHMODE
  131. * 以时间模式文件名取代
  132. * 2. 增加环境变量设置 IDLE_TIMEOUT_HOURS
  133. * 空闲超时
  134. *
  135. * 2015-3-10 Li Bo Feng
  136. * 1. 互斥运行逻辑
  137. * 保留原来的定时启动,以系统防止意外终止
  138. * 如果启动时发现指定日志文件已经有DC进程在处理,立即结束当前进程
  139. * 2. 执行效率优化
  140. * 测试机运行 平均CPU占比 0.1% 以下,内存占用 10MB 以下
  141. *
  142. * 2015-3-16 Li Bo Feng
  143. * 1. 时间偏移量修正
  144. * 通过环境变量设定虚拟当前时间 virtual_current_time
  145. * VIRTUAL_TIME=缺省为当前时间`date +"%Y-%m-%d %H:%M:%S"`
  146. * 文件名中的时间与当前时间的偏移量修正,用于目标交易日志文件名及DC运行日志文件名的定时更换
  147. * 目标交易日志数据时间与当前时间的偏移量修正,用于目标交易日志回放/测试中,同步数据扫描周期
  148. * 2. 修正文件名模式转换功能
  149. * 根据虚拟当前时间,修正参数给定的文件名中的时间标记 [YYYY] [MM] [DD] [HH] [MI]
  150. * 根据系统当前时间,修正参数给定的文件名中的时间标记 [yyyy] [mm] [dd] [hh] [mi]
  151. * 根据当前进程ID,修正参数给定的文件名中的PID标记 [pid] [PID]
  152. *
  153. * 2015-3-17 Li Bo Feng
  154. * 1. 调整启动参数
  155. * 合并参数 file_path 和 file_name,以便于进程查询处理
  156. * 2. 调整启动参数
  157. * 参数 send_mode, 形式改为下列各参数的标记字符组合,以增加可读性,如:AS|DS
  158. * AS SEND_MODE_ABROAD_SOCKET
  159. * DS SEND_MODE_DOMESTIC_SOCKET
  160. * AT SEND_MODE_ABROAD_TTAPI
  161. * DT SEND_MODE_DOMESTIC_TTAPI
  162. * 对应的服务器(地址:端口)设置在config.map文件中配置,根据业务需求调整配置关键字如下:
  163. * socket.server.abroad.NFXS=地址:端口
  164. * socket.server.abroad.BOCNET=地址:端口
  165. * socket.server.domestic.BOCNET=地址:端口
  166. * ttapi.server.abroad=tcp:地址:端口
  167. * ttapi.server.domestic=tcp:地址:端口
  168. *
  169. * 2015-3-19 Li Bo Feng
  170. * 1. 增加按时间同步扫描功能
  171. * 扫描数据的时间与虚拟当前时间同步
  172. * SCAN_DATA_BY_TIME=default 1 :scan data by virtual time / 0 :scan data from top of file and immediately begin.
  173. *
  174. * 2015-3-25
  175. * 1. 持续运行测试
  176. * date etime cputime rss
  177. * 2015-3-23 3-01:33:10 00:00:24 1952
  178. * 2015-3-25 5-03:38:34 00:00:40 1952
  179. * 2015-3-26 6-05:36:11 00:00:48 1952
  180. * 2015-3-30 10-07:39:12 00:01:20 1952
  181. *
  182. *
  183. * 2015-3-30 Li Bo Feng
  184. * 1. 调整参数,增加运行参数 SysName,AppName,ServerName,InstanceName
  185. * 解锁与文件名的关联,避免每个系统的规则不一样导致的程序硬代码
  186. *
  187. *
  188. * 2015-4-6 Li Bo Feng
  189. * 1. Fix内存泄露问题
  190. * 删除旧日志时,扫描目录功能(scandir)导致内存泄露
  191. * 重写,改用readdir功能扫描目录.
  192. * 2. 压力测试
  193. * 同时开启36进程,持续运行5天,系统状态正常
  194. * 3. 修改amake脚本,同时打包三个版本: 测试,演练,生产.
  195. * 4. 修改dc.sh启动脚本,根据task.lst自动选择不同运行环境参数
  196. * task.lst中可同时配置所有环境的运行参数
  197. *
  198. * 2015-4-16 Li Bo Feng
  199. * 1. 发布版本 3.0
  200. *
  201. *
  202. * 2015-5-8 Li Bo Feng
  203. * 1. 应用交易日志输出一次写盘信息不完整,导致不能完整读取一行日志记录
  204. * 需要在读取记录不完整(没有换行符)的情况下,需要等待数据完整后,再进行数据解析
  205. * 2. 等待数据完整中,如果发现新交易日志文件已经产生,则直接解析最后的不完整记录,并放弃等待
  206. * 等待时间 15 ~ 20秒 =
  207. * 数据文件再刷新间隔 TIMEOUT_REFRESH_FILE_BUFFER_SECONDS 5秒
  208. * 等待文件变更间隔 WAIT_FOR_FILE_CHANGE_SECONDS 10秒
  209. * 数据扫描间隔 DATA_SCAN_INTL_SECONDS 5秒
  210. *
  211. * 2015-5-11 Li Bo Feng
  212. * 1. 发布版本 3.1
  213. *
  214. * 2015-9-2 Li Bo Feng
  215. * 1. 增加程序注释信息
  216. * 2. 调整程序格式
  217. *
  218. * 2015-11-23 Li Bo Feng
  219. * 1. 修正叠加数据的容错处理
  220. * 当文件切换时,读取到的内容可能发生错乱
  221. * 增加更严格的记录数据格式判断,包括:
  222. * 记录时间格式判断
  223. * 记录重叠判断
  224. * 2. 增加缺省程序日志的输出
  225. * 缺省输出告警信息:
  226. * 忽略的记录
  227. * 等待数据状态
  228. * 3. 发布版本 3.2
  229. *
  230. ***************************************************************************/
  231. /*
  232. * 环境变量说明:
  233. * VIRTUAL_TIME
  234. * 虚拟当前时间,用于确定虚拟当前时间和系统当前时间的时间偏移,缺省值与系统当前时间一致
  235. *
  236. * SCAN_BEGIN_TIME
  237. * 扫描数据开始时间点,格式为yyyy-mm-dd hh:mi:ss,缺省空表示从虚拟当前时间开始扫描数据
  238. * SCAN_END_TIME
  239. * 扫描数据结束时间点,格式为yyyy-mm-dd hh:mi:ss,缺省空表示不限制结束时间
  240. * IDLE_TIMEOUT_HOURS
  241. * 空闲超时(小时数),待处理数据没有任何变化,导致空闲超时,程序自动退出,缺省为0表示不设置空闲超时
  242. *
  243. * TXNCDFILE
  244. * 交易码白名单配置文件
  245. * TXNFILE
  246. * 交易码/交易名称映射配置文件
  247. * RTNCDFILE
  248. * 交易返回码配置文件
  249. * FSYSMATCH
  250. * 应用系统别名配置文件
  251. * CONFIG_FILE
  252. * mapping样式的通用配置文件
  253. * 渠道信息配置
  254. * channel.BOCNET=BOCNET
  255. * 数据接收服务器地址端口
  256. * socket.server.domestic.BOCNET=127.0.0.1:5001
  257. * socket.server.abroad.BOCNET=127.0.0.1:5001
  258. * socket.server.abroad.NFXS=127.0.0.1:5005
  259. * ttapi.server.domestic=tcp:127.0.0.1:5455
  260. * ttapi.server.abroad=tcp:127.0.0.1:5455
  261. *
  262. * ABLOG_KEEP_HOURS
  263. * 本程序(DC)运行日志保留时间,缺省120小时(5天)
  264. * ABLOG_STDOUT
  265. * 是否输出到标准输出,0 不输出, 缺省为 1 输出
  266. * ABLOG_FILE
  267. * 本程序(DC)运行日志输出文件
  268. * 如果不指定输出文件,日志信息会输出到标准输出(忽略ABLOG_STDOUT指定)
  269. * 文件名支持时间模式替换,自动修正参数给定的文件名中的替换标记
  270. * 模式中可以替换内容包括:
  271. * [PID] 用当前进程id
  272. * [YYYY] 虚拟当前时间的年
  273. * [yyyy] 系统当前时间的年
  274. * [MM] 虚拟当前时间的月
  275. * [mm] 系统当前时间的月
  276. * [DD] 虚拟当前时间的日
  277. * [dd] 系统当前时间的日
  278. * [HH] 虚拟当前时间的时
  279. * [hh] 系统当前时间的时
  280. * [MI] 虚拟当前时间的分
  281. * [mi] 系统当前时间的分
  282. * ABLOG_CLASS
  283. * 本程序(DC)运行日志输出内容,由下列标识文字用逗号分隔组合而成,如"Error,Metrics"
  284. * All 缺省,全部信息
  285. * Error 程序运行错误信息
  286. * Metrics 程序运行过程重要提示信息
  287. * State 程序运行状态提示信息
  288. * Detail 程序运行详细信息
  289. * Flow 程序运行流程
  290. * Flow_Public 公共的程序运行流程
  291. * Flow_Private 私有的程序运行流程
  292. * Flow_Restricted 受限的程序运行流程
  293. * Flow_Minor 次要的程序运行流程
  294. *
  295. * SCAN_DATA_BY_TIME
  296. * =default 1 :scan data by virtual time / 0 :scan data from top of file and immediately begin.
  297. *
  298. * VALIDATE_DATA
  299. * 是否验证数据,0 不验证,缺省 1 验证
  300. * CHECK_FILE_STATUS
  301. * 检查文件状态
  302. * 读文件前,是否检查文件非追加变更状态(删除,改名,裁减,重写,修改),
  303. * 缺省0不检查,缓存数据使用完后,继续读取文件内容过程中,才会发现文件非追加变更(删除,裁减,重写,修改),改名不影响数据继续读取
  304. * 1检查,检查到文件发生非追加变更立即重读,放弃缓存中的数据,测试或回放旧数据时可以通过此设置
  305. *
  306. */
  307. /*
  308. * 数据扫描周期设定方式:
  309. * 开始条件:
  310. * 1. 从指定数据时间点开始发送
  311. * SCAN_BEGIN_TIME=yyyy-MM-dd HH:mm:ss
  312. * SCAN_BEGIN_TIME=0 //不限开始时间,从文件头开始
  313. *
  314. * 处理频率/周期:
  315. * 1. 按分钟对应数据发生速率,精确到 5 秒
  316. *
  317. * 结束条件:
  318. * 1. 到达指定数据时间点结束
  319. * SCAN_END_TIME=yyyy-MM-dd HH:mm:ss
  320. * SCAN_END_TIME=0 //持续运行,程序不会退出
  321. * 2. 空闲超时(小时)
  322. * IDLE_TIMEOUT_HOURS=0 // 待处理数据没有任何变化,导致空闲超时,程序自动退出
  323. *
  324. */
  325. #include "dc.h"
  326. #include "dc_code.h"
  327. #include "dc_args.h"
  328. #include "dc_socket.h"
  329. #include "dc_ttapi.h"
  330. #include "dc_target.h"
  331. #include "ab_map.h"
  332. /*------------------------------------------------------------------------
  333. * MAIN()
  334. *
  335. * 运行参数说明:
  336. * scan_from_new
  337. * 第1个参数,是否只扫描新增内容, 0 从头开始扫描数据, 1从文件尾开始扫描新产生的数据
  338. * 在打开文件时就已经确定,读取位置,优先级很高,但只有刚开始时起作用,文件切换或重读时,此参数将失去意义.
  339. * log_file_path
  340. * 第2个参数,目标日志文件路径,文件名支持模式替换
  341. * 模式中可以替换内容包括:
  342. * [PID] 用当前进程id
  343. * [YYYY] 虚拟当前时间的年
  344. * [yyyy] 系统当前时间的年
  345. * [MM] 虚拟当前时间的月
  346. * [mm] 系统当前时间的月
  347. * [DD] 虚拟当前时间的日
  348. * [dd] 系统当前时间的日
  349. * [HH] 虚拟当前时间的时
  350. * [hh] 系统当前时间的时
  351. * [MI] 虚拟当前时间的分
  352. * [mi] 系统当前时间的分
  353. * sys_name
  354. * 第3个参数,系统名称
  355. * app_name
  356. * 第4个参数,应用名称
  357. * server_name
  358. * 第5个参数,应用服务器名称
  359. * istance_name
  360. * 第6个参数,实例名称
  361. * send_mode
  362. * 第7个参数,数据发送模式,下列各参数的标记字符组合,如:AS|DS
  363. * AS SEND_MODE_ABROAD_SOCKET
  364. * DS SEND_MODE_DOMESTIC_SOCKET
  365. * AT SEND_MODE_ABROAD_TTAPI
  366. * DT SEND_MODE_DOMESTIC_TTAPI
  367. *
  368. * RTN:
  369. * others - reference to return code
  370. *
  371. *------------------------------------------------------------------------*/
  372. int main(int argc, char *argv[])
  373. {
  374. ABLOG_Entry(Public, main);
  375. DEFINE_DC_RETURN_CODE();
  376. int iRtn;
  377. // 防止因网络异常导致程序退出
  378. // 当服务器close一个连接时,若client端接着发数据。根据TCP 协议的规定,会收到一个RST响应,
  379. // client再往这个服务器发送数据时,系统会发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开了,不要再写了。
  380. // 根据信号的默认处理规则SIGPIPE信号的默认执行动作是terminate(终止、退出),所以client会退出。
  381. // 若不想客户端退出可以把SIGPIPE设为SIG_IGN
  382. // 这时SIGPIPE交给了系统处理。
  383. // 服务器采用了fork的话,要收集垃圾进程,防止僵尸进程的产生,可以这样处理:
  384. // signal(SIGCHLD,SIG_IGN); 交给系统init去回收。
  385. // 这里子进程就不会产生僵尸进程了。
  386. signal(SIGPIPE, SIG_IGN);
  387. // 收集验证启动参数
  388. iRtn = check_args(argc, argv);
  389. if (iRtn == DC_RET_OK)
  390. {
  391. ABLOG_Printf(Metrics,
  392. (ABLOG,"[I] <---------------------------------------------------------------->"));
  393. ABLOG_Printf(Metrics,
  394. (ABLOG,"[I] <------------------------ Log DC Started ------------------------>"));
  395. ABLOG_Printf(Metrics,
  396. (ABLOG,"[I] <---------------------------------------------------------------->"));
  397. // 程序日志文件变更时,打印程序运行参数信息
  398. on_ablog_reinitialized = print_args;
  399. // DC处理主过程
  400. iRtn = main_process();
  401. ABLOG_Printf(Metrics,
  402. (ABLOG,"[I] <------------------------- Log DC end -------------------------->"));
  403. }
  404. // 清理启动参数使用的资源
  405. clear_args();
  406. // 清理ab_code 使用的资源
  407. clear_coding();
  408. // 数据超时退出属于正常退出
  409. ABLOG_Return_Code(iRtn == DC_RET_TIMEOUT_QUIT?DC_RET_OK:iRtn);
  410. }