六、服务端开发

服务器端开发:

服务器设计框架:

缓解和转发的作用

连接音箱和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
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值