libuv TCP开发封装

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lightjia/article/details/84324241

如下是创建TCP服务器

#ifndef __CUVTCPSVR__H_
#define __CUVTCPSVR__H_
#include "UvNetBase.h"
class CUvTcpSvr : public CUvNetBase{
public:
    CUvTcpSvr();
    virtual ~CUvTcpSvr();

public:
    static void ConnCb(uv_stream_t* pHandle, int iStatus);

protected:
    virtual int OnAccept(uv_tcp_t* pUvTcp) = 0;//TODO free pUvTcp
    virtual uv_tcp_t* AllocTcpCli();

protected:
    int Listen(int iBackLog = 5);

protected:
    uv_tcp_t* mpTcpSvr;
};

#endif


#include "UvTcpSvr.h"

CUvTcpSvr::CUvTcpSvr(){
    mpTcpSvr = nullptr;
}

CUvTcpSvr::~CUvTcpSvr(){
}

uv_tcp_t* CUvTcpSvr::AllocTcpCli() {
    uv_tcp_t* pTcpCli = (uv_tcp_t*)do_malloc(sizeof(uv_tcp_t));
    //Can Use Another Loop In SubClass
    uv_tcp_init(GetUvLoop(), pTcpCli);
    return pTcpCli;
}

void CUvTcpSvr::ConnCb(uv_stream_t* pHandle, int iStatus){
    CUvTcpSvr* pTcpSvr = (CUvTcpSvr*)uv_handle_get_data((uv_handle_t*)pHandle);
    if (nullptr != pTcpSvr){
        if (iStatus < 0){
            LOG_ERR("uv_listen error:%s", uv_strerror(-iStatus));
            return;
        }

        uv_tcp_t* pTcpCli = pTcpSvr->AllocTcpCli();
        ASSERT_RET(nullptr != pTcpCli);
        int iRet = uv_accept((uv_stream_t*)pTcpSvr->mpTcpSvr, (uv_stream_t*)pTcpCli);
        if (iRet < 0){
            LOG_ERR("uv_accept error:%s", uv_strerror(-iRet));
            return;
        }

        if (pTcpSvr->OnAccept(pTcpCli) != 0){
            DOFREE(pTcpCli);
        }
    }
}

int CUvTcpSvr::Listen(int iBackLog){
    if (nullptr == mpUvLoop || nullptr == mpTcpSvr){
        return 1;
    }

    uv_handle_set_data((uv_handle_t*)mpTcpSvr, (void*)this);
    uv_tcp_init(mpUvLoop, mpTcpSvr);
    int iRet = uv_tcp_bind(mpTcpSvr, (struct sockaddr*)&mstLocalAddr, SO_REUSEADDR);
    if (iRet < 0){
        LOG_ERR("uv_tcp_bind error:%s", uv_strerror(-iRet));
        return 1;
    }

    return uv_listen((uv_stream_t*)mpTcpSvr, iBackLog, CUvTcpSvr::ConnCb);
}

如下是创建TCP客户端

#ifndef __CUVTCPCLI__H_
#define __CUVTCPCLI__H_
#include "UvNetBase.h"
#include <queue>
class CUvTcpCli : public CUvNetBase{
public:
    CUvTcpCli();
    virtual ~CUvTcpCli();

public:
    static void RecvCb(uv_stream_t* pHandle, ssize_t nRead, const uv_buf_t* pBuf);
    static void ConnCb(uv_connect_t* pReq, int iStatus);
    static void SendCb(uv_write_t* pReq, int iStatus);
    static void CloseCb(uv_handle_t* pHandle);
    static void NotifySend(uv_async_t* pHandle);

public:
    void SetTcpCli(uv_tcp_t* pTcpCli);
    int Connect(std::string strIp, unsigned short sPort);
    int Send(char* pData, ssize_t iLen);

protected:
    int Close();

private:
    int AfterConn();
    int Recv();
    int DoSend();
    void CleanSendQueue();

protected:
    virtual int OnRecv(ssize_t nRead, const uv_buf_t* pBuf) = 0;
    virtual int OnConn(int iStatus) = 0;
    virtual int OnClose() = 0;
    virtual int OnSend(int iStatus) = 0;

protected:
    uv_tcp_t* mpTcpCli;
    uv_connect_t* mpUvConn;

private:
    uv_async_t mstUvSendAsync;
    std::queue<uv_buf_t> mqueSendBuf;
    CUvMutex mcSendMutex;
    uv_write_t mstUvWriteReq;
    uv_buf_t mstWriteBuf;
};

#endif


#include "UvTcpCli.h"

CUvTcpCli::CUvTcpCli(){
    mpTcpCli = nullptr;
    mpUvConn = nullptr;
    memset(&mstUvWriteReq, 0, sizeof(mstUvWriteReq));
    memset(&mstWriteBuf, 0, sizeof(mstWriteBuf));
}

CUvTcpCli::~CUvTcpCli(){
    CleanSendQueue();
}

void CUvTcpCli::RecvCb(uv_stream_t* pHandle, ssize_t nRead, const uv_buf_t* pBuf){
    CUvTcpCli* pTcpCli = (CUvTcpCli*)uv_handle_get_data((uv_handle_t*)pHandle);
    if (nullptr != pTcpCli){
        if (nRead == 0){
            if (!uv_is_active((uv_handle_t*)pTcpCli->mpTcpCli)){
                LOG_ERR("Cli is Closed!");
            }

            return;
        }
        
        if (nRead < 0) {
            pTcpCli->Close();
            return;
        } else if (nRead > 0) {
            pTcpCli->OnRecv(nRead, pBuf);
        }
    }
}

void CUvTcpCli::SetTcpCli(uv_tcp_t* pTcpCli) {
    ASSERT_RET(nullptr != mpUvLoop);
    mpTcpCli = pTcpCli;
    uv_handle_set_data((uv_handle_t*)mpTcpCli, (void*)this);
    AfterConn();
}

int CUvTcpCli::AfterConn() {
    Recv();
    uv_handle_set_data((uv_handle_t*)&mstUvSendAsync, (void*)this);
    return uv_async_init(mpUvLoop, &mstUvSendAsync, CUvTcpCli::NotifySend);
}

void CUvTcpCli::ConnCb(uv_connect_t* pReq, int iStatus){
    CUvTcpCli* pTcpCli = (CUvTcpCli*)uv_handle_get_data((uv_handle_t*)pReq);
    if (nullptr != pTcpCli){
        if (iStatus >= 0) {
            pTcpCli->AfterConn();
        }

        pTcpCli->OnConn(iStatus);
        pTcpCli->DoSend();
    }
}

int CUvTcpCli::Connect(std::string strIp, unsigned short sPort){
    if (nullptr == mpTcpCli || nullptr == mpUvLoop || nullptr == mpUvConn){
        return 1;
    }

    uv_handle_set_data((uv_handle_t*)mpTcpCli, (void*)this);
    uv_tcp_init(mpUvLoop, mpTcpCli);
    if (musPort > 0) {
        int iRet = uv_tcp_bind(mpTcpCli, (struct sockaddr*)&mstLocalAddr, SO_REUSEADDR);
        if (iRet < 0){
            LOG_ERR("uv_tcp_bind error:%s", uv_strerror(-iRet));
            return 1;
        }
    }

    struct sockaddr_in stRemoteAddr;
    uv_ip4_addr(strIp.c_str(), sPort, &stRemoteAddr);
    uv_handle_set_data((uv_handle_t*)mpUvConn, (void*)this);
    return uv_tcp_connect(mpUvConn, mpTcpCli, (struct sockaddr*)&stRemoteAddr, CUvTcpCli::ConnCb);
}

int CUvTcpCli::Recv() {
    if (nullptr == mpTcpCli || nullptr == mpUvLoop) {
        return 1;
    }

    int iSockBufLen = (int)(mstUvBuf.iLen - mstUvBuf.iUse);
    uv_recv_buffer_size((uv_handle_t*)mpTcpCli, &iSockBufLen);
    return uv_read_start((uv_stream_t*)mpTcpCli, CUvBase::UvBufAlloc, CUvTcpCli::RecvCb);
}

void CUvTcpCli::SendCb(uv_write_t* pReq, int iStatus) {
    CUvTcpCli* pTcpCli = (CUvTcpCli*)uv_handle_get_data((uv_handle_t*)pReq);
    if (nullptr != pTcpCli)
    {
        pTcpCli->mcSendMutex.Lock();
       if (!pTcpCli->mqueSendBuf.empty()) {
            uv_buf_t stTmp = pTcpCli->mqueSendBuf.front();
            DOFREE(stTmp.base);
            pTcpCli->mqueSendBuf.pop();
        }
        pTcpCli->mcSendMutex.UnLock();

        pTcpCli->OnSend(iStatus);
        if (iStatus < 0) {
            if (iStatus == UV_ECANCELED) {
                return;
            }

            LOG_ERR("uv_write:%s", uv_strerror(-iStatus));
            pTcpCli->Close();
        }
        else
        {
            pTcpCli->DoSend();
        }
    }
}

void CUvTcpCli::NotifySend(uv_async_t* pHandle){
    CUvTcpCli* pTcpCli = (CUvTcpCli*)uv_handle_get_data((uv_handle_t*)pHandle);
    if (nullptr != pTcpCli){
        pTcpCli->DoSend();
    }
}

int CUvTcpCli::DoSend() {
    memset(&mstWriteBuf, 0, sizeof(mstWriteBuf));
    mcSendMutex.Lock();
    if (!mqueSendBuf.empty()) {
        uv_buf_t stTmp = mqueSendBuf.front();
        mstWriteBuf.base = stTmp.base;
        mstWriteBuf.len = stTmp.len;
    }
    mcSendMutex.UnLock();
    
    if (mstWriteBuf.len <= 0) {
        return 0;
    }

    uv_handle_set_data((uv_handle_t*)&mstUvWriteReq, (void*)this);
    return uv_write(&mstUvWriteReq, (uv_stream_t*)mpTcpCli, &mstWriteBuf, 1, CUvTcpCli::SendCb);
}

int CUvTcpCli::Send(char* pData, ssize_t iLen){
    if (nullptr == pData || iLen <= 0 || nullptr == mpTcpCli || nullptr == mpUvLoop || uv_is_closing((uv_handle_t*)&mstUvWriteReq) != 0) {
        return 1;
    }

    uv_buf_t stTmp;
    stTmp.base = (char*)do_malloc(iLen);
    stTmp.len = (unsigned long)iLen;
    memcpy(stTmp.base, pData, iLen);
    mcSendMutex.Lock();
    mqueSendBuf.push(stTmp);
    mcSendMutex.UnLock();
    return uv_async_send(&mstUvSendAsync);
}

void CUvTcpCli::CleanSendQueue(){
    mcSendMutex.Lock();
    while (!mqueSendBuf.empty()){
        uv_buf_t stTmp = mqueSendBuf.front();
        DOFREE(stTmp.base);
        mqueSendBuf.pop();
    }
    mcSendMutex.UnLock();
}

void CUvTcpCli::CloseCb(uv_handle_t* pHandle){
    CUvTcpCli* pTcpCli = (CUvTcpCli*)uv_handle_get_data((uv_handle_t*)pHandle);
    if (nullptr != pTcpCli){
        pTcpCli->OnClose();
    }
}

int CUvTcpCli::Close() {
    if (nullptr == mpTcpCli || nullptr == mpUvLoop || uv_is_closing((uv_handle_t*)mpTcpCli) != 0) {
        return 1;
    }

    if (uv_is_active((uv_handle_t*)&mstUvSendAsync) != 0) {
        uv_close((uv_handle_t*)&mstUvSendAsync, nullptr);
    }
   
    uv_close((uv_handle_t*)mpTcpCli, CUvTcpCli::CloseCb);
    CleanSendQueue();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lightjia/article/details/84324241
今日推荐