libuv UDP開發封裝

#ifndef __CUVUDP__H_
#define __CUVUDP__H_
#include "UvNetBase.h"

struct tagUvUdpPkg {
    struct sockaddr_in stAddr;
    uv_buf_t stBuf;
};

class CUvUdp : public CUvNetBase{
public:
    CUvUdp();
    virtual ~CUvUdp();

public:
    static void RecvCb(uv_udp_t* pHandle, ssize_t nRead, const uv_buf_t* pBuf, const struct sockaddr* pAddr, unsigned iFlag);
    static void NotifySend(uv_async_t* pHandle);
    static void SendCb(uv_udp_send_t* pReq, int iStatus);

public:
    int Start();
    int Close();
    int Send(char* pData, ssize_t iLen, std::string strIp, unsigned short uPort);
    int Send(char* pData, ssize_t iLen, const struct sockaddr* pAddr);

protected:
    virtual int OnRecv(ssize_t nRead, const uv_buf_t* pBuf, const struct sockaddr* pAddr, unsigned iFlag) = 0;
    virtual int OnSend(int iStatus) = 0;

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

protected:
    uv_udp_t* mpUdp;

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

#endif



#include "UvUdp.h"

CUvUdp::CUvUdp(){
    mpUdp = nullptr;
}

CUvUdp::~CUvUdp(){
    if (uv_is_active((uv_handle_t*)&mstUvSendAsync)) {
        uv_close((uv_handle_t*)&mstUvSendAsync, nullptr);
    }

    CleanSendQueue();
}

void CUvUdp::RecvCb(uv_udp_t* pHandle, ssize_t nRead, const uv_buf_t* pBuf, const struct sockaddr* pAddr, unsigned iFlag) {
    if (nRead <= 0){
        return;
    }

    CUvUdp* pUdpSvr = (CUvUdp*)uv_handle_get_data((uv_handle_t*)pHandle);
    if (nullptr != pUdpSvr) {
        pUdpSvr->OnRecv(nRead, pBuf, pAddr, iFlag);
    }
}

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

int CUvUdp::Send(char* pData, ssize_t iLen, std::string strIp, unsigned short uPort) {
    ASSERT_RET_VALUE(nullptr != mpUdp && nullptr != mpUvLoop, 1);

    struct sockaddr_in stAddr;
    uv_ip4_addr(strIp.c_str(), uPort, &stAddr);
    return Send(pData, iLen, (const struct sockaddr*)&stAddr);
}

int CUvUdp::Send(char* pData, ssize_t iLen, const struct sockaddr* pAddr) {
    ASSERT_RET_VALUE(nullptr != mpUdp && nullptr != mpUvLoop && nullptr != pAddr, 1);
    tagUvUdpPkg stTmp;
    stTmp.stBuf.base = (char*)do_malloc(iLen);
    stTmp.stBuf.len = (unsigned long)iLen;
    memcpy(stTmp.stBuf.base, pData, iLen);
    memcpy(&stTmp.stAddr, pAddr, sizeof(stTmp.stAddr));

    mcSendMutex.Lock();
    mqueSendBuf.push(stTmp);
    mcSendMutex.UnLock();
    return uv_async_send(&mstUvSendAsync);
}

void CUvUdp::SendCb(uv_udp_send_t* pReq, int iStatus) {
    if (iStatus < 0) {
        LOG_ERR("Udp Send Error");
    }

    CUvUdp* pUdp = (CUvUdp*)uv_handle_get_data((uv_handle_t*)pReq);
    if (nullptr != pUdp) {
        pUdp->mcSendMutex.Lock();
        tagUvUdpPkg stTmp = pUdp->mqueSendBuf.front();
        DOFREE(stTmp.stBuf.base);
        pUdp->mqueSendBuf.pop();
        pUdp->mcSendMutex.UnLock();

        pUdp->OnSend(iStatus);
        pUdp->DoSend();
    }
}

int CUvUdp::DoSend() {
    memset(&mstWriteBuf, 0, sizeof(mstWriteBuf));
    tagUvUdpPkg stTmp;
    mcSendMutex.Lock();
    if (!mqueSendBuf.empty()) {
        stTmp = mqueSendBuf.front();
        mstWriteBuf.base = stTmp.stBuf.base;
        mstWriteBuf.len = stTmp.stBuf.len;
    }
    mcSendMutex.UnLock();

    if (mstWriteBuf.len <= 0) {
        return 0;
    }

    uv_handle_set_data((uv_handle_t*)&mstUvWriteReq, (void*)this);
    return uv_udp_send(&mstUvWriteReq, mpUdp, &mstWriteBuf, 1, (struct sockaddr*)&stTmp.stAddr, CUvUdp::SendCb);
}

int CUvUdp::Start() {
    ASSERT_RET_VALUE(nullptr != mpUvLoop && nullptr != mpUdp, 1);
    uv_udp_init(mpUvLoop, mpUdp);
    uv_handle_set_data((uv_handle_t*)mpUdp, (void*)this);
    if (musPort > 0) {
        int iRet = uv_udp_bind(mpUdp, (struct sockaddr*)&mstLocalAddr, UV_UDP_REUSEADDR);
        if (iRet < 0) {
            LOG_ERR("uv_udp_bind error:%s,port(%d)", uv_strerror(-iRet), mstLocalAddr.sin_port);
            return 1;
        }
    }
    else {
        uv_udp_set_broadcast(mpUdp, 1);
    }

    int iSockBufLen = (int)(mstUvBuf.iLen - mstUvBuf.iUse);
    uv_recv_buffer_size((uv_handle_t*)mpUdp, &iSockBufLen);
    uv_udp_recv_start(mpUdp, CUvBase::UvBufAlloc, CUvUdp::RecvCb);

    uv_handle_set_data((uv_handle_t*)&mstUvSendAsync, (void*)this);
    uv_async_init(mpUvLoop, &mstUvSendAsync, CUvUdp::NotifySend);

    return DoSend();
}

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

int CUvUdp::Close() {
    ASSERT_RET_VALUE(nullptr != mpUvLoop && nullptr != mpUdp, 1);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章