诚心问心跳包的制作
最近需要制作一个心跳包, 这方面的demo,范例很少。 本菜鸟只要硬着头皮写,现在完成了一部分,
以下是我在别人指导下初步完成的心跳包,还需要完善,对boost熟练的童鞋,帮忙指导一下,去除里面的语法错误。
现在编译不过去。 csdn大牛很多,有空的大牛,帮忙看一下是哪里语法错误了,不胜感激涕零.
服务器功能:
1.发送数据给客户端
2.发送心跳包给客户端,如果断线,则提示,并且删除与客户端通信的会话
3.30秒算是超时, 10秒发送一次心跳包。 发送"heartbeat"给客户端,客户端接受后,再次返回这个数据给服务端,
服务端收到后,进行比较
客户端功能:
1.收到服务端心跳包,做出回应。
2.收到服务端 非心跳包数据,打印或者存盘
顺便提供个思路,客户端收到数据后,是立即回应服务端呢,还是如何处理之, 有时候会收到心跳包,有时候会收到服务端给他的数据。 我在思考,是否客户端也需要开一个定时器什么的,之所以有这个考虑,原因是:
客户端夜需要知道自己是否在线。 当然客户端有个功能:发送数据,可以做出判断,发送失败,那么断定自己掉线。
有经验的大牛,告知一声。谢谢了
代码我只提供了 服务端:
//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;}