LinuxC/C++编程基础(28) “心跳”信息的处理

来源:互联网 发布:怎样合理网络理财 编辑:程序博客网 时间:2024/04/30 03:21

写在前面:前面几篇文字已经把服务器端相关的叙述了,这里再把客户端的给加上

一.client.cpp函数的实现,如下:

1.构造函数的实现,如下:
Client::Client():writable(true){
    if((epfd = epoll_create(MAXEVENTS)) == -1){
        exit(-1);
    }
    if((connfd = epoll_create(MAXEVENTS)) == -1){
        exit(-1);
    }
    tcpfd = ::socket(AF_INET, SOCK_STREAM, 0);
    udpfd = ::socket(AF_INET, SOCK_DGRAM, 0);
    epevent.events = EPOLLET | EPOLLIN | EPOLLOUT;
}

2.连接函数的实现,如下:
void Client::connect(std::string host, int port){
    int rc = 1;
    int flags = 0;
    struct sockaddr_in tcpAddr;
    tcpAddr.sin_family = AF_INET;
    tcpAddr.sin_port = htons(port);

    tcpAddr.sin_addr.s_addr = ::inet_addr(host.c_str());   

    if((rc = ::connect(tcpfd, (struct sockaddr*)&tcpAddr, sizeof(struct sockaddr_in))) < 0){
        printf("[Client::connect] tcp connect failed.\n");
        writable = false;
        rc = 1;
        return;
    }
    if(epoll_ctl(epfd, EPOLL_CTL_ADD, tcpfd, &epevent) == -1){
        printf("[Client::connect] epAdd tcp failed:%s", strerror(errno));
        return;
    }else{
        printf("[Client::connect] epAdd tcp successfully.\n");
    }
}

3.epoll事件的监听,如下:
void Client::epHandle(){
    int n = -1;
    n = epoll_wait(epfd, events, MAXEVENTS, 0);
    for(int i=0;i<n;++i){
        if(events[i].events & (EPOLLERR | EPOLLHUP)){
            printf("[Client::connHandle] epoll err.\n");
            continue;
        }
        if(events[i].events & EPOLLOUT){
#ifdef OPEN_LOG
            printf("[Client::epHandle] EPOLLOUT event happen.\n");
#endif
        }
        if(events[i].events & EPOLLIN){
#ifdef OPEN_LOG
            printf("[Client::epHandle] EPOLLIN event happen.\n");
#endif      
            recvData();
        }
    }
}

4.登录消息的发送,如下:
int Client::sendLoginReq(){
    int rc = 1;
    char buf[50] = {0};
    int offset = 0;
    Json::Value jv;
    Json::FastWriter writer;
    int uri = 3;
    std::string msg = "ustc";
    jv["uri"] = Json::Value(uri);
    jv["msg"] = Json::Value(msg);
    std::string loginReq = writer.write(jv);
    offset += sprintf(buf, "%04d", loginReq.size());
    offset += sprintf(buf+offset, "%s", loginReq.c_str());
#ifdef OPEN_LOG
    printf("[Client::sendLoginReq] loginReq size is %d\n", loginReq.size());
    printf("[Client::sendLoginReq] offset is %d\n", offset);
#endif
    if(writable && (rc = ::send(tcpfd, buf, offset, MSG_DONTWAIT))
            != offset && errno == EAGAIN){
        printf("[Client::sendLoginReq] send EAGAIN, modify writable status.\n");
        writable = false;
        rc = 1;
    }else{
        printf("[Client::sendLoginReq] send loginReq successfully.\n");
    }
    return rc;
}

5.响应消息的实现,如下:
void Client::receiveLoginRes(){
    printf("[Client::receiveLoginRes] handle login res.\n");
}


void Client::receivePingRes(){
    printf("[Client::receivePingRes] handle ping res.\n");
}


void Client::handle(const char* pack, int length){
    Json::Value v;
    Json::Reader reader;
    if(reader.parse(pack, v)){
        int uri = v["uri"].asUInt();
        std::string msg = v["msg"].asString();
        switch(uri){
            case PLoginRes:
                receiveLoginRes();
                break;
            case PPingRes:
                receivePingRes();
                break;
            default:
                printf("[Client::handle] unknown uri:%d\n", uri);
                break;
        }
    }
}


void Client::recvData(){
    int lenExpected = 0;
    int lenRead = 0;
    int rc = 0;
    char buf[BUFFERSIZE] = {0};
    if(tcpfd == -1){
        return;
    }
    if((lenRead =::recv(tcpfd, buf, 4, MSG_DONTWAIT)) != 4){
        printf("[Client::receiveLoginRes] recv bytes is not equal to 4\n");
    }
    lenExpected = getLength(buf);
    if((lenRead = ::recv(tcpfd, buf, lenExpected, MSG_DONTWAIT)) < lenExpected){
        printf("[Client::receiveLoginRes] recv bytes less than expected.\n");
    }
#ifdef OPEN_LOG
    printf("[Client::receiveLoginRes] recv data is %s\n", buf);
#endif
    handle(buf, lenExpected);

}


6.ping心跳信息的发送,如下:
void Client::sendPingReq(){
    int rc = 1;
    char buf[50] = {0};
    int offset = 0;
    Json::Value jv;
    Json::FastWriter writer;
    int uri = 5;
    std::string msg = "linyanwen";
    jv["uri"] = Json::Value(uri);
    jv["msg"] = Json::Value(msg);
    std::string pingReq = writer.write(jv);
#ifdef OPEN_LOG
    printf("[Client::sendPingReq] pingReq size:%d\n", pingReq.size());
    printf("[Client::sendPingReq] json message is %s", pingReq.c_str());
#endif
    offset += sprintf(buf, "%04d", pingReq.size());
    offset += sprintf(buf+offset, "%s", pingReq.c_str());
#ifdef OPEN_LOG
    printf("[Client::sendPingReq] offset size:%d\n", offset);
#endif
    if(writable && (rc = ::send(tcpfd, buf, offset, MSG_DONTWAIT))
            != pingReq.size() && errno == EAGAIN){
        printf("[Client::sendLoginReq] send EAGAIN, modify writable status.\n");
        writable = false;
        rc = 1;
    }else{
    #ifdef OPEN_LOG
        printf("[Client::sendPingReq] send pingReq successfully.\n");
    #endif
    }

}

说明:代码简洁明了,不再赘述

二.main.cpp函数的实现,如下:

#include <Poco/Thread.h>
#include <Poco/Runnable.h>
#include <Poco/Mutex.h>
#include "Timer.h"
#include "client.h"
using Poco::Mutex;
Mutex mutex;
Client cli;
void ping(int){
    Mutex::ScopedLock lock(mutex);
    cli.sendPingReq();
}
void loop(int){
    Mutex::ScopedLock lock(mutex);
    cli.epHandle();
}
class loopThread:public Poco::Runnable{
    virtual void run(){
        printf("[loopThread:run] ~~~~~~ invoke ~~~~~\n");
        while(1){
            loop(1);
        }
    }
};
class pingThread:public Poco::Runnable{
    virtual void run(){
        printf("[pingThread:run] ~~~~~~ invoke ~~~~~\n");
        while(1){
            ping(1);
            sleep(5);
        }
    }
};
int main(int argc, char** argv){
    std::string host = "your server ip address";
    int port = 9999;
    //connect
    cli.connect(host, port);
    //ep listen
    loopThread looper;
    Poco::Thread listenThread("listen");
    listenThread.start(looper);
    //send login req
    cli.sendLoginReq();
    //ping
    pingThread pinger;
    Poco::Thread pingThread("ping");//开辟另外一个线程实现ping信息的发送
    pingThread.start(pinger);
    listenThread.join();
    pingThread.join();
    return 0;
}

.运行结果,如下:

1.客户端运行结果:

2.服务器端运行结果:

说明:服务器端运行结果是3个客户端同时发送ping信息的结果,而客户端这里只给出其中一个的运行结果


转载请注明出处:山水间博客,http://blog.csdn.net/linyanwen99/article/details/8315899

原创粉丝点击