这里先写下主要的业务代码,一些库代码稍后补充上

/**
* Feed新闻个性化推送
*/ #include "push_service_news.h" /**
* 保证单进程运行
*/
void single_process() {
lock_fd = open("logs/lock", O_CREAT | O_RDWR | O_TRUNC, );
if (push_trylock_fd(lock_fd) == FAILURE) {
push_sys_notice("push_service_news already exists\n");
close(lock_fd);
exit();
} else {
push_sys_notice("push_service_news lock success");
}
} /**
* 线程数据回收函数,单线程结束的时候,系统自动调用
*/
void *push_thread_data_del(void *data) {
if (data) {
free(data);
push_sys_notice("thread data free success");
} else {
push_sys_notice("thread data free fail");
}
} /**
* 初始化
* 连接mysql、线程池、日志打印目录
*/
void init_main(int argc, char **argv) {
a_tpool = push_init_tpool(PUSH_TPOOL_THREAD_COUNT, PUSH_TPOOL_MAX_TASK);
if (!a_tpool) {
push_sys_error("push_init_tpool error");
exit();
}
ThreadData_create(push_thread_data, push_thread_data_del);
} /**
* 获取待执行的任务
*/
void get_task() {
int ret = push_mysql_connect(PUSH_DB_HOST, PUSH_DB_USER, PUSH_DB_PASSWD,
PUSH_DB_PORT, PUSH_DB_DBNAME);
if (ret) {
push_sys_error("mysql_connect error");
exit();
}
ret = push_dao_newstask_getone(&a_newstask);
if (ret == FAILURE) {
push_sys_error("push_dao_newstask_getone error");
exit();
}
if (ret == ) {
push_sys_notice("have no task");
exit();
}
task_id = atol(a_newstask.info[][F_news_task_id]);
if (!task_id) {
push_sys_error("task_id error,:%d", task_id);
exit();
}
ret = push_dao_newstask_update_status(task_id, STATUS_DOING);
if (!ret) {
push_sys_error("update status doing error:%d", task_id);
exit();
}
push_mysql_close();
} /**
* 初始化一些基础路径
*/
void init_path(int platform) {
//重新初始化日志打印目录
char log_path[PUSH_MAXLEN_PATH] = {};
snprintf(log_path, sizeof (log_path), "logs/%u", task_id);
push_init_logger(log_path);
//base_path
snprintf(base_path, sizeof (base_path), "logs/%u/", task_id);
//data_path
snprintf(data_path, sizeof (data_path), "%s%s", base_path, "data/");
char *ptr = platform == PUSH_PLATFORM_ANDROID ? "android" : "iphone";
//cuids_path
snprintf(cuids_path, sizeof (cuids_path), "%s%s_cuids", data_path, ptr);
//bigdata_path
snprintf(bigdata_path, sizeof (bigdata_path), "%s%s_bigdata", data_path, ptr);
//mkdir
push_mkdir(data_path);
push_sys_notice("cuids_path[%s] bigdata_path[%s]", cuids_path, bigdata_path);
/**
* 记录一下task的详细信息
*/
push_sys_notice("task_name[%s]", a_newstask.info[][F_news_task_task_name]);
push_sys_notice("android_cuid_files[%s]", a_newstask.info[][F_news_task_android_cuid_files]);
push_sys_notice("iphone_cuid_files[%s]", a_newstask.info[][F_news_task_iphone_cuid_files]);
push_sys_notice("platform[%s]", a_newstask.info[][F_news_task_platform]); } /**
* 下载Ftp文件
* @notice 此函数中不能使用strtok会造成iPhone只解析一个
* @todo 一篇文章重复推送
* @param src_file
* @param platform
*/
void download_files(char *src_file) {
char *ptr = NULL, *save_ptr = NULL;
char wget_cmd[PUSH_LEN_256] = {};
char uniq_cmd[PUSH_LEN_256] = {};
ptr = strtok_r(src_file, ",", &save_ptr);
int num = , ret = ;
//下载所有cuid的文件
while (ptr) {
snprintf(wget_cmd, sizeof (wget_cmd), "wget -c -O %s_%d %s >> %swget.log 2>&1", cuids_path, num, ptr, base_path);
push_sys_notice("wget_cmd start");
ret = system(wget_cmd);
push_sys_notice("wget_cmd end:[%s]", wget_cmd);
if (ret) {
push_sys_error("wget file error:[%s] [%s]", strerror(errno), wget_cmd);
}
ptr = strtok_r(NULL, ",", &save_ptr);
num++;
}
/**
* 对文件进行去重
* ① 如果选择的是一个tag则不需要处理了,针对全量用户效果是显著的
*/
if (num <= ) {
snprintf(uniq_cmd, sizeof (uniq_cmd), "cat %s_* > %s", cuids_path, bigdata_path);
} else {
snprintf(uniq_cmd, sizeof (uniq_cmd), "sort %s_* -u -T /home/work/tmp/sort_tmp > %s", cuids_path, bigdata_path);
}
push_sys_notice("uniq_cmd start");
system(uniq_cmd);
push_sys_notice("uniq_cmd end:[%s]", uniq_cmd);
} /**
* 工作线程函数
* @param arg
*/
void worker(void *arg) {
/*-------------------------------qps控制ST---------------------------------*/
push_thread_data_t *thread_data = (push_thread_data_t *) ThreadData_get(push_thread_data);
//第一次初始化
if (!thread_data) {
thread_data = (push_thread_data_t *) calloc(, sizeof (push_thread_data_t));
if (!thread_data) {
push_sys_error("push_thread_data calloc error:%s", strerror(errno));
pthread_exit(NULL);
}
thread_data->count = ;
thread_data->timestamp = push_timestamp();
ThreadData_set(push_thread_data, thread_data);
}
while () {
int now_timestamp = push_timestamp();
if (now_timestamp == thread_data->timestamp) {
//触发了qps限制
if (thread_data->count >= PUSH_EVERY_THREAD_QPS) {
push_sys_notice("qps limit: %d >= %d", thread_data->count, PUSH_EVERY_THREAD_QPS);
usleep();
continue;
} else { //没有触发qps限制
thread_data->count++;
push_sys_notice("qps:%d", thread_data->count);
break;
}
} else { //时间不相等,说明肯定没有触发qps限制
thread_data->count = ;
thread_data->timestamp = now_timestamp;
break;
}
}
/*-------------------------------qps控制SE----------------------------------*/
//工作流程
push_news_worker_param_t *param = (push_news_worker_param_t *) arg;
char *response = push_mapi_news_batch(param->platform, task_id, param->cuids, &a_newstask);
if (!response) {
push_error("response error cuids[%s]", param->cuids);
} else if (strstr(response, "{\"errno\":0")) {
push_notice("send success:response[%s]", response);
} else {
push_error("send fail:response[%s] cuids[%s]", response, param->cuids);
}
free(param);
} /**
* 读取文件,向线程池添加任务
*/
int read_file(int platform) {
FILE *fp = fopen(bigdata_path, "r");
if (!fp) {
push_sys_error("open %s error:%s", bigdata_path, strerror(errno));
return FAILURE;
}
char line_data[PUSH_LEN_256] = {};
char cuid_data[PUSH_LEN_256] = {};
int count;
push_news_worker_param_t *worker_param;
for (count = ; !feof(fp) && fgets(line_data, sizeof (line_data), fp) != NULL; count++) {
if (count % PUSH_ONCE_CUID_COUNT == ) {
worker_param = calloc(, sizeof (push_news_worker_param_t));
if (!worker_param) {
push_sys_error("calloc worker_param error:%s", strerror(errno));
continue;
}
worker_param->platform = platform;
}
sscanf(line_data, "%[^\n]", cuid_data);
strncat(worker_param->cuids, cuid_data, PUSH_MAX_CUID_LEN);
strncat(worker_param->cuids, ",", ); if (count % PUSH_ONCE_CUID_COUNT == (PUSH_ONCE_CUID_COUNT - )) {
if (push_tpool_add_task(a_tpool, worker, worker_param)) {
push_sys_error("bigdata_path[%s] tpool add task error", bigdata_path);
} else {
push_sys_notice("bigdata_path[%s] tpool add task success", bigdata_path);
}
}
}
//不是整数的需要特殊处理的
if ((count % PUSH_ONCE_CUID_COUNT != (PUSH_ONCE_CUID_COUNT - )) && (count % PUSH_ONCE_CUID_COUNT != )) {
if (push_tpool_add_task(a_tpool, worker, worker_param)) {
push_sys_error("bigdata_path[%s] tpool add task error", bigdata_path);
} else {
push_sys_notice("bigdata_path[%s] tpool add task success", bigdata_path);
}
}
fclose(fp);
return count;
} /**
* 更新数据库数据
*/
void update_mysql() {
if (task_id == ) {
return;
}
push_sys_notice("---android_send_count[%d]---", android_send_count);
push_sys_notice("---iphone_send_count[%d]---", iphone_send_count);
int ret = push_mysql_connect(PUSH_DB_HOST, PUSH_DB_USER, PUSH_DB_PASSWD,
PUSH_DB_PORT, PUSH_DB_DBNAME);
if (ret) {
push_sys_error("mysql_connect error");
return;
}
int affect;
affect = push_dao_newstask_update_send_count(task_id, android_send_count, iphone_send_count);
if (!affect) {
push_sys_error("update send_count error");
}
affect = push_dao_newstask_update_status(task_id, STATUS_SUSS);
if (affect > ) {
push_sys_error("update status success, status[%d]", STATUS_SUSS);
}
push_mysql_close();
} /**
* 收尾工作
* 关闭mysql连接、销毁线程池、释放查询结果集
*/
void end_main(void) {
push_tpool_destroy(a_tpool);
push_dao_newstask_free_result(&a_newstask);
update_mysql();
push_unlock_fd(lock_fd);
close(lock_fd);
ThreadData_delete(push_thread_data);
push_sys_notice("--------------------task:%d end----------------\n", task_id);
} /**
* 主函数
*/
int main(int argc, char **argv) {
push_init_logger("logs");
single_process();
atexit(end_main);
/**
*@todo应该先获取任务在实例化线程池
*/
init_main(argc, argv);
get_task(); /**
* 分平台去处理各自的逻辑
*/
platform = atoi(a_newstask.info[][F_news_task_platform]);
//Android平台
if (platform == PUSH_PLATFORM_ANDROID || platform == PUSH_PLATFORM_ALL) {
init_path(PUSH_PLATFORM_ANDROID);
download_files(a_newstask.info[][F_news_task_android_cuid_files]);
android_send_count = read_file(PUSH_PLATFORM_ANDROID);
}
//iphone平台
if (platform == PUSH_PLATFORM_IPHONE || platform == PUSH_PLATFORM_ALL) {
init_path(PUSH_PLATFORM_IPHONE);
download_files(a_newstask.info[][F_news_task_iphone_cuid_files]);
iphone_send_count = read_file(PUSH_PLATFORM_IPHONE);
}
//错误的平台设置
if (platform != PUSH_PLATFORM_ANDROID && platform != PUSH_PLATFORM_ALL &&
platform != PUSH_PLATFORM_IPHONE) {
push_sys_error("platform error:%d", platform);
exit();
}
}

第一个C语言的小项目的更多相关文章

  1. 一个简陋的个人小项目,也是个人第一个真正意义上的独立项目——Graph

    由来 我最早接触到图这个概念是在大二的离散数学当中图论相关的内容,当时是以著名的哥尼斯堡七桥问题引出图论的概念,现在依然记忆犹新(不过只是记得这个名字,具体的解题思路我重新温习了一下才想起来),当时也 ...

  2. 使用OC和Swift两种语言写一个发射烟花的小项目

    OC与Swift两种实现方式基本上区别不大,主要是在一些对象或方法的调用方式不同,附带源码. OC代码样式: self.view.backgroundColor = [UIColor blackCol ...

  3. 我发起并创立了一个 C 语言编译器 开源项目 InnerC

    本文是 VMBC / D#  项目 的 系列文章, 有关 VMBC / D# ,  见 <我发起并创立了一个 VMBC 的 子项目 D#>(以下简称 <D#>)  https: ...

  4. 10分钟掌握Python-机器学习小项目

    学习机器学习相关技术的最好方式就是先自己设计和完成一些小项目. Python 是一种非常流行和强大的解释性编程语言.不像 R 语言,Python 是个很完整的语言和平台,你既可以用来做研发,也可以用来 ...

  5. Vue小项目二手书商城:(一)准备工作、组件和路由

    本项目基于vue2.5.2,与低版本部分不同之处会在(五)参考资料中提出 完整程序:https://github.com/M-M-Monica/bukesi 实现内容: 资源准备(mock数据) 组件 ...

  6. 【源码项目+解析】C语言/C++开发,打造一个小项目扫雷小游戏!

    一直说写个几百行的小项目,于是我写了一个控制台的扫雷,没有想到精简完了代码才200行左右,不过考虑到这是我精简过后的,浓缩才是精华嘛,我就发出来大家一起学习啦,看到程序跑起来能玩,感觉还是蛮有成就感的 ...

  7. 小项目特供 贪吃蛇游戏(基于C语言)

    C语言写贪吃蛇本来是打算去年暑假写的,结果因为ACM集训给耽搁了,因此借寒假的两天功夫写了这个贪吃蛇小项目,顺带把C语言重温了一次. 是发表博客的前一天开始写的,一共写了三个版本,第一天写了第一版,第 ...

  8. python3开发进阶-Django框架学习前的小项目(一个简单的学员管理系统)

    ''' 自己独立写一个学员管理系统 表结构: 班级表: -id -grade_name 学生表: -id -student_name -grade 关联外键班级表 老师表: -id -teacher_ ...

  9. C语言实现简单计算器小项目

    昨天刚安装上devc++,半夜想着练练C语言吧 于是就看到实验楼有一个计算器的项目 之前做过一次,这次写的主要是思路 首先我们先从原理思考jia,实现简单的计算器就要具备加减乘除这些,看普通的计算器也 ...

随机推荐

  1. 一个技术汪的开源梦 —— 基于 .Net Core 的公共组件之目录结构

    一个技术汪的开源梦 —— 目录 这篇文章是开源公共组件的开篇那就先说说项目的 Github 目录结构和 .Net Core 的项目结构. 1. GitHub 目录结构和相关文件 - src 源码项目目 ...

  2. java8 lamda快速入门

    Lambda语法详解 我们在此抽象一下lambda表达式的一般语法: 1 (Type1 param1, Type2 param2, ..., TypeN paramN) -> { 2   sta ...

  3. 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(2)

    作者 彭東林 pengdonglin137@163.com 平臺 tiny4412 ADK Linux-4.4.4 u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uIma ...

  4. Java豆瓣电影爬虫——使用Word2Vec分析电影短评数据

    在上篇实现了电影详情和短评数据的抓取.到目前为止,已经抓了2000多部电影电视以及20000多的短评数据. 数据本身没有规律和价值,需要通过分析提炼成知识才有意义.抱着试试玩的想法,准备做一个有关情感 ...

  5. 7.JAVA之GUI编程鼠标事件

    鼠标事件: 功能: 1.基本窗体功能实现 2.鼠标移动监听,当鼠标移动到按钮上时,触发打印事件. 3.按钮活动监听,当按钮活动时,触发打印事件. 4.按钮被单击时触发打印事件. 源码如下: impor ...

  6. 外边距塌陷之clearance

    在一个BFC中,垂直方向上相邻的块级盒子产生外边距塌陷,本文要说一个特殊的外边距塌陷情况,即当垂直方向上,两个块级盒子之间有个浮动元素相隔时,这个时候会产生什么样的效果呢? .outer{ overf ...

  7. 11 个很少人知道但很有用的 Linux 命令

    Linux命令行吸引了大多数Linux爱好者.一个正常的Linux用户一般掌握大约50-60个命令来处理每日的任务.Linux命令和它们的转换对于Linux用户.Shell脚本程序员和管理员来说是最有 ...

  8. TeamCity : .NET Core 插件

    笔者在<TeamCity : 配置 Build 过程>一文中提到 "TeamCity 内置支持几乎所有的 build 类型".在当今这个软件语言和各种框架飞速发展的时代 ...

  9. 第三篇 Entity Framework Plus 之 Query Cache

    离上一篇博客,快一周,工作太忙,只能利用休息日来写一些跟大家分享,Entity Framework Plus 组件系列文章,之前已经写过两篇 第一篇 Entity Framework Plus 之 A ...

  10. 偷天换日:网络劫持,网页js被伪装替换。

    偷天换日 3月12号石家庄一个客户(后面简称乙方)有几家门店,平台收银(web)有一些功能无法正常使用,平台有上千家门店在使用,到目前为止别的省份都没有此问题.远程协助发现,js日期控件无法正常调用, ...