服务器端开发:
服务器设计框架:
缓解和转发的作用
连接音箱和app
最大一个作用转发
一个app操作音箱
app绑定音箱
服务器类实现:
jsoncpp
libvent
verser.h
#ifndef SERVER_H
#define SERVER_H#include #define IP "172.17.7.99"
#define PORT 8000class 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);
//使用libventstruct 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "player.h"
#include "node.h"#define IP "172.17.7.99"
#define PORT 8000class PlayerServer
{
private:struct event_base *base; //事件集合struct evconnlistener *listener;static Player *p;static std::list *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; //解析jsonJson::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;//保存appbevstrcpy(n.app_id, val["appid"].asString().c_str());//获取appidstrcpy(n.device_id, val["deviceid"].asString().c_str());//获取设备idn.online_flag = 0;//设备是否在线,设备不在线n.app_online_flag = 1;//app是否在线,app在线l->push_back(n);//把结构体放入链表中//回复APPval["cmd"] = "bind_success";//回复app连接成功//把Value对象转换成stringstd::string str = Json::FastWriter().write(val);size_t ret = bufferevent_write(bev, str.c_str(), strlen(str.c_str()));//回复给appif (ret < 0){std::cout << "bufferevent_write error" << std::endl;}}else if (!strcmp(cmd, "search_bind")) //查询是否已经绑定{//遍历链表,判断链表中是否存在 appidstd::list::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_bevit->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::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
#include
#include 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 *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
#include "node.h"
#include
#include
#include
#include
#include
#include
#include class Player
{
private:public:void player_alive_info(std::list *l, struct bufferevent *bev, Json::Value val, struct event_base *base);void player_operation(std::list *l, struct bufferevent *app_bev, const char *cmd);void player_reply_result(std::list *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 *l, struct bufferevent *bev, Json::Value val, struct event_base *base)//保活调用
{char deviceid[8] = {0};//存放涉笔idstrcpy(deviceid, val["deviceid"].asString().c_str());//把客户端的deviceid拷贝到deviceid中//从链表中查找deviceidfor (std::list::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 *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::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 *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 对应的 buffereventfor (std::list::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::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
保活
先判断在不在线,第一次发送保活消息,然后启动定时器。
静态成员函数不能调用非静态成员变量
#include "server.h"int main()
{PlayerServer ps;return 0;
}
#ifndef NODE_H
#define NODE_H#include
#include
#include 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 *l;char id[8];
};
typedef struct timeout_node tNode;#endif
#include "player.h"void Player::player_alive_info(std::list *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::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 *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::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 *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 对应的 buffereventfor (std::list::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::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;}}
}
#ifndef PLAYER_H
#define PLAYER_H#include
#include "node.h"
#include
#include
#include
#include
#include
#include
#include class Player
{
private:public:void player_alive_info(std::list *l, struct bufferevent *bev, Json::Value val, struct event_base *base);void player_operation(std::list *l, struct bufferevent *app_bev, const char *cmd);void player_reply_result(std::list *l, struct bufferevent *bev, Json::Value val);static void timeout_cb(evutil_socket_t fd, short event, void *arg);
};#endif
#include "server.h"Player *PlayerServer::p = new Player(); //创建播放器对象
std::list *PlayerServer::l = new std::list();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);//回复APPval["cmd"] = "bind_success";//把Value对象转换成stringstd::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")) //查询是否已经绑定{//遍历链表,判断链表中是否存在 appidstd::list::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_bevit->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::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::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;}
}
#ifndef SERVER_H
#define SERVER_H#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "player.h"
#include "node.h"#define IP "172.17.7.99"
#define PORT 8000class PlayerServer
{
private:struct event_base *base; //事件集合struct evconnlistener *listener;static Player *p;static std::list *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