首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

诚意问心跳包的制作

2012-08-01 
诚心问心跳包的制作最近需要制作一个心跳包, 这方面的demo,范例很少。 本菜鸟只要硬着头皮写,现在完成了一

诚心问心跳包的制作
最近需要制作一个心跳包, 这方面的demo,范例很少。 本菜鸟只要硬着头皮写,现在完成了一部分,

以下是我在别人指导下初步完成的心跳包,还需要完善,对boost熟练的童鞋,帮忙指导一下,去除里面的语法错误。

现在编译不过去。 csdn大牛很多,有空的大牛,帮忙看一下是哪里语法错误了,不胜感激涕零.



服务器功能:
1.发送数据给客户端
2.发送心跳包给客户端,如果断线,则提示,并且删除与客户端通信的会话
3.30秒算是超时, 10秒发送一次心跳包。 发送"heartbeat"给客户端,客户端接受后,再次返回这个数据给服务端,
服务端收到后,进行比较

客户端功能:
1.收到服务端心跳包,做出回应。
2.收到服务端 非心跳包数据,打印或者存盘


顺便提供个思路,客户端收到数据后,是立即回应服务端呢,还是如何处理之, 有时候会收到心跳包,有时候会收到服务端给他的数据。 我在思考,是否客户端也需要开一个定时器什么的,之所以有这个考虑,原因是:
客户端夜需要知道自己是否在线。 当然客户端有个功能:发送数据,可以做出判断,发送失败,那么断定自己掉线。

有经验的大牛,告知一声。谢谢了




代码我只提供了 服务端:

C/C++ code
//ClientSession.h#pragma  once#include <boost/shared_ptr.hpp>#include <boost/asio.hpp>#include <boost/asio/deadline_timer.hpp>#include <boost/asio/ip/tcp.hpp>#include <boost/enable_shared_from_this.hpp>#include <boost/asio/buffer.hpp>#include <boost/bind.hpp>#include <boost/thread/thread.hpp>  #include <boost/date_time/posix_time/posix_time.hpp>  #include <list>using boost::shared_ptr;using namespace boost::asio;using boost::enable_shared_from_this;using namespace boost::asio::ip;#define max_len 100#define HEART_BEAT_TIME 10000                //10 秒发一次#define CHAOSHI 30000                        //30秒超时#define XINTIAOBAO        "heartbeat"            //要发送的心跳包的内容typedef shared_ptr<tcp::socket> sock_pt;//一个与客户端通信的会话类,负责发送心跳包,发送数据(非心跳包数据)给客户端,返回客户端是否在线的类class ClientSession : public enable_shared_from_this<ClientSession>{public:    ClientSession(io_service& ioservice, sock_pt sock);    sock_pt socket();    void timeTick(DWORD valTime);            //计时函数      void onRecv();                            //接受客户端发送过来的心跳包    void sendDataToClinet( );                //发送数据给客户端(非心跳包)    bool isClientOnLine();                    //返回客户端在线状态private:    //处理发送数据    void handleSend( boost::system::error_code& error);    //处理客户端发送过来的心跳包    void handleReadHeartBeatPacket(boost::system::error_code &e);    sock_pt m_socket;    char m_sendData[max_len];        //发送的数据    char m_receData[max_len];        //心跳包数据    DWORD m_Time;    bool bIsOnline;                    //是否在线};//ClientSession.cpp#include "ClientSession.h"    ClientSession::ClientSession(io_service& ioservice, sock_pt sock)        :m_socket(sock),m_Time(CHAOSHI),bIsOnline(false)      {        memset(m_sendData, '\0', sizeof(m_sendData));    }    sock_pt ClientSession::socket()    {        return m_socket;    }    void ClientSession::timeTick(DWORD valTime)            //计时函数      {        m_Time-=valTime;                                //减去定时器间隔        if(m_Time%HEART_BEAT_TIME==0)                    //时间到,则发送心跳包        {            m_socket->async_write_some(buffer(XINTIAOBAO, strlen(XINTIAOBAO)+1),                boost::bind(&ClientSession::timeTick, shared_from_this()));        }    }    void ClientSession::onRecv()                        //接受客户端发送过来的心跳包,供server类回调    {        m_socket->async_read_some(boost::asio::buffer(m_receData,max_len),            boost::bind(&ClientSession::handleReadHeartBeatPacket,shared_from_this(),            boost::asio::placeholders::error));    }    void ClientSession::sendDataToClinet( )                //发送数据给客户端(非心跳包)    {        //数据可以来自磁盘里的文件,以下只是个演示        strncpy(m_sendData,"hello",strlen("hello")+1);        m_socket->async_write_some(buffer(m_sendData, max_len),            boost::bind(&ClientSession::handleSend, shared_from_this(), placeholders::error));    }    bool ClientSession::isClientOnLine()                    //返回客户端在线状态    {        return bIsOnline;    }    //处理发送给客户端的数据    void ClientSession::handleSend( boost::system::error_code& error)    {        if (! error)        {            m_socket->async_write_some(buffer(m_sendData, max_len),                  boost::bind(&ClientSession::handleSend, shared_from_this(), placeholders::error));        }        else        {            m_socket->close();        }    }    //处理客户端发送过来的心跳包    void ClientSession::handleReadHeartBeatPacket(boost::system::error_code &e)    {        if(e) //客户端掉线,告诉服务器,去掉该客户端        {            bIsOnline=false;        }        else        {            if( strncmp(m_receData,XINTIAOBAO,strlen(XINTIAOBAO)+1)==0)            {                m_Time=0;                //客户端在线,计时器清零                bIsOnline=true;            }            else                        //目前的程序要么收到,一旦收到错误的,几乎不可能            {            }        }        m_Time=CHAOSHI;                    //再次初始化    }//main.cpp#include "ClientSession.h"                //客户端会话类class serverApp{    typedef boost::shared_ptr<ClientSession> session_ptr;public:    serverApp(io_service& ioservice,tcp::endpoint& endpoint)        :m_ioservice(ioservice),        sessCount(0),        m_acceptor(ioservice, endpoint),        t(m_ioservice,boost::posix_time::seconds(1)) //定时器1秒    {        sock_pt sock(new tcp::socket(ioservice));        m_acceptor.async_accept(*sock, boost::bind(&serverApp::handle_accept, this, placeholders::error, sock));        t.async_wait(boost::bind(&serverApp::checkClient,this));    }private:    void checkClient();                        //检测与客户断通信的socket    void handle_accept(const boost::system::error_code& error, sock_pt sock);    io_service& m_ioservice;    tcp::acceptor m_acceptor;    std::list<session_ptr> session;                //保存会话    int sessCount;    boost::asio::deadline_timer t;                //检测定时器};void serverApp::checkClient()                            //检测与客户断通信的socket{    std::list<session_ptr>::iterator iter=session.begin();    while(iter!=session.end())    {        session_ptr tmpSe=*iter;        if(! tmpSe->isClientOnLine() )        //不在线        {            tmpSe->socket()->close();        //关闭掉线的套接字              iter=session.erase(iter);         // 这里语法错误            std::cout<<"有人掉线"<<std::endl;        }        else                                 //在线,发送心跳包        {            //tmpSe->timeTick(CHAOSHI);            //这里不能再发送心跳包了,因为handle_accept已经发送了        }        ++iter;    }}void serverApp::handle_accept(const boost::system::error_code& error, sock_pt sock){    if (! error)    {        session_ptr new_session(new ClientSession(m_ioservice, sock));        session.push_back(new_session);        new_session->timeTick(1000);    //发送心跳包        new_session->onRecv( );        //处理客户端回应心跳包        new_session->sendDataToClinet( );    //发送数据    }}int main( ){    boost::asio::io_service ios;    serverApp serv(ios, tcp::endpoint(tcp::v4(), 1500));    boost::thread_group tg;    tg.add_thread(new boost::thread(boost::bind(&io_service::run, &ios)));    return 0;} 





[解决办法]
我个人觉得越清晰的流程,越健壮且容易维护。
你的问题我觉得需要以下部件:
1.客户端心跳定时器及超时累加器;
2.服务器端心跳定时器组及超时累加器组(多客户端);
3.心跳包(只有msg head和心跳包标志(用于区别正常数据包),协议自己可以定);

流程:
1.客户端连接确认之后,可由任意一方发起心跳;
2.任意一方收到心跳之后,重置超时定时器,清理超时累加器,回发心跳,以此循环;

难点:
1.心跳包的捕获:可以用心跳标记,或者消息head和end标记以及msg length控制;
2.心跳包的处理时机:心跳包不同于一般数据包,也许你的消息处理流程是线性的,但是心跳包必须立即处理,而不能等待前面的消息完毕了再处理,在超时时间以毫秒为单位的高速系统中基本都会误报超时;
3.确认超时之后的重连恢复处理。

我想到的主要就以上几点,实际开发中肯定会存在其他的问题,但是这几个应该是主要问题了。

如果觉得我说的有用,请给分!哇咔咔咔!

热点排行