服务器端开发:
服务器设计框架:
缓解和转发的作用
连接音箱和app
最大一个作用转发
一个app操作音箱
app绑定音箱
服务器类实现:
jsoncpp
libvent
verser.h
#ifndef SERVER_H
#define SERVER_H
#include <event.h>
#define IP "172.17.7.99"
#define PORT 8000
class PlayerServer
{
private:
struct event_base *base; //事件集合
public:
PlayerServer(const char *ip = IP, int port = PORT);
~PlayerServer();
};
#endif
vim server.cpp
#include "server.h"
//初始化构造函数
PlayerServer::PlayerServer(const char *ip, int port)
{
base = event_base_new(); //创建事件集合
struct sockaddr_in server_addr; //服务器ip绑定
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = inet_addr(ip);
//使用libvent
struct evconnlistener *listener = evconnlistener_new_bind(base, listener_cb, base,
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 10, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (NULL == listener)
{
std::cout << "evconnlistener_new_bind error" << std::endl;
}
event_base_dispatch(base); //监听集合
}
PlayerServer::~PlayerServer()
{
//释放两个对象
evconnlistener_free(listener);
event_base_free(base);
}
当有客户端发起连接的时候调用listener_cb回调函数
server.h
private: //作为回调函数使用
static void listener_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr,
server.cpp
void PlayerServer::listener_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int socklen, void *arg)
{
struct event_base *base = (struct event_base *)arg;//事件集合作为参数传入
std::cout << "有客户端连接 " << fd << std::endl;
//创建bufferevent事件,客户端连接一个bev,app连接一个bev base事件集合, fd客户端描述符
struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
if (NULL == bev)
{
std::cout << "bufferevent_socket_new error" << std::endl;
}
bufferevent_setcb(bev, read_cb, NULL, event_cb, base);//调用两个回调函数,有读或者事件调用
bufferevent_enable(bev, EV_READ);//使能bev
}
vim server.h
#ifndef SERVER_H
#define SERVER_H
#include <event.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <string.h>
#include <event2/listener.h>
#include <jsoncpp/json/json.h>
#include <list>
#include <time.h>
#include "player.h"
#include "node.h"
#define IP "172.17.7.99"
#define PORT 8000
class PlayerServer
{
private:
struct event_base *base; //事件集合
struct evconnlistener *listener;
static Player *p;
static std::list<Node> *l;
public:
PlayerServer(const char *ip = IP, int port = PORT);
~PlayerServer();
private: //作为回调函数使用
static void listener_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr,
int socklen, void *arg);
static void read_cb(struct bufferevent *bev, void *ctx);
static void event_cb(struct bufferevent *bev, short what, void *ctx);
};
#endif
server.cpp
void PlayerServer::read_cb(struct bufferevent *bev, void *ctx)//当有客户端连接的可读时候调用该函数
{
struct event_base *base = (struct event_base *)ctx;//事件集合作为参数传入
char buf[1024] = {0};//接收数据
size_t ret = bufferevent_read(bev, buf, sizeof(buf));//从客户端中读取数据
if (ret < 0)
{
std::cout << "bufferevent_read error" << std::endl;
}
}
void PlayerServer::event_cb(struct bufferevent *bev, short what, void *ctx)
{
if (what & BEV_EVENT_EOF)
{
std::cout << "音箱下线" << std::endl;
}
else
{
std::cout << "异常发生" << std::endl;
}
}
在main.cpp创建服务器对象
#include "server.h"
int main()
{
PlayerServer ps;
return 0;
}
服务器数据解析:
这里解析
解析消息
有可能app发过来
有可能音箱发过来
app向服务器发送
音箱向服务器发送
server.h
server.cpp
void PlayerServer::read_cb(struct bufferevent *bev, void *ctx)
{
struct event_base *base = (struct event_base *)ctx;//事件集合
char buf[1024] = {0};//保存客户端数据
size_t ret = bufferevent_read(bev, buf, sizeof(buf));//读取客户端数据
if (ret < 0)
{
std::cout << "bufferevent_read error" << std::endl;
}
std::cout << buf << std::endl;
Json::Reader reader; //解析json
Json::Value val;
bool result = reader.parse(buf, val);//解析val放到buf中
if (!result)
{
std::cout << "解析json出错" << std::endl;
return;
}
char cmd[32] = {0};//获取cmd键值
strcpy(cmd, val["cmd"].asString().c_str());
//app发送的消息
if (!strcmp(cmd, "bind")) //绑定功能
{
Node n;//结构体
n.app_bev = bev;//保存appbev
strcpy(n.app_id, val["appid"].asString().c_str());//获取appid
strcpy(n.device_id, val["deviceid"].asString().c_str());//获取设备id
n.online_flag = 0;//设备是否在线,设备不在线
n.app_online_flag = 1;//app是否在线,app在线
l->push_back(n);//把结构体放入链表中
//回复APP
val["cmd"] = "bind_success";//回复app连接成功
//把Value对象转换成string
std::string str = Json::FastWriter().write(val);
size_t ret = bufferevent_write(bev, str.c_str(), strlen(str.c_str()));//回复给app
if (ret < 0)
{
std::cout << "bufferevent_write error" << std::endl;
}
}
else if (!strcmp(cmd, "search_bind")) //查询是否已经绑定
{
//遍历链表,判断链表中是否存在 appid
std::list<Node>::iterator it;
for (it = l->begin(); it != l->end(); it++)
{
if (!strcmp(it->app_id, val["appid"].asString().c_str()))
{
it->app_bev = bev; //更新 app_bev
it->app_online_flag = 1; //app在线
//appid 存在
val["cmd"] = "reply_bind";
val["result"] = "yes";
break;
}
}
if (it == l->end()) //链表遍历到最后,appid 不存在
{
val["cmd"] = "reply_bind";
val["result"] = "no";
}
std::string str = Json::FastWriter().write(val);
size_t ret = bufferevent_write(bev, str.c_str(), strlen(str.c_str()));
if (ret < 0)
{
std::cout << "bufferevent_write error" << std::endl;
}
}
else if (!strcmp(cmd, "app_start")) //开始播放
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_stop")) //结束播放
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_suspend")) //暂停播放
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_continue")) //继续播放
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_prior")) //上一首
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_next")) //下一首
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_voice_up")) //增加音量
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_voice_down")) //减小音量
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_sequence")) //顺序播放
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_random")) //随机播放
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_circle")) //单曲播放
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_music")) //获取音乐
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_off_line")) //APP下线
{
for (std::list<Node>::iterator it = l->begin(); it != l->end(); it++)
{
if (it->app_bev == bev)
{
it->app_online_flag = 0;
bufferevent_free(it->app_bev);
std::cout << "APP下线" << std::endl;
break;
}
}
}
//音箱发送的消息
else if (!strcmp(cmd, "reply")) //操作成功回复
{
p->player_reply_result(l, bev, val);
}
else if (!strcmp(cmd, "info")) //音箱的保活消息
{
p->player_alive_info(l, bev, val, base);
}
else if (!strcmp(cmd, "reply_status")) //回复播放器状态
{
p->player_reply_result(l, bev, val);
}
else if (!strcmp(cmd, "reply_music")) //返回所有音乐
{
p->player_reply_result(l, bev, val);
}
}
node.h
#ifndef NODE_H
#define NODE_H
#include <event.h>
#include <time.h>
#include <list>
struct Node
{
struct bufferevent *app_bev;
struct bufferevent *device_bev;
char app_id[8];
char device_id[8];
int online_flag; //表示设备是否在线 0 表示不在线
int app_online_flag; //表示app 是否在线//
time_t time;
struct event timeout; //定时器事件
};
typedef struct Node Node;
struct timeout_node
{
std::list<Node> *l;
char id[8];
};
typedef struct timeout_node tNode;
#endif
保活消息
vim player.h
vim player.cpp
判断device id在不在链表
player.h
#ifndef PLAYER_H
#define PLAYER_H
#include <list>
#include "node.h"
#include <event.h>
#include <jsoncpp/json/json.h>
#include <string.h>
#include <time.h>
#include <iostream>
#include <event2/util.h>
#include <stdlib.h>
class Player
{
private:
public:
void player_alive_info(std::list<Node> *l, struct bufferevent *bev, Json::Value val, struct event_base *base);
void player_operation(std::list<Node> *l, struct bufferevent *app_bev, const char *cmd);
void player_reply_result(std::list<Node> *l, struct bufferevent *bev, Json::Value val);
static void timeout_cb(evutil_socket_t fd, short event, void *arg);
};
#endif
player.cpp
#include "player.h"
void Player::player_alive_info(std::list<Node> *l, struct bufferevent *bev, Json::Value val, struct event_base *base)//保活调用
{
char deviceid[8] = {0};//存放涉笔id
strcpy(deviceid, val["deviceid"].asString().c_str());//把客户端的deviceid拷贝到deviceid中
//从链表中查找deviceid
for (std::list<Node>::iterator it = l->begin(); it != l->end(); it++)
{
if (!strcmp(deviceid, it->device_id)) //比较deviceid是否在链表中
{
if (it->online_flag == 0) //表示设备不在线,第一次发送保活消息
{
tNode *t = new tNode;
t->l = l;
strcpy(t->id, deviceid);
event_assign(&(it->timeout), base, -1, EV_PERSIST, timeout_cb, t); //设置事件参数
struct timeval tv;
evutil_timerclear(&tv);
tv.tv_sec = 1; //1秒执行一次
event_add(&(it->timeout), &tv);
it->online_flag = 1; //表示设备在线
}
it->device_bev = bev;
it->time = time(NULL);
std::cout << "收到保活消息 信息更新成功" << std::endl;
return;
}
}
std::cout << "收到保活消息 但是设备未绑定" << std::endl;
}
服务器处理app消息:
app发送开始结束等消息
服务器收到这些消息转发
player.cpp
/*
描述:服务器收到APP消息,转发给音箱
参数:app_bev 对应的是app的bufferevent
*/
void Player::player_operation(std::list<Node> *l, struct bufferevent *app_bev, const char *cmd)
{
Json::Value val;
if (!strcmp(cmd, "app_start"))
{
val["cmd"] = "start";
}
else if (!strcmp(cmd, "app_stop"))
{
val["cmd"] = "stop";
}
else if (!strcmp(cmd, "app_suspend"))
{
val["cmd"] = "suspend";
}
else if (!strcmp(cmd, "app_continue"))
{
val["cmd"] = "continue";
}
else if (!strcmp(cmd, "app_prior"))
{
val["cmd"] = "prior";
}
else if (!strcmp(cmd, "app_next"))
{
val["cmd"] = "next";
}
else if (!strcmp(cmd, "app_voice_up"))
{
val["cmd"] = "voice_up";
}
else if (!strcmp(cmd, "app_voice_down"))
{
val["cmd"] = "voice_down";
}
else if (!strcmp(cmd, "app_sequence"))
{
val["cmd"] = "sequence";
}
else if (!strcmp(cmd, "app_random"))
{
val["cmd"] = "random";
}
else if (!strcmp(cmd, "app_circle"))
{
val["cmd"] = "circle";
}
else if (!strcmp(cmd, "app_music"))
{
val["cmd"] = "music";
}
std::string str = Json::FastWriter().write(val);
size_t ret;
//遍历链表判断是否在线
for (std::list<Node>::iterator it = l->begin(); it != l->end(); it++)
{
if (it->app_bev == app_bev)
{
if (it->online_flag == 1) //在线
{
ret = bufferevent_write(it->device_bev, str.c_str(), strlen(str.c_str()));
if (ret < 0)
{
std::cout << "bufferevent_write error" << std::endl;
}
}
else
{
Json::Value v;
v["cmd"] = "app_reply";
v["result"] = "off_line";
std::string s = Json::FastWriter().write(v);
ret = bufferevent_write(app_bev, s.c_str(), strlen(s.c_str()));
if (ret < 0)
{
std::cout << "bufferevent_write error" << std::endl;
}
}
}
break;
}
}
/*
描述:收到音箱的回复消息,服务器回复APP
参数:bev 对应的是音箱的 bufferevent
*/
void Player::player_reply_result(std::list<Node> *l, struct bufferevent *bev, Json::Value val)
{
char cmd[32] = {0};
strcpy(cmd, val["cmd"].asString().c_str());
if (!strcmp(cmd, "reply"))
{
val["cmd"] = "app_reply";
}
else if (!strcmp(cmd, "reply_music"))
{
val["cmd"] = "app_reply_music";
}
else if (!strcmp(cmd, "reply_status"))
{
val["cmd"] = "app_reply_status";
}
std::string str = Json::FastWriter().write(val);
size_t ret;
//遍历链表,找到 app 对应的 bufferevent
for (std::list<Node>::iterator it = l->begin(); it != l->end(); it++)
{
if (it->device_bev == bev)
{
if (it->app_online_flag == 1)
{
ret = bufferevent_write(it->app_bev, str.c_str(), strlen(str.c_str()));
if (ret < 0)
{
std::cout << "bufferevent_write" << std::endl;
}
}
return;
}
}
std::cout << "app 不存在" << std::endl;
}
void Player::timeout_cb(evutil_socket_t fd, short event, void *arg)
{
std::cout << "定时器事件" << std::endl;
tNode t;
memcpy(&t, arg, sizeof(tNode));
//1、根据 time 判断音箱是否在线
std::list<Node>::iterator it;
for (it = (t.l)->begin(); it != (t.l)->end(); it++)
{
if (!strcmp(it->device_id, t.id))
{
if (time(NULL) - it->time > 1)
{
it->online_flag = 0; //表示不在线
}
else
{
it->online_flag = 1;
}
break;
}
}
//2、如果音箱和 APP 同时在线,则发起状态请求
if (it->app_online_flag == 1 && it->online_flag == 1)
{
Json::Value val;
val["cmd"] = "get";
std::string str = Json::FastWriter().write(val);
size_t ret = bufferevent_write(it->device_bev, str.c_str(), strlen(str.c_str()));
if (ret < 0)
{
std::cout << "bufferevent_write error" << std::endl;
}
}
}
服务器定时任务:
服务器每隔一秒向音响播放播放器状态:
服务器开始定时器
libevent里面有一个定时器任务
思路
所有app 和音响对应关系在链表里面
每个节点都加一个定时器事件
修改一下链表,struct event timeout
定时器不一定启动,音响下线关掉
音响上线,向服务器发送保活消息,第一次发送启动一个定时器,online——flag
vim player.cpp
保活
先判断在不在线,第一次发送保活消息,然后启动定时器。
静态成员函数不能调用非静态成员变量
因为着急春招,写的比较潦草,主要是为了找工作对项目有一个印象,不是很详细,代码自取如下
一、main.cpp
#include "server.h"
int main()
{
PlayerServer ps;
return 0;
}
二、node.h
#ifndef NODE_H
#define NODE_H
#include <event.h>
#include <time.h>
#include <list>
struct Node
{
struct bufferevent *app_bev;
struct bufferevent *device_bev;
char app_id[8];
char device_id[8];
int online_flag; //表示设备是否在线 0 表示不在线
int app_online_flag; //表示app 是否在线//
time_t time;
struct event timeout; //定时器事件
};
typedef struct Node Node;
struct timeout_node
{
std::list<Node> *l;
char id[8];
};
typedef struct timeout_node tNode;
#endif
三、player.cpp
#include "player.h"
void Player::player_alive_info(std::list<Node> *l, struct bufferevent *bev, Json::Value val, struct event_base *base)
{
char deviceid[8] = {0};
strcpy(deviceid, val["deviceid"].asString().c_str());
for (std::list<Node>::iterator it = l->begin(); it != l->end(); it++)
{
if (!strcmp(deviceid, it->device_id))
{
if (it->online_flag == 0) //表示设备不在线,第一次发送保活消息
{
tNode *t = new tNode;
t->l = l;
strcpy(t->id, deviceid);
event_assign(&(it->timeout), base, -1, EV_PERSIST, timeout_cb, t); //设置事件参数
struct timeval tv;
evutil_timerclear(&tv);
tv.tv_sec = 1; //1秒执行一次
event_add(&(it->timeout), &tv);
it->online_flag = 1; //表示设备在线
}
it->device_bev = bev;
it->time = time(NULL);
std::cout << "收到保活消息 信息更新成功" << std::endl;
return;
}
}
std::cout << "收到保活消息 但是设备未绑定" << std::endl;
}
/*
描述:服务器收到APP消息,转发给音箱
参数:app_bev 对应的是app的bufferevent
*/
void Player::player_operation(std::list<Node> *l, struct bufferevent *app_bev, const char *cmd)
{
Json::Value val;
if (!strcmp(cmd, "app_start"))
{
val["cmd"] = "start";
}
else if (!strcmp(cmd, "app_stop"))
{
val["cmd"] = "stop";
}
else if (!strcmp(cmd, "app_suspend"))
{
val["cmd"] = "suspend";
}
else if (!strcmp(cmd, "app_continue"))
{
val["cmd"] = "continue";
}
else if (!strcmp(cmd, "app_prior"))
{
val["cmd"] = "prior";
}
else if (!strcmp(cmd, "app_next"))
{
val["cmd"] = "next";
}
else if (!strcmp(cmd, "app_voice_up"))
{
val["cmd"] = "voice_up";
}
else if (!strcmp(cmd, "app_voice_down"))
{
val["cmd"] = "voice_down";
}
else if (!strcmp(cmd, "app_sequence"))
{
val["cmd"] = "sequence";
}
else if (!strcmp(cmd, "app_random"))
{
val["cmd"] = "random";
}
else if (!strcmp(cmd, "app_circle"))
{
val["cmd"] = "circle";
}
else if (!strcmp(cmd, "app_music"))
{
val["cmd"] = "music";
}
std::string str = Json::FastWriter().write(val);
size_t ret;
//遍历链表判断是否在线
for (std::list<Node>::iterator it = l->begin(); it != l->end(); it++)
{
if (it->app_bev == app_bev)
{
if (it->online_flag == 1) //在线
{
ret = bufferevent_write(it->device_bev, str.c_str(), strlen(str.c_str()));
if (ret < 0)
{
std::cout << "bufferevent_write error" << std::endl;
}
}
else
{
Json::Value v;
v["cmd"] = "app_reply";
v["result"] = "off_line";
std::string s = Json::FastWriter().write(v);
ret = bufferevent_write(app_bev, s.c_str(), strlen(s.c_str()));
if (ret < 0)
{
std::cout << "bufferevent_write error" << std::endl;
}
}
}
break;
}
}
/*
描述:收到音箱的回复消息,服务器回复APP
参数:bev 对应的是音箱的 bufferevent
*/
void Player::player_reply_result(std::list<Node> *l, struct bufferevent *bev, Json::Value val)
{
char cmd[32] = {0};
strcpy(cmd, val["cmd"].asString().c_str());
if (!strcmp(cmd, "reply"))
{
val["cmd"] = "app_reply";
}
else if (!strcmp(cmd, "reply_music"))
{
val["cmd"] = "app_reply_music";
}
else if (!strcmp(cmd, "reply_status"))
{
val["cmd"] = "app_reply_status";
}
std::string str = Json::FastWriter().write(val);
size_t ret;
//遍历链表,找到 app 对应的 bufferevent
for (std::list<Node>::iterator it = l->begin(); it != l->end(); it++)
{
if (it->device_bev == bev)
{
if (it->app_online_flag == 1)
{
ret = bufferevent_write(it->app_bev, str.c_str(), strlen(str.c_str()));
if (ret < 0)
{
std::cout << "bufferevent_write" << std::endl;
}
}
return;
}
}
std::cout << "app 不存在" << std::endl;
}
void Player::timeout_cb(evutil_socket_t fd, short event, void *arg)
{
std::cout << "定时器事件" << std::endl;
tNode t;
memcpy(&t, arg, sizeof(tNode));
//1、根据 time 判断音箱是否在线
std::list<Node>::iterator it;
for (it = (t.l)->begin(); it != (t.l)->end(); it++)
{
if (!strcmp(it->device_id, t.id))
{
if (time(NULL) - it->time > 1)
{
it->online_flag = 0; //表示不在线
}
else
{
it->online_flag = 1;
}
break;
}
}
//2、如果音箱和 APP 同时在线,则发起状态请求
if (it->app_online_flag == 1 && it->online_flag == 1)
{
Json::Value val;
val["cmd"] = "get";
std::string str = Json::FastWriter().write(val);
size_t ret = bufferevent_write(it->device_bev, str.c_str(), strlen(str.c_str()));
if (ret < 0)
{
std::cout << "bufferevent_write error" << std::endl;
}
}
}
四、player.h
#ifndef PLAYER_H
#define PLAYER_H
#include <list>
#include "node.h"
#include <event.h>
#include <jsoncpp/json/json.h>
#include <string.h>
#include <time.h>
#include <iostream>
#include <event2/util.h>
#include <stdlib.h>
class Player
{
private:
public:
void player_alive_info(std::list<Node> *l, struct bufferevent *bev, Json::Value val, struct event_base *base);
void player_operation(std::list<Node> *l, struct bufferevent *app_bev, const char *cmd);
void player_reply_result(std::list<Node> *l, struct bufferevent *bev, Json::Value val);
static void timeout_cb(evutil_socket_t fd, short event, void *arg);
};
#endif
五、server.cpp
#include "server.h"
Player *PlayerServer::p = new Player(); //创建播放器对象
std::list<Node> *PlayerServer::l = new std::list<Node>();
PlayerServer::PlayerServer(const char *ip, int port)
{
base = event_base_new(); //创建事件集合
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = inet_addr(ip);
listener = evconnlistener_new_bind(base, listener_cb, base,
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 10, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (NULL == listener)
{
std::cout << "evconnlistener_new_bind error" << std::endl;
}
event_base_dispatch(base); //监听集合
}
PlayerServer::~PlayerServer()
{
//释放两个对象
evconnlistener_free(listener);
event_base_free(base);
}
void PlayerServer::listener_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int socklen, void *arg)
{
struct event_base *base = (struct event_base *)arg;
std::cout << "有客户端连接 " << fd << std::endl;
//创建bufferevent事件
struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
if (NULL == bev)
{
std::cout << "bufferevent_socket_new error" << std::endl;
}
bufferevent_setcb(bev, read_cb, NULL, event_cb, base);
bufferevent_enable(bev, EV_READ);
}
void PlayerServer::read_cb(struct bufferevent *bev, void *ctx)
{
struct event_base *base = (struct event_base *)ctx;
char buf[1024] = {0};
size_t ret = bufferevent_read(bev, buf, sizeof(buf));
if (ret < 0)
{
std::cout << "bufferevent_read error" << std::endl;
}
std::cout << buf << std::endl;
Json::Reader reader;
Json::Value val;
bool result = reader.parse(buf, val);
if (!result)
{
std::cout << "解析json出错" << std::endl;
return;
}
char cmd[32] = {0};
strcpy(cmd, val["cmd"].asString().c_str());
//app发送的消息
if (!strcmp(cmd, "bind")) //绑定功能
{
Node n;
n.app_bev = bev;
strcpy(n.app_id, val["appid"].asString().c_str());
strcpy(n.device_id, val["deviceid"].asString().c_str());
n.online_flag = 0;
n.app_online_flag = 1;
l->push_back(n);
//回复APP
val["cmd"] = "bind_success";
//把Value对象转换成string
std::string str = Json::FastWriter().write(val);
size_t ret = bufferevent_write(bev, str.c_str(), strlen(str.c_str()));
if (ret < 0)
{
std::cout << "bufferevent_write error" << std::endl;
}
}
else if (!strcmp(cmd, "search_bind")) //查询是否已经绑定
{
//遍历链表,判断链表中是否存在 appid
std::list<Node>::iterator it;
for (it = l->begin(); it != l->end(); it++)
{
if (!strcmp(it->app_id, val["appid"].asString().c_str()))
{
it->app_bev = bev; //更新 app_bev
it->app_online_flag = 1; //app在线
//appid 存在
val["cmd"] = "reply_bind";
val["result"] = "yes";
break;
}
}
if (it == l->end()) //链表遍历到最后,appid 不存在
{
val["cmd"] = "reply_bind";
val["result"] = "no";
}
std::string str = Json::FastWriter().write(val);
size_t ret = bufferevent_write(bev, str.c_str(), strlen(str.c_str()));
if (ret < 0)
{
std::cout << "bufferevent_write error" << std::endl;
}
}
else if (!strcmp(cmd, "app_start")) //开始播放
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_stop")) //结束播放
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_suspend")) //暂停播放
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_continue")) //继续播放
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_prior")) //上一首
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_next")) //下一首
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_voice_up")) //增加音量
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_voice_down")) //减小音量
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_sequence")) //顺序播放
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_random")) //随机播放
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_circle")) //单曲播放
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_music")) //获取音乐
{
p->player_operation(l, bev, cmd);
}
else if (!strcmp(cmd, "app_off_line")) //APP下线
{
for (std::list<Node>::iterator it = l->begin(); it != l->end(); it++)
{
if (it->app_bev == bev)
{
it->app_online_flag = 0;
bufferevent_free(it->app_bev);
std::cout << "APP下线" << std::endl;
break;
}
}
}
//音箱发送的消息
else if (!strcmp(cmd, "reply")) //操作成功回复
{
p->player_reply_result(l, bev, val);
}
else if (!strcmp(cmd, "info")) //音箱的保活消息
{
p->player_alive_info(l, bev, val, base);
}
else if (!strcmp(cmd, "reply_status")) //回复播放器状态
{
p->player_reply_result(l, bev, val);
}
else if (!strcmp(cmd, "reply_music")) //返回所有音乐
{
p->player_reply_result(l, bev, val);
}
}
void PlayerServer::event_cb(struct bufferevent *bev, short what, void *ctx)
{
if (what & BEV_EVENT_EOF)
{
for (std::list<Node>::iterator it = l->begin(); it != l->end(); it++)
{
if (it->device_bev == bev)
{
std::cout << "音箱下线" << std::endl;
it->online_flag = 0; //表示不在线
event_del(&it->timeout); //移除定时器
return;
}
/*if (it->app_bev == bev)
{
std::cout << "APP 下线" << std::endl;
it->app_online_flag = 0;
}*/
}
}
else
{
std::cout << "异常发生" << std::endl;
}
}
六、server.h
#ifndef SERVER_H
#define SERVER_H
#include <event.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <string.h>
#include <event2/listener.h>
#include <jsoncpp/json/json.h>
#include <list>
#include <time.h>
#include "player.h"
#include "node.h"
#define IP "172.17.7.99"
#define PORT 8000
class PlayerServer
{
private:
struct event_base *base; //事件集合
struct evconnlistener *listener;
static Player *p;
static std::list<Node> *l;
public:
PlayerServer(const char *ip = IP, int port = PORT);
~PlayerServer();
private: //作为回调函数使用
static void listener_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr,
int socklen, void *arg);
static void read_cb(struct bufferevent *bev, void *ctx);
static void event_cb(struct bufferevent *bev, short what, void *ctx);
};
#endif