问题
近日更新了C++用户信息管理服务3.0 修复了之前的一系列问题等等
0427更新 问题和解决方案简单陈述
1、connect等public字段应该修改为private字段 并且改成写相关链接函数和析构函数来实现相关链接和断连接操作
int32_t EstablishConnection()
{
struct timeval timeout = { 1, 500000 }; // 1.5 seconds
//---------------链接mysql------------
l_mysql_connect = mysql_init(NULL);
if(l_mysql_connect==NULL)
{
std::cout<<"初始化环境失败 "<<std::endl;
return 406;//
}
l_mysql_connect=mysql_real_connect(l_mysql_connect, "192.168.100.160", "root", "200101",
"exam2", 3306, NULL, 0);
if(l_mysql_connect == NULL)
{
std::cout<<"连接数据库服务器失败 "<<std::endl;
return 407;//
}
//---------------链接mysql------------
//---------------链接redis------------
l_redis_connect = redisConnectWithTimeout("127.0.0.1", 6379, timeout);
if (l_redis_connect == NULL || l_redis_connect->err)
{
if (l_redis_connect)
{
std::cout<<"connect error:"<<l_redis_connect->errstr<<std::endl;
redisFree(l_redis_connect); //释放redisConnect()所产生的连接。
}
else
{
std::cout<<"connect error: can't allocate redis context "<<std::endl;
}
return 301;
}
//---------------链接redis------------
//---------------链接kafka------------
char l_errstr[512]={}; // API错误报告缓冲区
char l_buf[512]={}; // 消息值临时缓冲区
l_conf=rd_kafka_conf_new();//创建kafka 客户端配置
//配置各项参数 其中kafka port默认为9022号端口
if(rd_kafka_conf_set(l_conf,"bootstrap.servers", l_brokers, l_errstr,sizeof(l_errstr)) != RD_KAFKA_CONF_OK)
{//若返回结果不等于这个enum类型 错误结果打印
fprintf(stderr, "%s\n", l_errstr);
rd_kafka_conf_destroy(l_conf);
//
return 502;
}
//设置发送回调函数 用以反馈信息发送的成败
rd_kafka_conf_set_dr_msg_cb(l_conf, dr_msg_cb); //设置发送回调函数 一旦生产的每条消息被rd_kafka_produce函数接收,投递报告回调函数会被立即调用
//初始化一个顶层对象 的基础容器 用于全局配置和共享状态
//conf在rd_kafka_new调之后不能被再次使用·
l_rk=rd_kafka_new(RD_KAFKA_PRODUCER, l_conf, l_errstr, sizeof(l_errstr));
if(!l_rk)
{
fprintf(stderr, "%% Failed to create new producer: %s\n",l_errstr);
rd_kafka_conf_destroy(l_conf);//
return 503;
}
//如果分配成功 临时配置对象会在rd_kafka_new中被释放 此时无需再rd_kafka_conf_destroy
l_conf=NULL;
//---------------链接kafka------------
return 0;
}
2、判断数量是不合适的,要用判断必须有的字段是否存在来替代 可以设置一个数组 每个下标代表一个字段是否存在
memset(l_array_check,0,sizeof(l_array_check));//初始化这个数组 以判定这个redis是否满足这个条件
...
if(strcmp(l_strs_temp.c_str(),l_str_row[j].c_str())==0)
{
l_flag_field=j;
l_array_check[j]++;
break;
}
...
for(int i=1;i<l_redis_size/2;i++)
{
if(l_array_check[i]==0)
{
_return.error_flag=-305;
std::cout<<"有必要字段不存在..."<<" "<<i<<std::endl;
}
}
3、调用mysql_free_result函数后,MYSQL_ROW指针 不能使用 因此将free后置
4、字符串大小 100->300
5、不需要的代码清理掉例如root2 count 信号量 l_buf
6、pro2con的变量命名不符合规范
7、client 先判断是否有错误,没有错误再使用数据
if(l_msg_temp.error_flag==-404)
{
printf("用户id不存在,请重新键入数字...\n");
return 1;
}
else if(l_msg_temp.usr.seqId>0)//这个id既合法也存在
{
}
else
{
printf("用户id输入不合法,请重新键入数字...\n");
return 1;
}
8、变量命名 大小写
9、client这部分校验代码是否可复用
int l_change_num=0;//修改的数目
int l_check_parameters=0;//输入的参数是否正确
//name
if(user.name.c_str()!=NULL)
{
if(user.name.size()<=20)
{
l_change_num++;
}
else
{
printf("name输入太长,请重新输入!\n");
l_check_parameters= 1;
}
}
...
if(l_check_parameters)
{
std::cout<<"输入的参数错误...!"<<std::endl;
return 1;
}
if(l_change_num<=0)
{
std::cout<<"修改字段数量小于1...!"<<std::endl;
return 1;
}
10、client找到匹配的数据后循环是否没必要继续
if(l_flag_field==0)
{
for(int j=1;j<=l_redis_size/2;j++)
{
if(strcmp(l_strs_temp.c_str(),l_str_row[j].c_str())==0)
{
l_flag_field=j;
l_array_check[j]++;
break;
}
}
}
11、更新数据应该是需要更新什么字段就带什么字段,不需要更新的字段就不设置
主要代码:
server的<upudata>中:
int l_change_num=0;//修改的数目
int l_check_parameters=0;//输入的参数是否正确
//name
if(!user.name.empty())
{
if(user.name.size()<=20)
{
l_change_num++;
}
else
{
std::cout<<"\n传递过来的message数据name字段非法...\n"<<std::endl;
l_check_parameters= -4;
}
}
//sex
if(user.sex!=-1)
{
if(user.sex==0||user.sex==1)
{
l_change_num++;
}
else
{
std::cout<<"\n传递过来的message数据sex字段非法...\n"<<std::endl;
l_check_parameters= -4;
}
}
pthread_mutex_lock(&l_updata_mutex);//再加一个updata lock防止出现 有两个客户端同时更新一个用户的数据 如果这里只用mysql锁 那么下一行QueryUser会死锁
//----得到一个待修改前完整的user 将未修改的字段也填上 后面存储过程updata无法更新单个或部分字段
QueryUser(l_temp_query_msg,seqId);
if(!user.name.empty())l_temp_query_msg.usr.name=user.name;
if(user.sex!=-1)l_temp_query_msg.usr.sex=user.sex;//222222222
if(user.age!=-1)l_temp_query_msg.usr.age=user.age;
if(!user.tel.empty())l_temp_query_msg.usr.tel=user.tel;
if(!user.email.empty())l_temp_query_msg.usr.email=user.email;
if(!user.pers_desc.empty())l_temp_query_msg.usr.pers_desc=user.pers_desc;
client<main>中
l_msg.usr.sex=(std::stoi(argv[i+1])==-1?std::stoi(argv[i+1])-1:std::stoi(argv[i+1]));//若用户就输入-1 则-2
12、如果没有必要,不要使用earliest,正常情况应当从group创建的时刻开始读取数据
if(rd_kafka_conf_set(l_conf, "auto.offset.reset", "latest", l_errstr,
sizeof(l_errstr)) != RD_KAFKA_CONF_OK) {
fprintf(stderr, "%s\n", l_errstr);
rd_kafka_conf_destroy(l_conf);//
return 4;
}
13、使用json要做好异常处理
std::cout<<"新得到的数据如下"<<std::endl;
if(root["ID"]!=Json::nullValue&&root["ID"].isInt())
{
std::cout<<"ID:"<<root["ID"]<<std::endl;
}
if(root["name"]!=Json::nullValue&&root["name"].isString())
{
std::cout<<"name:"<<root["name"]<<std::endl;
}
if(root["sex"]!=Json::nullValue&&root["sex"].isInt())
{
std::cout<<"sex:"<<root["sex"]<<std::endl;
}
if(root["age"]!=Json::nullValue&&root["age"].isInt())
{
std::cout<<"age:"<<root["age"]<<std::endl;
}
if(root["tel"]!=Json::nullValue&&root["tel"].isString())
{
std::cout<<"tel:"<<root["tel"]<<std::endl;
}
if(root["email"]!=Json::nullValue&&root["email"].isString())
{
std::cout<<"email:"<<root["email"]<<std::endl;
}
if(root["pers_desc"]!=Json::nullValue&&root["pers_desc"].isString())
{
std::cout<<"pers_desc:"<<root["pers_desc"]<<std::endl;
}
14、内存泄漏consumer中的内存泄漏
if(reader.parse((const char *)l_rkm->payload,root)==0)
{
std::cout<<"reader.parse赋值错误!"<<std::endl;
rd_kafka_message_destroy(l_rkm);
continue;
}
15、能在循环外定义的变量就定义循环外
rd_kafka_message_t *l_rkm;
Json::Reader l_reader(Json::Features::strictMode());
Json::Value l_root;
while (1)
0424更新 问题和解决方案简单陈述
1、表和存储过程的名称问题
test->t_test
queryuser->pr_queryuser
insertuser->pr_insertuser
updatauser->pr_updatauser
2、Select选取数量问题不要用*
queryuser:
create procedure pr_queryuser (in in_id int)
label_a:begin
SELECT id,name,sex,age,tel,email,pers_desc from t_test where id=in_id limit 1;
end;
3、updata的存储过程要判断是否该成功
int l_affected_rows=mysql_affected_rows(l_mysql_connect);
if(l_affected_rows!=1)
{
std::cout<<"修改错误 本应修改的行数为1,实际值为"<<l_affected_rows<<std::endl;
return 401;
}
4、message传递信息要嵌套 再getuser里面
struct message
{
1:User1 usr;
2:i32 error_flag;
}
5、变量作用域的问题 不要使用全局变量
private:
const char *hostname = "127.0.0.1";
const int l_redis_size=12;
const int l_redis_port=6379;
pthread_mutex_t l_redis_mutex=PTHREAD_MUTEX_INITIALIZER;//static init mutex
pthread_mutex_t l_mysql_mutex=PTHREAD_MUTEX_INITIALIZER;//static init mutex
std::string l_str_row[7]={"ID","name","sex","age","tel","email","pers_desc"};
public:
redisContext *l_redis_connect=NULL;
MYSQL* l_mysql_connect=NULL;
rd_kafka_t *l_rk=NULL; // 生产者实例句柄
rd_kafka_conf_t *l_conf=NULL; // 临时配置对象
6、redis可以存储null mysql 存储改为不用非得有默认值 以个人介绍为例子
create table t_test(id int primary key AUTO_INCREMENT,name varchar(20) not null DEFAULT 'unknow',sex int not null DEFAULT -1, age int not null DEFAULT -1, tel varchar(20) not null DEFAULT 'unknow', email varchar(30) not null DEFAULT 'unknow', pers_desc varchar(150) )
if(strncmp(user.pers_desc.c_str(),"NULL",4))
l_reply = (redisReply*)redisCommand(l_redis_connect,"hmset user%d name %s sex %d age %d tel %s email %s pers_desc %s",user.seqId,user.name.c_str(),user.sex,user.age,user.tel.c_str(),user.email.c_str(),user.pers_desc.c_str());
else
l_reply = (redisReply*)redisCommand(l_redis_connect,"hmset user%d name %s sex %d age %d tel %s email %s",user.seqId,user.name.c_str(),user.sex,user.age,user.tel.c_str(),user.email.c_str());
从redis提取数据给User时 防止有pers_desc为空的情况 _return.usr.pers_desc="NULL";//先赋值一个null
7、redis输出顺序 不保证顺序 乱序处理情况
//根据当前出现的redis字符串 设置l_flag_fileld 找到下一个element应该赋给的自变量
l_flag_fileld=0;
if(l_flag_fileld==0)
{
for(int j=1;j<=l_redis_size/2;j++)/
{
if(strcmp(l_strs_temp.c_str(),l_str_row[j].c_str())==0)//与各种字段title进行匹配
{
l_flag_fileld=j;
}
}
}
else
{
switch (l_flag_fileld)
{
case 1:
_return.usr.name=l_strs_temp;
break;
case 2:
_return.usr.sex=l_strs_temp[0]-'0';
break;
case 3:
_return.usr.age=std::stoi(l_strs_temp.c_str());
break;
case 4:
_return.usr.tel=l_strs_temp;
break;
case 5:
_return.usr.email=l_strs_temp;
break;
case 6:
_return.usr.pers_desc=l_strs_temp;
break;
default:
break;
}
l_flag_fileld=0;
}
8、unlock解锁漏了
if(l_result==NULL)
{
printf("mysql_store_result() 失败了 \n");
//mysql_free_result(l_result);
_return.error_flag=-402;
pthread_mutex_unlock(&l_mysql_mutex);//解锁
return ;
}
9、精简mysql中的清除result代码 代码复用
MYSQL_ROW row=NULL;
int l_num=0;
int l_result_flag=0;
if(l_result==NULL)
{
l_result_flag=1;
}
if(l_result!=NULL)
{
row = mysql_fetch_row(l_result);
l_num=mysql_num_fields(l_result);
}
mysql_free_result(l_result);
while (!mysql_next_result(l_mysql_connect)) {
l_result = mysql_store_result(l_mysql_connect);
mysql_free_result(l_result);
}
pthread_mutex_unlock(&l_mysql_mutex);
if(l_result_flag)return -402;
10、mysql注入错误字符的情况 写一个check函数 改正字符串可能错误情况 例如将 ‘ -> ‘‘ 再插入数据库
std::string CheckStr(std::string str)
{
//std::string l_key[11] = { "%","/","union","|","&","^","#","/*","*/","'"," "};
std::string l_str_tmp="'";
int l_pos=str.find(l_str_tmp);
for ( int i=0;i<str.size();i++)
{
if(str[i]=='\'')
{
str.insert(i,l_str_tmp);
i++;
}
}
std::cout<<str<<std::endl;
return str;
}
11、_return直接赋值 而不是赋值给别的自变量 再赋值给_return
_return.error_flag=-302;
return ;
12、错误输出的细化 输出更多的内容更详细的内容
if(user.name.size()>20)
{
std::cout<<"\n传递过来的message数据name字段非法...\n"<<std::endl;
return -4;
}
else if(user.sex>1||user.sex<0)
{
std::cout<<"\n传递过来的message数据sex字段非法...\n"<<std::endl;
return -4;
}
else if(user.age>150||user.age<0)
{
std::cout<<"\n传递过来的message数据age字段非法...\n"<<std::endl;
return -4;
}
else if(user.tel.size()>20)
{
std::cout<<"\n传递过来的message数据tel字段非法...\n"<<std::endl;
return -4;
}
else if(user.email.size()>30)
{
std::cout<<"\n传递过来的message数据email字段非法...\n"<<std::endl;
return -4;
}
else if(user.pers_desc.size()>100)
{
std::cout<<"\n传递过来的message数据pers_desc字段非法...\n"<<std::endl;
return -4;
}
13、kafka连接问题 将其带到server中 对实例l_rk上锁
char l_errstr[512]={}; // API错误报告缓冲区
char l_buf[512]={}; // 消息值临时缓冲区
handler->l_conf=rd_kafka_conf_new();//创建kafka 客户端配置
//配置各项参数 其中kafka port默认为9022号端口
if(rd_kafka_conf_set(handler->l_conf,"bootstrap.servers", handler->l_brokers, l_errstr,sizeof(l_errstr)) != RD_KAFKA_CONF_OK)
{//若返回结果不等于这个enum类型 错误结果打印
fprintf(stderr, "%s\n", l_errstr);
rd_kafka_conf_destroy(handler->l_conf);
//
return 502;
}
//设置发送回调函数 用以反馈信息发送的成败
rd_kafka_conf_set_dr_msg_cb(handler->l_conf, handler->dr_msg_cb); //设置发送回调函数 一旦生产的每条消息被rd_kafka_produce函数接收,投递报告回调函数会被立即调用
//初始化一个顶层对象 的基础容器 用于全局配置和共享状态
//conf在rd_kafka_new调之后不能被再次使用·
handler->l_rk=rd_kafka_new(RD_KAFKA_PRODUCER, handler->l_conf, l_errstr, sizeof(l_errstr));
if(!handler->l_rk)
{
fprintf(stderr, "%% Failed to create new producer: %s\n",l_errstr);
rd_kafka_conf_destroy(handler->l_conf);//
return 503;
}
//如果分配成功 临时配置对象会在rd_kafka_new中被释放 此时无需再rd_kafka_conf_destroy
handler->l_conf=NULL;
14、重写client,使其改成main的命令行输入 类似于svn
fprintf(stderr,"%% Usage: ""%s Find <ID> \n",argv[0]);
fprintf(stderr,"%% Usage: ""%s Insert <name> <sex> <age> <tel> <email> (<pers_desc>)..\n",argv[0]);
fprintf(stderr,"%% Usage: ""%s Updata <ID> <field1> <content> <field2> <content>... )\n",argv[0]);
15、输出形式统一 不要c/c++混用
目前暂时统一了服务器的输出格式为cout
0422更新:
1将服务端中的CheckID和QueryUser融合为一个函数 其中返回为message
2将客户端中的CheckID函数删除 检查ID操作移交给服务器Query全权负责
3将服务端中的Mysql连接和Redis连接部分放在main函数中 并对连接上锁
只有需要对连接使用时 开始对连接上锁 使用完毕立即将连接下锁
4对存储过程的修改和简化
queryuser:
create procedure pr_queryuser (in in_id int)
label_a:begin
SELECT id,name,sex,age,tel,email,pers_desc from t_test where id=in_id limit 1;
end;
call queryuser (1);
insertuser:
create procedure pr_insertuser (in in_name varchar(20),in in_sex bool,in in_age int,in in_tel varchar(20),in in_email varchar(30),in in_pers_desc varchar(150))
label_a:begin
insert into t_test (name,sex,age,tel,email,pers_desc) values (in_name,in_sex,in_age,in_tel,in_email,in_pers_desc);
SELECT LAST_INSERT_ID();
end;
updatauser:
create procedure pr_updatauser (in in_id int,in in_name varchar(20),in in_sex bool,in in_age int,in in_tel varchar(20),in in_email varchar(30),in in_pers_desc varchar(150))
begin
update t_test set name=in_name,sex=in_sex,age=in_age,tel=in_tel,email=in_email,pers_desc=in_pers_desc where id=in_id;
end;
5存储结构更改为id自增 并且age改为数字
create table test(id int primary key AUTO_INCREMENT,name varchar(20) not null DEFAULT 'unknow',sex int not null DEFAULT -1, age int not null DEFAULT -1, tel varchar(20) not null DEFAULT 'unknow', email varchar(30) not null DEFAULT 'unknow', pers_desc varchar(150) not null DEFAULT 'unknow')
6调用存储过程后,没有完全释放资源:
在mysql_free_result之后需要循环mysql_next_result清除result否则无法进行新的query
server代码
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "serDemo.h"
#include <thrift/concurrency/ThreadManager.h>
#include <thrift/concurrency/ThreadFactory.h>
#include <thrift/server/TThreadPoolServer.h>
#include <thrift/server/TThreadedServer.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <unistd.h>
#include <pthread.h>
#include <jsoncpp/json/json.h>
#include "rdkafka.h"
#include <fstream>
#include <sstream>
#include <map>
#include <string>
#include <pthread.h>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <mysql8/mysql.h>
#include <cstdio>
#include <memory>
#include <hiredis.h>
// 读: 读redis->没有,读mysql->把mysql数据写回redis,有的话直接从redis中取;
// 写: 写mysql->成功,再写redis;
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using namespace ::apache::thrift::concurrency;
//l_msg_temp.id =-1 getuser 返回了一个空值
// return -2没有该用户id
// return -1id不合法
// return -101 服务端getuser失败
// return 1数据插入数据库失败
// return 2新数据修改数据库vec失败!
// return 3客户端输出失败
// return 4message传入的数值不合法
//return 5 修改的数量为0
//seqid为负数也代表相应含义
// return 301 redisContext链接失败
// return 302 reply 获取失败
// return 303 reply->type 类型不对
// return 304 reply 数值不对
// return 305 reply->elements 数值不对
// return 401 mysql语句返回错误
// return 402 l_result返回错误
// return 403 判断存储过程中的return是否出错
// return 404 数据库没有该id的数据
// return 405 l_row[0]为null 不该为null的为null
// return 406 初始化mysql失败
// return 407 mysql连接失败
// return 408 mysql affecct_row=0;
// return 501 反序列化失败
// return 502 rd_kafka_conf_set失败
// return 503 rd_kafka_new失败
class serDemoHandler : virtual public serDemoIf {
private:
const char *hostname = "127.0.0.1";
const int l_redis_size=12;
const int l_redis_port=6379;
redisContext *l_redis_connect=NULL;
MYSQL* l_mysql_connect=NULL;
//-----kafka---------------
char l_brokers[100]="192.168.100.160:9092";
char l_topic[100]="TestTopicForDocker";
rd_kafka_t *l_rk=NULL; // 生产者实例句柄
rd_kafka_conf_t *l_conf=NULL; // 临时配置对象
//-----kafka---------------
pthread_mutex_t l_redis_mutex=PTHREAD_MUTEX_INITIALIZER;//static init mutex
pthread_mutex_t l_mysql_mutex=PTHREAD_MUTEX_INITIALIZER;//static init mutex
pthread_mutex_t l_kafka_mutex=PTHREAD_MUTEX_INITIALIZER;//static init mutex
pthread_mutex_t l_updata_mutex=PTHREAD_MUTEX_INITIALIZER;//static init mutex
std::string l_str_row[7]={"ID","name","sex","age","tel","email","pers_desc"};
std::string CheckStr(std::string str)
{
// std::string l_key[11] = { "%","/","union","|","&","^","#","/*","*/","'"," "};
// for (int i = 0; i < 11; i++)
// {
// if (str.find(l_key[i]) != std::string::npos)
// {
// return false;
// }
// }
// return true;
std::string l_str_tmp="'";
int l_pos=str.find(l_str_tmp);
for(int i=0;i<str.size();i++)
{
if(str[i]=='\'')
{
str.insert(i,l_str_tmp);
i++;
}
}
std::cout<<str<<std::endl;
return str;
}
int l_array_check[10]={0};
public:
serDemoHandler() {
// Your initialization goes here
}
~serDemoHandler() {
redisFree(l_redis_connect);
mysql_close(l_mysql_connect);
rd_kafka_destroy(l_rk);//万事俱备 销毁实例
}
int32_t EstablishConnection()
{
struct timeval timeout = { 1, 500000 }; // 1.5 seconds
//---------------链接mysql------------
l_mysql_connect = mysql_init(NULL);
if(l_mysql_connect==NULL)
{
std::cout<<"初始化环境失败 "<<std::endl;
return 406;//
}
l_mysql_connect=mysql_real_connect(l_mysql_connect, "192.168.100.160", "root", "200101",
"exam2", 3306, NULL, 0);
if(l_mysql_connect == NULL)
{
std::cout<<"连接数据库服务器失败 "<<std::endl;
return 407;//
}
//---------------链接mysql------------
//---------------链接redis------------
l_redis_connect = redisConnectWithTimeout("127.0.0.1", 6379, timeout);
if (l_redis_connect == NULL || l_redis_connect->err)
{
if (l_redis_connect)
{
std::cout<<"connect error:"<<l_redis_connect->errstr<<std::endl;
redisFree(l_redis_connect); //释放redisConnect()所产生的连接。
}
else
{
std::cout<<"connect error: can't allocate redis context "<<std::endl;
}
return 301;
}
//---------------链接redis------------
//---------------链接kafka------------
char l_errstr[512]={}; // API错误报告缓冲区
//char l_buf[512]={}; // 消息值临时缓冲区
l_conf=rd_kafka_conf_new();//创建kafka 客户端配置
//配置各项参数 其中kafka port默认为9022号端口
if(rd_kafka_conf_set(l_conf,"bootstrap.servers", l_brokers, l_errstr,sizeof(l_errstr)) != RD_KAFKA_CONF_OK)
{//若返回结果不等于这个enum类型 错误结果打印
fprintf(stderr, "%s\n", l_errstr);
rd_kafka_conf_destroy(l_conf);
//
return 502;
}
//设置发送回调函数 用以反馈信息发送的成败
rd_kafka_conf_set_dr_msg_cb(l_conf, dr_msg_cb); //设置发送回调函数 一旦生产的每条消息被rd_kafka_produce函数接收,投递报告回调函数会被立即调用
//初始化一个顶层对象 的基础容器 用于全局配置和共享状态
//conf在rd_kafka_new调之后不能被再次使用·
l_rk=rd_kafka_new(RD_KAFKA_PRODUCER, l_conf, l_errstr, sizeof(l_errstr));
if(!l_rk)
{
fprintf(stderr, "%% Failed to create new producer: %s\n",l_errstr);
rd_kafka_conf_destroy(l_conf);//
return 503;
}
//如果分配成功 临时配置对象会在rd_kafka_new中被释放 此时无需再rd_kafka_conf_destroy
l_conf=NULL;
//---------------链接kafka------------
return 0;
}
void QueryUser(message& _return, const int32_t seqId)
{
std::cout<<"\nQueryMysql..."<<std::endl;
//message l_msg_temp;
_return.error_flag=0;
if(seqId<1||seqId>=0x7fffffff)
{
std::cout<<"用户id输入长度或数值不合法传入过来的ID是:"<<seqId<<std::endl;
_return.error_flag=-1;
return ;
}
//先找redis
// //-------------------操作redis部分--------------------↓
//
//1链接测试部分
std::cout<<"\n进行redis链接...先查询redis是否存在数据..."<<std::endl;
redisReply *l_reply=NULL;
//sleep(20);
//2从redis中找数据部分
pthread_mutex_lock(&l_redis_mutex);
l_reply = (redisReply*)redisCommand(l_redis_connect,"hgetall user%d",seqId);
//int q;
//std::cin>>q;
pthread_mutex_unlock(&l_redis_mutex);
if(l_reply==NULL)
{
std::cout<<"reply获取失败"<<std::endl;
_return.error_flag=-302;
return ;
}
else if(l_reply->type!=REDIS_REPLY_ARRAY)
{
std::cout<<"reply->type 类型错误"<<std::endl;
freeReplyObject(l_reply);
_return.error_flag=-303;
return ;
}
else if(l_reply->elements%2==0&&l_reply->elements!=0)//在redis中 可能找到了 要进行判定
{
memset(l_array_check,0,sizeof(l_array_check));//初始化这个数组 以判定这个redis是否满足这个条件
//std::cout<<"queryuser函数中在redis中找到了"<<std::endl;
std::cout<<"l_reply->elements"<<l_reply->elements<<std::endl;
//_return.usr.pers_desc="NULL";//先赋值一个null
int l_flag_field=0;
for(int i=0;i<l_reply->elements;i++)
{
if(l_reply->element[i]==NULL)
{
std::cout<<"reply获取失败"<<std::endl;
freeReplyObject(l_reply);
_return.error_flag=-302;
return ;
}
else if(l_reply->element[i]->type!=REDIS_REPLY_STRING)
{
std::cout<<"数据展示出错2"<<std::endl;
freeReplyObject(l_reply);
_return.error_flag=-303;
return ;
}
//1//输出一下
std::string l_strs_temp(l_reply->element[i]->str,l_reply->element[i]->len);
std::cout<<"index "<<i<<":"<<l_strs_temp.c_str()<<std::endl;
//根据当前出现的redis字符串 设置l_flag_field 找到下一个element应该赋给的自变量
if(l_flag_field==0)
{
for(int j=1;j<=l_redis_size/2;j++)
{
if(strcmp(l_strs_temp.c_str(),l_str_row[j].c_str())==0)
{
l_flag_field=j;
l_array_check[j]++;
break;
}
}
}
else
{
switch (l_flag_field)
{
case 1:
_return.usr.name=l_strs_temp;
break;
case 2:
_return.usr.sex=std::stoi(l_strs_temp.c_str());
break;
case 3:
_return.usr.age=std::stoi(l_strs_temp.c_str());
break;
case 4:
_return.usr.tel=l_strs_temp;
break;
case 5:
_return.usr.email=l_strs_temp;
break;
case 6:
_return.usr.pers_desc=l_strs_temp;
break;
default:
break;
}
l_flag_field=0;
}
}
for(int i=1;i<l_redis_size/2;i++)
{
if(l_array_check[i]==0)
{
_return.error_flag=-305;
std::cout<<"有必要字段不存在..."<<" "<<i<<std::endl;
freeReplyObject(l_reply);
return ;
}
}
_return.usr.seqId=seqId;
freeReplyObject(l_reply);
std::cout<<"GetUser函数结束..."<<std::endl;
return ;
}
//std::cout<<l_reply->type<<" "<<l_reply->elements<<std::endl;
std::cout<<"查询redis完毕 没找到数据结束redis链接..."<<std::endl;
freeReplyObject(l_reply);
//redisFree(connect);
//-------------------操作redis部分--------------------↑
//再找数据库
//-------------------操作数据库部分--------------------
std::cout<<"开始查找数据库..."<<std::endl;
//4调用过程//
char l_call_cstr[300]={};
//std::string l_call_str="";
sprintf(l_call_cstr, "call pr_queryuser (%d);",seqId);
//l_call_str=l_call_cstr;
pthread_mutex_lock(&l_mysql_mutex);//上锁
int l_ret1=mysql_query(l_mysql_connect,l_call_cstr);
//cout<<l_ret1<<" "<<l_mysql_connect<<" "<<l_call_cstr<<endl;
if(l_ret1!=0)
{
std::cout<<"操作数据库语句错误call_error,语句为:"<<l_call_cstr<<"\n mysql_query的返回值为:"<<l_ret1<<std::endl;
_return.error_flag=-401;
pthread_mutex_unlock(&l_mysql_mutex);//解锁
return ;
}
//返回结果测试
MYSQL_RES* l_result=mysql_store_result(l_mysql_connect);
if(l_result==NULL)
{
std::cout<<"mysql_store_result() 失败了,原因 l_result=NULL."<<std::endl;
//mysql_free_result(l_result);
_return.error_flag=-402;
pthread_mutex_unlock(&l_mysql_mutex);//解锁
return ;
}
//6展示
MYSQL_ROW l_row;
l_row = mysql_fetch_row(l_result);
int l_num=mysql_num_fields(l_result);
//std::string s_temp="404";
if(l_row==NULL)//strncmp(l_row[0],"0",1)!=0
{
std::cout<<"MYSQL_ROW为NULL,当前查询的id 在数据库中查询不到"<<std::endl;
_return.error_flag=-404;
//return ;//没有该id
}
else if(l_num!=7)//这里mysql即使有字段为nuLL 数量也是7 除非没该id
{
std::cout<<l_num<<std::endl;
std::cout<<"MYSQL_ROW不为NULL,但是查询到的字段值竟然不是7 一个预期之外的错误!"<<std::endl;
_return.error_flag=-405;
//return ;//判断存储过程中的return是否出错
}
else
{
std::cout<<"存储过程返回值数据如下:"<<std::endl;
for(int i=0;i<l_redis_size/2+1;i++)
{
if(l_row[i]!=NULL)
{
std::cout<<l_str_row[i]<<l_row[i]<<std::endl;
}
else
{
std::cout<<l_str_row[i]<<"为null"<<std::endl;
if(i!=6)
{
std::cout<<"一个不是可以为null的字段竟然为null,预期之外的错误!"<<std::endl;
_return.error_flag=-405;
//return ;
break;
}
}
}
//释放mysql资源
_return.usr.seqId=seqId;
_return.usr.name=l_row[1];
_return.usr.sex=std::stoi(l_row[2]);
//std::string l_strs_temp_row3(l_row[3]);
_return.usr.age=std::stoi(l_row[3]);//
_return.usr.tel=l_row[4];
_return.usr.email=l_row[5];
_return.usr.pers_desc=l_row[6];
}
// 在row使用完毕之后 开始清除l_result
mysql_free_result(l_result);
//循环清除结果集 对于存储过程必须如此 否则无法重复使用连接
while (!mysql_next_result(l_mysql_connect)) {
l_result = mysql_store_result(l_mysql_connect);
mysql_free_result(l_result);
}
pthread_mutex_unlock(&l_mysql_mutex);//解锁
l_row=NULL;
if(_return.error_flag!=0)
{
std::cout<<"queryuser 函数在redis和数据库中都没找到相关数据..."<<std::endl;
return ;
}
//
std::cout<<"queryuser 函数在数据库中找到相关数据..."<<std::endl;
//-------------------操作数据库部分--------------------↑
// //-------------------操作redis部分--------------------↓
std::cout<<"mysql找到数据完毕...将数据插入到redis..."<<std::endl;
pthread_mutex_lock(&l_redis_mutex);
//2写入redis中数据部分
if(_return.usr.pers_desc.c_str()!=NULL)//
l_reply = (redisReply*)redisCommand(l_redis_connect,"hmset user%d name %s sex %d age %d tel %s email %s pers_desc %s",seqId,_return.usr.name.c_str(),_return.usr.sex,_return.usr.age,_return.usr.tel.c_str(),_return.usr.email.c_str(),_return.usr.pers_desc.c_str());
else
l_reply = (redisReply*)redisCommand(l_redis_connect,"hmset user%d name %s sex %d age %d tel %s email %s",seqId,_return.usr.name.c_str(),_return.usr.sex,_return.usr.age,_return.usr.tel.c_str(),_return.usr.email.c_str());
pthread_mutex_unlock(&l_redis_mutex);
if(l_reply==NULL)
{
std::cout<<"reply获取失败"<<std::endl;
_return.error_flag=302;
return ;
}
else if(l_reply->type!=REDIS_REPLY_STATUS)
{
std::cout<<"reply->type 类型错误"<<std::endl;
freeReplyObject(l_reply);
_return.error_flag=303;
return ;
}
else if(strncmp("OK",l_reply->str,2)!=0)
{
std::cout<<"数据插入失败"<<std::endl;
freeReplyObject(l_reply);
_return.error_flag=304;
return ;
}
std::cout<<"query将数据插入redis完毕 ..."<<std::endl;
//-------------------操作redis部分--------------------上
//3释放redis资源
freeReplyObject(l_reply);
std::cout<<"QueryUser函数结束 ..."<<std::endl;
return ;//该id存在
}
int32_t InsertUser(const User1& user)
{
std::cout<<"InsertUser..."<<std::endl;
User1 l_temp_user=user;
int32_t l_Query_return=0;
int32_t l_seqId=0;
if(user.name.size()>20)
{
std::cout<<"传递过来的message数据name字段非法..."<<std::endl;
return -4;
}
else if(user.sex>1||user.sex<0)
{
std::cout<<"传递过来的message数据sex字段非法..."<<std::endl;
return -4;
}
else if(user.age>150||user.age<0)
{
std::cout<<"传递过来的message数据age字段非法..."<<std::endl;
return -4;
}
else if(user.tel.size()>20)
{
std::cout<<"传递过来的message数据tel字段非法..."<<std::endl;
return -4;
}
else if(user.email.size()>30)
{
std::cout<<"传递过来的message数据email字段非法..."<<std::endl;
return -4;
}
else if(user.pers_desc.size()>100)
{
std::cout<<"传递过来的message数据pers_desc字段非法..."<<std::endl;
return -4;
}
//先插入mysql
//-------------------操作数据库部分--------------------
//mysql指针初始化
//4调用过程
char l_call_cstr[300]={};
//std::string l_call_str="";
//sprintf(l_call_cstr, "call insertuser ('111',1,1,'1','1','1');");
sprintf(l_call_cstr, "call pr_insertuser ('%s', %d , %d , '%s','%s','%s');",CheckStr(user.name).c_str(),user.sex,user.age,CheckStr(user.tel).c_str(),CheckStr(user.email).c_str(),CheckStr(user.pers_desc).c_str());
//l_call_str=l_call_cstr;
//printf("%s\n",l_call_cstr);
pthread_mutex_lock(&l_mysql_mutex);
int32_t l_ret1=mysql_query(l_mysql_connect, l_call_cstr);
MYSQL_ROW l_row=NULL;
int l_num=0;
int l_result_flag=0;
if(l_ret1!=0)
{
std::cout<<"操作数据库语句错误call_error,语句为:"<<l_call_cstr<<"\n mysql_query的返回值为:"<<l_ret1<<std::endl;
pthread_mutex_unlock(&l_mysql_mutex);
return -401;
}
MYSQL_RES* l_result=mysql_store_result(l_mysql_connect);
if(l_result==NULL)
{
l_result_flag=-402;
std::cout<<"mysql_store_result() 失败了,l_result==NULL"<<std::endl;
}
else
{
l_row = mysql_fetch_row(l_result);
l_num = mysql_num_fields(l_result);
}
if(l_result_flag==0&&l_row==NULL)//strncmp(l_row[0],"0",1)!=0
{
std::cout<<"没有当前查询id..."<<std::endl;
l_result_flag= -405;//没有该id
}
else if(l_result_flag==0&&(l_num!=1||l_row[0]==NULL))
{
std::cout<<"l_num_filed:"<<l_num<<std::endl;
l_result_flag= -405;//判断存储过程中的return是否出错
}
else if(l_result_flag==0)
{
l_seqId=std::stoi(l_row[0]);//
}
// 返回结果测试
//清除掉相应的result 但是同时也要注意 不要将 row还在的时候就将其清除掉否则会导致row指针悬挂
mysql_free_result(l_result);
while (!mysql_next_result(l_mysql_connect)) {
l_result = mysql_store_result(l_mysql_connect);
mysql_free_result(l_result);
}
pthread_mutex_unlock(&l_mysql_mutex);
if(l_result_flag!=0)
{
std::cout<<"queryuser 函数在redis和数据库中都没找到相关数据..."<<std::endl;
return l_result_flag;
}
std::cout<<"成功插入进数据库..插入成功!..."<<std::endl;
//-------------------操作数据库部分--------------------↑
//然后再插入redis
//-------------------操作redis部分--------------------↓
redisReply *l_reply=NULL;
struct timeval timeout = { 1, 500000 }; // 1.5 seconds
//1链接测试部分
//2写入redis中数据部分
pthread_mutex_lock(&l_redis_mutex);
if(strncmp(user.pers_desc.c_str(),"NULL",4))
l_reply = (redisReply*)redisCommand(l_redis_connect,"hmset user%d name %s sex %d age %d tel %s email %s pers_desc %s",user.seqId,user.name.c_str(),user.sex,user.age,user.tel.c_str(),user.email.c_str(),user.pers_desc.c_str());
else
l_reply = (redisReply*)redisCommand(l_redis_connect,"hmset user%d name %s sex %d age %d tel %s email %s",user.seqId,user.name.c_str(),user.sex,user.age,user.tel.c_str(),user.email.c_str());
pthread_mutex_unlock(&l_redis_mutex);
if(l_reply==NULL)
{
std::cout<<"reply获取失败"<<std::endl;
//redisFree(connect); //释放redisConnect()所产生的连接。
return -302;
}
else if(l_reply->type!=REDIS_REPLY_STATUS)
{
std::cout<<"reply->type 类型错误"<<std::endl;
freeReplyObject(l_reply);
//redisFree(connect); //释放redisConnect()所产生的连接。
return -303;
}
else if(strncmp("OK",l_reply->str,2)!=0)
{
std::cout<<"数据插入失败"<<std::endl;
freeReplyObject(l_reply);
//redisFree(connect); //释放redisConnect()所产生的连接。
return -304;
}
std::cout<<"成功插入进redis..插入成功!..."<<std::endl;
freeReplyObject(l_reply);
//redisFree(connect);
//-------------------操作redis部分--------------------↑
int l_return_pro=Prod2Cons(user);
//传递给生产者
if(l_return_pro!=0)
{
std::cout<<"传递给生产者出错..."<<std::endl;
}
std::cout<<"InsertUser函数结束...\n"<<std::endl;
return l_seqId;
}
int32_t UpdataUser(const int32_t seqId,const User1& user)
{
std::cout<<"\nUpdataUser...\n"<<std::endl;
int l_change_num=0;//修改的数目
int l_check_parameters=0;//输入的参数是否正确
//name
if(!user.name.empty())
{
if(user.name.size()<=20)
{
l_change_num++;
}
else
{
std::cout<<"\n传递过来的message数据name字段非法...\n"<<std::endl;
l_check_parameters= -4;
}
}
//sex
if(user.sex!=-1)
{
if(user.sex==0||user.sex==1)
{
l_change_num++;
}
else
{
std::cout<<"\n传递过来的message数据sex字段非法...\n"<<std::endl;
l_check_parameters= -4;
}
}
//age user.age!=NULL
if( user.age!=-1)
{
if(user.age<=150&&user.age>=0)
{
l_change_num++;
}
else
{
std::cout<<"\n传递过来的message数据age字段非法...\n"<<std::endl;
l_check_parameters = -4 ;
}
}
//tel
if(!user.tel.empty())
{
if(user.tel.size()>20)
{
printf("tel输入过长错误,请重新输入!\n");
l_check_parameters = -4 ;
}
else
{
for(int i=0;i<user.tel.size();i++)
{
if(user.tel[i]<'0'||user.tel[i]>'9')
{
std::cout<<"\n传递过来的message数据tel字段非法...\n"<<std::endl;
l_check_parameters = -4 ;
break;
}
if(i==user.tel.size()-1)
{
l_change_num++;
}
}
}
}
//email
if(!user.email.empty())
{
if(user.email.size()<=30)
{
l_change_num++;
}
else
{
std::cout<<"\n传递过来的message数据email字段非法...\n"<<std::endl;
l_check_parameters = -4 ;
}
}
//pers_desc
if(!user.pers_desc.empty())
{
if(user.pers_desc.size()<=150)
{
l_change_num++;
}
else
{
std::cout<<"\n传递过来的message数据pers_desc字段非法...\n"<<std::endl;
l_check_parameters = -4 ;
}
}
if(l_check_parameters)return l_check_parameters;
if(l_change_num==0)return -5;
std::cout<<"l_change_num"<<l_change_num<<std::endl;
//1 判断一下该id是否存在
// QueryUser(l_temp_query_user,seqId);
// l_Query_return=l_temp_query_user.seqId;
// if(l_Query_return==-404)
// {
// printf("该id数据不存在,修改失败!\n");
// return l_Query_return;
// }
// else if(l_Query_return<=0)
// {
// printf("QueryMysql出错 l_Query_return=%d\n",l_Query_return);
// return l_Query_return;
// }
//-------------------操作数据库部分--------------------
//mysql指针初始化
char l_call_cstr[300]={0};
//std::string l_call_str="";
message l_temp_query_msg;
//l_call_str=l_call_cstr;
pthread_mutex_lock(&l_updata_mutex);//再加一个updata lock防止出现 有两个客户端同时更新一个用户的数据 如果这里只用mysql锁 那么下一行QueryUser会死锁
//----得到一个待修改前完整的user 将未修改的字段也填上 后面存储过程updata无法更新单个或部分字段
QueryUser(l_temp_query_msg,seqId);
if(l_temp_query_msg.error_flag!=0)
{
std::cout<<"插入时 在query函数中查询该id 未得到正确结果 返回错误代码为:"<<l_temp_query_msg.error_flag<<std::endl;
pthread_mutex_unlock(&l_updata_mutex);
return l_temp_query_msg.error_flag;
}
std::cout<<std::endl<<"---------------------"<<std::endl<<l_temp_query_msg.usr.email<<std::endl;
//若有改变 就赋值给user 否则用原来的值
if(!user.name.empty())l_temp_query_msg.usr.name=user.name;
if(user.sex!=-1)l_temp_query_msg.usr.sex=user.sex;//222222222
if(user.age!=-1)l_temp_query_msg.usr.age=user.age;
if(!user.tel.empty())l_temp_query_msg.usr.tel=user.tel;
if(!user.email.empty())l_temp_query_msg.usr.email=user.email;
if(!user.pers_desc.empty())l_temp_query_msg.usr.pers_desc=user.pers_desc;
std::cout<<std::endl<<"---------------------"<<std::endl<<l_temp_query_msg.usr.email<<std::endl;
sprintf(l_call_cstr, "call pr_updatauser (%d,'%s',%d,'%d','%s','%s','%s');"
,seqId
,CheckStr(l_temp_query_msg.usr.name).c_str()//
,l_temp_query_msg.usr.sex
,l_temp_query_msg.usr.age
,CheckStr(l_temp_query_msg.usr.tel).c_str()
,CheckStr(l_temp_query_msg.usr.email).c_str()
,CheckStr(l_temp_query_msg.usr.pers_desc).c_str());
//----得到一个待修改前完整的user 将未修改的字段也填上 后面存储过程updata无法更新单个或部分字段
pthread_mutex_lock(&l_mysql_mutex);
int32_t l_ret1=mysql_query(l_mysql_connect, l_call_cstr);
if(l_ret1!=0)
{
std::cout<<"call_updatastudent_error 输入参数长度有问题"<<std::endl;
pthread_mutex_unlock(&l_mysql_mutex);
pthread_mutex_unlock(&l_updata_mutex);
return 401;
}
int l_affected_rows=mysql_affected_rows(l_mysql_connect);//这里int型可以在free_result后使用
MYSQL_RES* l_result=mysql_store_result(l_mysql_connect);
mysql_free_result(l_result);
while (!mysql_next_result(l_mysql_connect)) //
{
l_result = mysql_store_result(l_mysql_connect);
mysql_free_result(l_result);
}
pthread_mutex_unlock(&l_mysql_mutex);
pthread_mutex_unlock(&l_updata_mutex);
if(l_affected_rows!=1)
{
std::cout<<"修改错误 本应修改的行数为1,实际值为"<<l_affected_rows<<std::endl;
return 401;
}
// //返回结果测试
// MYSQL_RES* l_result=mysql_store_result(mysql);
// if(l_result==NULL)
// {
// printf("mysql_store_result() 失败了, 原因: %s\n", mysql_error(mysql));
// mysql_free_result(l_result);
// return 402;
// }
// mysql_free_result(l_result);
std::cout<<"成功修改进数据库..插入成功!"<<std::endl;
//-------------------操作数据库部分--------------------
//-------------------操作redis部分--------------------
redisReply *l_reply=NULL;
struct timeval timeout = { 1, 500000 }; // 1.5 seconds
//2写入redis中数据部分
pthread_mutex_lock(&l_redis_mutex);
if(!l_temp_query_msg.usr.pers_desc.empty())
l_reply = (redisReply*)redisCommand(l_redis_connect,"hmset user%d name %s sex %d age %d tel %s email %s pers_desc %s"
,seqId
,l_temp_query_msg.usr.name.c_str()
,l_temp_query_msg.usr.sex
,l_temp_query_msg.usr.age
,l_temp_query_msg.usr.tel.c_str()
,l_temp_query_msg.usr.email.c_str()
,l_temp_query_msg.usr.pers_desc.c_str());
else
l_reply = (redisReply*)redisCommand(l_redis_connect,"hmset user%d name %s sex %d age %d tel %s email %s"
,seqId
,l_temp_query_msg.usr.name.c_str()
,l_temp_query_msg.usr.sex
,l_temp_query_msg.usr.age
,l_temp_query_msg.usr.tel.c_str()
,l_temp_query_msg.usr.email.c_str());
pthread_mutex_unlock(&l_redis_mutex);
if(l_reply==NULL)
{
std::cout<<"reply获取失败"<<std::endl;
//redisFree(connect); //释放redisConnect()所产生的连接。
return 302;
}
else if(l_reply->type!=REDIS_REPLY_STATUS)
{
std::cout<<"reply->type 类型错误"<<std::endl;
freeReplyObject(l_reply);
//redisFree(connect); //释放redisConnect()所产生的连接。
return 303;
}
else if(strncmp("OK",l_reply->str,2)!=0)
{
std::cout<<"数据插入失败"<<std::endl;
freeReplyObject(l_reply);
//redisFree(connect); //释放redisConnect()所产生的连接。
return 304;
}
std::cout<<"成功修改进redis..修改成功!"<<std::endl;
freeReplyObject(l_reply);
//-------------------操作redis部分--------------------
int l_return_pro=Prod2Cons(l_temp_query_msg.usr);
//传递给生产者
if(l_return_pro!=0)
{
std::cout<<"传递给生产者出错..."<<std::endl;
}
std::cout<<"Updata函数结束...\n"<<std::endl;
return 0;
}
//return 501 反序列化失败
//return 502 rd_kafka_conf_set失败
//return 503 rd_kafka_new失败
static void dr_msg_cb(rd_kafka_t *l_rk, const rd_kafka_message_t *l_rkmessage, void *l_opaque)
{
if (l_rkmessage->err)
{
fprintf(stderr,"%% Message delivery failed: %s\n",rd_kafka_err2str(l_rkmessage->err));
}
else
{
fprintf(stderr,"%% Message delivered (%zd bytes, partition %" PRId32 ")\n",
l_rkmessage->len, l_rkmessage->partition);
}
// l_rkmessage 能自动销毁by librdkafka
}
int Prod2Cons(User1 usr)
{
//-----------------------msg to json---------------
Json::Value l_root;
l_root["ID"]=usr.seqId;
l_root["name"]=usr.name;
l_root["sex"]=usr.sex;
l_root["age"]=usr.age;
l_root["tel"]=usr.tel;
l_root["email"]=usr.email;
l_root["pers_desc"]=usr.pers_desc;
//-----------------------msg to json---------------
//-----------------------json to str---------------
Json::StreamWriterBuilder l_swb;
std::shared_ptr <Json::StreamWriter > l_sw(l_swb.newStreamWriter() ) ; //l_sw指向l_l_swb
//通过l_sw的write将l_root序列化成Json字符串,并存储到str中
std::stringstream l_str;
l_sw->write(l_root,&l_str);
std::string l_str_serialization=l_str.str();
char * l_trans_str=(char*)l_str_serialization.data();
//char *str_char=l_str_serialization.c_str();
if(l_trans_str==NULL)
{
std::cout<<"反序列化失败\n"<<std::endl;
return 501;
}
//-----------------------json to str---------------
//-----------------------producer模板---------------
pthread_mutex_lock(&l_kafka_mutex);
/* Signal handler for clean shutdown */
fprintf(stderr,//打印...
"%% Type some text and hit enter to produce message\n"
"%% Or just hit enter to only serve delivery reports\n"
"%% Press Ctrl-C or Ctrl-D to exit\n");
rd_kafka_resp_err_t l_err;//错误代码提示
// SendProduce message.
// 这是一个异步调用,在成功的情况下,只会将消息排入内部producer队列,
// 对broker的实际传递尝试由后台线程处理,之前注册的传递回调函数(dr_msg_cb)
// 用于在消息传递成功或失败时向应用程序发回信号
while(1)
{
l_err=rd_kafka_producev(
l_rk,//顶层对象 的基础容器 用于全局配置和共享状态,之前通过rd_kafka_topic_new()生成
RD_KAFKA_V_TOPIC(l_topic),//topic
RD_KAFKA_V_MSGFLAGS(RD_KAFKA_MSG_F_COPY),//表示librdkafka 在信息发送前立即从 payload 做一份拷贝
RD_KAFKA_V_VALUE(l_trans_str, l_str_serialization.size()),//消息和长度//传信息
RD_KAFKA_V_OPAQUE(NULL),//可选的,应用程序为每个消息提供的无类型指针,提供给消息发送回调函数,用于应用程序引用。
RD_KAFKA_V_END); /* End sentinel */
if(l_err)
{//若该值不是0则为一个错误码
fprintf(stderr,"%% Failed to produce to topic %s: %s\n", l_topic, rd_kafka_err2str(l_err));
if(l_err==RD_KAFKA_RESP_ERR__QUEUE_FULL)
{
//如果内部队列已满,请等待消息传递,然后重试。
//内部队列表示要发送的消息和已经发送或失败的消息,等待调用它们的传递报告回调。
rd_kafka_poll(l_rk,1000 );//阻塞等待消息1000ms至发送完成或其它操作
continue;//再传!
}
}
else
{//若该值为0 传送成功 打印出相应成果
fprintf(stderr,"%% Enqueued message (%zd bytes) for topic %s\n",l_str_serialization.size(), l_topic);
break;
}
}
// producer应用程序应不断地通过以频繁的间隔调用rd_kafka_poll()来为
// 传送报告队列提供服务。在没有生成消息以确定先前生成的消息已发送了其
// 发送报告回调函数(和其他注册过的回调函数)期间,要确保rd_kafka_poll()
// 仍然被调用
rd_kafka_poll(l_rk, 0);
// rd_kafka_flush是rd_kafka_poll()的抽象化,
// 等待所有未完成的produce请求完成,通常在销毁producer实例前完成
// 以确保所有排列中和正在传输的produce请求在销毁前完成
fprintf(stderr, "%% Flushing final messages..\n");
rd_kafka_flush(l_rk,10*1000);
//如果输出队列仍然不为空,则存在向集群生成消息的问题。
if(rd_kafka_outq_len(l_rk)>0)
{
fprintf(stderr,"%% %d message(s) were not delivered\n",rd_kafka_outq_len(l_rk));
}
pthread_mutex_unlock(&l_kafka_mutex);
//-----------------------producer模板---------------
return 0;
}
};
int main() {
int l_thrift_port = 9090;
// ::std::shared_ptr<serDemoHandler> handler(new serDemoHandler());
// ::std::shared_ptr<TProcessor> processor(new serDemoProcessor(handler));
// ::std::shared_ptr<TServerTransport> serverTransport(new TServerSocket(l_thrift_port));
// ::std::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
// ::std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
// TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
// thread pool
::std::shared_ptr<serDemoHandler> handler(new serDemoHandler());
::std::shared_ptr<TProcessor> processor(new serDemoProcessor(handler));
::std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
::std::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
::std::shared_ptr<TServerTransport> serverTransport(new TServerSocket(9090));
// 指定15个线程
::std::shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(15);
::std::shared_ptr<ThreadFactory> threadFactory
= ::std::shared_ptr<ThreadFactory>(new ThreadFactory());
threadManager->threadFactory(threadFactory);
threadManager->start();
std::cout<<"start... "<<std::endl;
TThreadPoolServer server(processor,
serverTransport,
transportFactory,
protocolFactory,
threadManager);
int l_con_return=handler->EstablishConnection();
if(l_con_return!=0)
{
return l_con_return;
}
server.serve();
std::cout<<"end"<<std::endl;
return 0;
// MYSQL* mysql = mysql_init(NULL);
// cout<<1<<endl;
// server.serve();
}
Client
// 在同级目录下创建 client.cpp 文件
// ----------替换成自己的头文件----------
#include "serDemo.h"
// --------------------------------------
#include <thrift/transport/TSocket.h>
#include <iostream>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <map>
#include <string>
#include <pthread.h>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <mysql8/mysql.h>
#include <cstdio>
#include <hiredis.h>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
// using boost::shared_ptr;
// return -2没有该用户id
// return -1id不合法
// return -101 服务端getuser失败
// return 1数据插入数据库失败
// return 2新数据修改数据库vec失败!
// return 3客户端输出失败
// return 4message传入的数值不合法
//seqid为负数也代表相应含义
// return 301 redisContext链接失败
// return 302 reply 获取失败
// return 303 reply->type 类型不对
// return 304 reply 数值不对
// return 401 mysql语句返回错误
// return 402 l_result返回错误
// return 403 判断存储过程中的return是否出错
// return 404 数据库没有该id的数据
// return 405 l_row[0]为null 不该为null的为null
// return 406 初始化mysql失败
// return 407 mysql连接失败
// return 408 mysql affecct_row=0;
// return 501 反序列化失败
// return 502 rd_kafka_conf_set失败
// return 503 rd_kafka_new失败
const int data_size=7;
int32_t OutPut(const User1& user) {
printf("id:%d\nname:%s\nsex:%d\nage:%d\ntel:%s\nemail:%s\npers_desc:%s\n",
user.seqId,user.name.c_str(),user.sex,user.age,user.tel.c_str(),user.email.c_str(),user.pers_desc.c_str());
return 0;
}
int32_t FindUser(serDemoClient client,int32_t l_tmp_seqId)
{
message l_msg_temp;
// Your implementation goes here
printf("正在查询用户...\n");
printf("请输入你想查询的用户id,请键入数字...\n");
if(l_tmp_seqId<0||l_tmp_seqId>=0x7fffffff)
{
printf("用户id不数字非法,请重新键入数字...\n");
return 1;
}
client.QueryUser(l_msg_temp,l_tmp_seqId);
if(l_msg_temp.error_flag==-404)
{
printf("用户id不存在,请重新键入数字...\n");
return 1;
}
else if(l_msg_temp.usr.seqId>0)//这个id既合法也存在
{
}
else
{
printf("用户id输入不合法,请重新键入数字...\n");
return 1;
}
//得到该用户
std::cout<<"客户端展示用户数据中..."<<std::endl;
if(OutPut(l_msg_temp.usr))
{
std::cout<<"客户端展示用户数据失败"<<std::endl;
return 3;
}
std::cout<<"查找用户成功!"<<std::endl;
return 0;
}
int32_t CreateUser(serDemoClient client,User1 user )//
{
//printf("正在创建用户...\n");
int l_check_parameters=0;
//name
if(user.name.size()>20)
{
l_check_parameters=1;
printf("name输入太长,请重新输入!\n");
//printf("用户name输入成功!\n");
}
//sex
if(user.sex!=0&&user.sex!=1)
{
l_check_parameters=1;
printf("sex输入错误,请重新输入!\n");
}
//age
if(user.age>150||user.age<0)
{
printf("age输入错误,请重新输入!\n");
l_check_parameters=1;
}
//tel
for(int i=0;i<user.tel.size();i++)
{
if(user.tel[i]<'0'||user.tel[i]>'9')
{
printf("tel输入非法字符,请重新输入!\n");
l_check_parameters=1;
break;
}
}
if(user.tel.size()>20)
{
printf("tel输入过长错误,请重新输入!\n");
l_check_parameters=1;
}
//email
if(user.email.size()>30)
{
printf("email输入过长错误,请重新输入!\n");
l_check_parameters=1;
}
//pers_desc
// getchar();
// getline(std::cin,l_desc_temp);
if(user.pers_desc.c_str()!=NULL&&user.pers_desc.size()>150)//2222222222
{
printf("personal_describe输入过长错误,请重新输入!\n");
l_check_parameters=1;
}
if(l_check_parameters)
{
return 1;
}
int32_t l_createuser_return=client.InsertUser(user);
//将数据插入数据库
if(l_createuser_return<=0)
{
//插入数据失败!
std::cout<<"数据插入数据库失败!"<<std::endl;
return 1;
}
std::cout<<"创建用户成功!你的用户id是:"<<l_createuser_return<<std::endl;
return 0;
}
int32_t UpdataUser(serDemoClient client,User1 user)
{
int l_change_num=0;//修改的数目
int l_check_parameters=0;//输入的参数是否正确
//name
if(!user.name.empty())
{
if(user.name.size()<=20)
{
l_change_num++;
}
else
{
printf("name输入太长,请重新输入!\n");
l_check_parameters= 1;
}
}
//sex
if(user.sex!=-1)///2222222222222222222222222222222222
{
if(user.sex==0||user.sex==1)
{
l_change_num++;
}
else
{
printf("sex输入错误,请重新输入!\n");
l_check_parameters= 1;
}
}
//age
if(user.age!=-1)//222222222222222222
{
if(user.age<=150&&user.age>=0)
{
l_change_num++;
}
else
{
printf("age输入错误,请重新输入!\n");
l_check_parameters = 1 ;
}
}
//tel
if(!user.tel.empty())
{
if(user.tel.size()>20)
{
printf("tel输入过长错误,请重新输入!\n");
l_check_parameters = 1 ;
}
else
{
for(int i=0;i<user.tel.size();i++)
{
if(user.tel[i]<'0'||user.tel[i]>'9')
{
printf("tel输入非法字符,请重新输入!\n");
l_check_parameters = 1 ;
break;
}
if(i==user.tel.size()-1)
{
l_change_num++;
}
}
}
}
//email
if(!user.email.empty())
{
if(user.email.size()<=30)
{
l_change_num++;
}
else
{
printf("email输入过长错误,请重新输入!\n");
l_check_parameters = 1 ;
}
}
//pers_desc
// getchar();
// getline(std::cin,l_desc_temp);
if(!user.pers_desc.empty())
{
if(user.pers_desc.size()<=150)
{
l_change_num++;
}
else
{
printf("personal_describe输入过长错误,请重新输入!\n");
l_check_parameters = 1 ;
}
}
if(l_check_parameters)
{
std::cout<<"输入的参数错误...!"<<std::endl;
return 1;
}
if(l_change_num<=0)
{
std::cout<<"修改字段数量小于1...!"<<std::endl;
return 1;
}
int32_t l_updatauser_return=client.UpdataUser(user.seqId,user);
//将数据插入数据库
if(l_updatauser_return!=0)
{
//插入数据失败!
std::cout<<"数据更新进数据库失败!"<<std::endl;
return 1;
}
std::cout<<"更新用户成功"<<std::endl;
return 0;
}
int main(int argc,char **argv)
{
std::shared_ptr<TSocket> socket(new TSocket("192.168.48.2", 9090));
std::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
serDemoClient client(protocol);
transport->open();
char *l_operate=NULL;
char *l_id=NULL;
char **l_fields=NULL;
int l_field_nums=0;
User1 user;
std::string l_str_row[7]={"ID","name","sex","age","tel","email","pers_desc"};
if (argc<3)
{
fprintf(stderr,"%% Usage: ""%s Find <ID> \n",argv[0]);
fprintf(stderr,"%% Usage: ""%s Insert <name> <sex> <age> <tel> <email> (<pers_desc>)..\n",argv[0]);
fprintf(stderr,"%% Usage: ""%s Updata <ID> <field1> <content> <field2> <content>... )\n",argv[0]);
printf("退出系统\n");
transport->close();
return 1;
}
l_operate=argv[1];
//--------------find----------
if(strcmp(l_operate,"Find")==0)//find
{
if (argc!=3)
{
fprintf(stderr,"%% Usage: ""%s Find <ID> \n",argv[0]);
printf("退出系统\n");
transport->close();
return 1;
}
l_id=argv[2];
if(FindUser(client,std::stoi(l_id)))
{
fprintf(stderr,"%% Usage: ""%s Find <ID> \n",argv[0]);
printf("退出系统\n");
transport->close();
return 1;
}
}
//----------------insert--------
else if(strcmp(l_operate,"Insert")==0)//insert
{
if (argc!=7&&argc!=8)
{
//输入数量错误
fprintf(stderr,"%% Usage: ""%s Insert <name> <sex> <age> <tel> <email> (<pers_desc>)..\n",argv[0]);
std::cout<<"argc数量错误数量为:"<<argc<<"...\n退出系统\n"<<std::endl;
transport->close();
return 1;
}
user.name=argv[2];
user.sex=std::stoi(argv[3]);
user.age=std::stoi(argv[4]);
user.tel=argv[5];
user.email=argv[6];
if(argc==8)
{
user.pers_desc=argv[7];
}
else
{
//user.pers_desc="NULL";
}
if(CreateUser(client,user))
{
fprintf(stderr,"%% Usage: ""%s Insert <name> <sex> <age> <tel> <email> (<pers_desc>)..\n",argv[0]);
printf("CreateUser 失败...\n退出系统\n");
transport->close();
return 1;
}
}
//------------updata-------
else if(strcmp(l_operate,"Updata")==0)//updata
{
if (argc%2==0||argc>3+(data_size-1)*2)
{
//输入数量错误
fprintf(stderr,"%% Usage: ""%s Updata <ID> <field1> <content> <field2> <content>..\n",argv[0]);
printf("退出系统\n");
transport->close();
return 1;
}
message l_msg;
int l_flag_field=0;
// client.QueryUser(l_msg,std::stoi(argv[2]));//
// if(l_msg.error_flag<0)
// {
// std::cout<<"ID查找错误,错误代码:"<<l_msg.error_flag<<std::endl;
// printf("退出系统\n");
// transport->close();
// return 1;
// }
l_msg.usr.seqId=std::stoi(argv[2]);
l_msg.usr.age=-1;
l_msg.usr.sex=-1;
//给user更新
for(int i=3;i<argc;i+=2)
{
l_flag_field=0;
for(int j=1;j<=data_size-1;j++)
{
if(strcmp(argv[i],l_str_row[j].c_str())==0)
{
l_flag_field=j;
break;
}
}
if(l_flag_field==0)
{
std::cout<<"输入字段名错误: 请输入如下字段<name> <sex> <age> <tel> <email> (<pers_desc>)"<<argv[i]<<std::endl;
printf("退出系统\n");
transport->close();
return 1;
}
switch (l_flag_field)
{
case 1:
l_msg.usr.name=argv[i+1];
break;
case 2:
l_msg.usr.sex=(std::stoi(argv[i+1])==-1?std::stoi(argv[i+1])-1:std::stoi(argv[i+1]));//若用户就输入-1 则-2
break;
case 3:
l_msg.usr.age=(std::stoi(argv[i+1])==-1?std::stoi(argv[i+1])-1:std::stoi(argv[i+1]));//若用户就输入-1 则-2
break;
case 4:
l_msg.usr.tel=argv[i+1];
break;
case 5:
l_msg.usr.email=argv[i+1];
break;
case 6:
l_msg.usr.pers_desc=argv[i+1];
break;
default:
break;
}
}
if(UpdataUser(client,l_msg.usr))
{
printf("退出系统\n");
transport->close();
return 1;
}
}
else //else
{
fprintf(stderr,"%% Usage: ""%s Find <ID> \n",argv[0]);
fprintf(stderr,"%% Usage: ""%s Insert <name> <sex> <age> <tel> <email> (<pers_desc>)..\n",argv[0]);
fprintf(stderr,"%% Usage: ""%s Updata <ID> <field1> <content> <field2> <content>..\n",argv[0]);
}
printf("退出系统\n");
transport->close();
return 0;
}
consumer
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <iostream>
#include <cstdio>
#include <ctype.h>
#include "rdkafka.h"
#include<jsoncpp/json/json.h>
// volatile sig_atomic_t g_run = 1;
// void stop(int sig) {
// g_run = 0;
// }
int is_printable(void *buf1, size_t size)
{
size_t i;
char *l_buf=(char *)buf1;//
for(i=0;i<size;i++)
if(!isprint((int)l_buf[i]))
return 0;
return 1;
}
int main(int argc, char **argv) {
rd_kafka_t *l_rk=NULL; //生产者实例句柄
rd_kafka_conf_t *l_conf=NULL; //临时配置对象
rd_kafka_resp_err_t l_err; // librdkafka API 错误代码
char l_errstr[512]={0}; // librdkafka API 错误缓冲区内容
char *l_brokers=NULL; // broker list
char *l_groupid=NULL; //组id
char **l_topics=NULL; //要订阅的 topic
int l_topic_cnt=0; //要订阅的topic数量
rd_kafka_topic_partition_list_t *l_subscription=NULL;
int i=0;
if (argc<4)
{
fprintf(stderr,"%% Usage: ""%s <broker> <group.id> <topic1> <topic2>..\n",argv[0]);
return 1;
}
l_brokers=argv[1];
l_groupid=argv[2];
l_topics=&argv[3];
l_topic_cnt=argc-3;
l_conf = rd_kafka_conf_new();
//配置设置ip,端口 默认9092
if(rd_kafka_conf_set(l_conf, "bootstrap.servers", l_brokers, l_errstr,sizeof(l_errstr)) != RD_KAFKA_CONF_OK)
{
fprintf(stderr, "%s\n", l_errstr);
//销毁l_conf
rd_kafka_conf_destroy(l_conf);
return 2;
}
//配置消费者组id
//共享相同组id的所有消费者将加入同一个组,订阅的topic'partitions将根据partition.assignment.strategy(消费者配置属性)分配给组中的消费者。
if(rd_kafka_conf_set(l_conf, "group.id", l_groupid, l_errstr,sizeof(l_errstr)) != RD_KAFKA_CONF_OK)
{
fprintf(stderr, "%s\n", l_errstr);
rd_kafka_conf_destroy(l_conf);
return 3;
}
// 如果一个分区之前没有提交偏移量,则auto.offset.reset策略将用于决定在分区的哪个位置开始获取消息。
// 通过将此设置为最早,如果之前没有提交偏移量,消费者将读取分区中的所有消息。
//earliest -> latest
if(rd_kafka_conf_set(l_conf, "auto.offset.reset", "latest", l_errstr,
sizeof(l_errstr)) != RD_KAFKA_CONF_OK) {
fprintf(stderr, "%s\n", l_errstr);
rd_kafka_conf_destroy(l_conf);//
return 4;
}
// 创建使用者实例。实例化一个顶级对象rd_kafka_t作为基础容器,提供全局配置和共享状态
// 注意:rd_kafka_new()拥有conf对象的所有权,在调用后应用程序不能再次引用它。
l_rk = rd_kafka_new(RD_KAFKA_CONSUMER, l_conf, l_errstr, sizeof(l_errstr));
//在分配成功的情况下 这里l_conf的配置临时配置对象其实已经被rd_kafka_new释放
if(!l_rk)
{
fprintf(stderr, "%% Failed to create new consumer: %s\n",l_errstr);
//没分配成功的需要 再手动释放
rd_kafka_conf_destroy(l_conf);
return 5;
}
//rd_kafka_conf_destroy(l_conf);这里不需要再销毁配置对象
l_conf=NULL; //配置对象现在由rd_kafka_t实例拥有和释放
//重定向 rd_kafka_poll()队列到consumer_poll()队列
rd_kafka_poll_set_consumer(l_rk);
//将所有topic list转化为 适合kafka的格式
l_subscription=rd_kafka_topic_partition_list_new(l_topic_cnt);
for (i=0;i<l_topic_cnt;i++)
rd_kafka_topic_partition_list_add(l_subscription, l_topics[i],
/* the partition is ignored
* by subscribe() */RD_KAFKA_PARTITION_UA);
// 订阅 l_topics list
l_err=rd_kafka_subscribe(l_rk, l_subscription);
if (l_err)
{//订阅出错
fprintf(stderr, "%% Failed to subscribe to %d l_topics: %s\n",l_subscription->cnt,rd_kafka_err2str(l_err));
rd_kafka_topic_partition_list_destroy(l_subscription);
rd_kafka_destroy(l_rk);
return 6;
}
fprintf(stderr,"%% Subscribed to %d topic(s),waiting for rebalance and messages...\n",l_subscription->cnt);
rd_kafka_topic_partition_list_destroy(l_subscription);//释放l_topics list使用的所有资源和它自己
// /* Signal handler for clean shutdown */
// signal(SIGINT, stop);
rd_kafka_message_t *l_rkm;
Json::Reader l_reader(Json::Features::strictMode());
Json::Value l_root;
while (1)
{
l_rkm = rd_kafka_consumer_poll(l_rk, 100);//从consumer_poll读取信息
if (!l_rkm)
continue; //超时就重新尝试
//返回错误的信息
if (l_rkm->err)
{
fprintf(stderr, "%% Consumer error: %s\n",
rd_kafka_message_errstr(l_rkm));
rd_kafka_message_destroy(l_rkm);
continue;
}
//正确就如下
//打印 字段 分区 offset等信息
printf("Message on %s [%" PRId32 "] at offset %" PRId64 ":\n",
rd_kafka_topic_name(l_rkm->rkt), l_rkm->partition,
l_rkm->offset);
// /* Print the message key. */
// if (l_rkm->key && is_printable(l_rkm->key, l_rkm->key_len))
// printf(" Key: %.*s\n", (int)l_rkm->key_len,
// (const char *)l_rkm->key);
// else if (l_rkm->key)
// printf(" Key: (%d bytes)\n", (int)l_rkm->key_len);
//打印信息字段
//--------------进行反序列化操作 ---------------
if(l_reader.parse((const char *)l_rkm->payload,l_root)==0)
{
std::cout<<"reader.parse赋值错误!"<<std::endl;
rd_kafka_message_destroy(l_rkm);
continue;
}
std::cout<<"新得到的数据如下"<<std::endl;
if(l_root["ID"]!=Json::nullValue&&l_root["ID"].isInt())
{
std::cout<<"ID:"<<l_root["ID"]<<std::endl;
}
if(l_root["name"]!=Json::nullValue&&l_root["name"].isString())
{
std::cout<<"name:"<<l_root["name"]<<std::endl;
}
if(l_root["sex"]!=Json::nullValue&&l_root["sex"].isInt())
{
std::cout<<"sex:"<<l_root["sex"]<<std::endl;
}
if(l_root["age"]!=Json::nullValue&&l_root["age"].isInt())
{
std::cout<<"age:"<<l_root["age"]<<std::endl;
}
if(l_root["tel"]!=Json::nullValue&&l_root["tel"].isString())
{
std::cout<<"tel:"<<l_root["tel"]<<std::endl;
}
if(l_root["email"]!=Json::nullValue&&l_root["email"].isString())
{
std::cout<<"email:"<<l_root["email"]<<std::endl;
}
if(l_root["pers_desc"]!=Json::nullValue&&l_root["pers_desc"].isString())
{
std::cout<<"pers_desc:"<<l_root["pers_desc"]<<std::endl;
}
// printf("ID:%d\nID:%d\n")
//--------------进行反序列化操作 ---------------
if (l_rkm->payload && is_printable(l_rkm->payload, l_rkm->len))
printf(" Value: %.*s\n", (int)l_rkm->len,(const char *)l_rkm->payload);
else if (l_rkm->payload)
printf(" Value: (%d bytes)\n", (int)l_rkm->len);
rd_kafka_message_destroy(l_rkm);
}
//关闭消费者 离开组
fprintf(stderr, "%% Closing consumer\n");
rd_kafka_consumer_close(l_rk);
//销毁消费者
rd_kafka_destroy(l_rk);
return 0;
}