簡單的c++ UDP類 + 多線程 win32編程

////////////////////////UdpClient.h

#include "Thread.h"

class IUdpRecvCallback
{
public:
    virtual void OnRecv(const char* buf, USHORT len, const char* fromIp, USHORT fromPort) = 0;
};

class CUdpClient : public IRunnable
{
public:
    CUdpClient(IUdpRecvCallback* callback);
    ~CUdpClient();

public:
    BOOL Start(USHORT localPort);
    void Stop();
    BOOL SendTo(const char* buf, USHORT len, const char* remoteIp, USHORT remotePort);

protected:
    virtual void Run()override;

private:
    SOCKET m_sock;
    CThread* m_thread = nullptr;
    BOOL m_running = FALSE;
    IUdpRecvCallback* m_recvCallback = nullptr;
};

////////////////////////UdpClient.cpp

#include "UdpClient.h"
#include <winsock2.h>


#pragma comment(lib, "ws2_32.lib")


CUdpClient::CUdpClient(IUdpRecvCallback* callback)
{
    m_recvCallback = callback;
}


CUdpClient::~CUdpClient()
{
    Stop();
}

BOOL CUdpClient::Start(USHORT localPort)
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    wVersionRequested = MAKEWORD(2, 2);
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0)
    {
        TRACE(_T("WSAStartup error\n"));
        return FALSE;
    }
    if (LOBYTE(wsaData.wVersion) != 2 ||
        HIBYTE(wsaData.wVersion) != 2)
    {
        TRACE(_T("WSAStartup version is not right\n"));
        WSACleanup();
        return FALSE;
    }


    m_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (m_sock == INVALID_SOCKET) {
        TRACE(_T("socket failed with error: %ld\n"), WSAGetLastError());
        WSACleanup();
        return FALSE;
    }

    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(localPort);

    if (-1 == bind(m_sock, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)))
    {
        TRACE(_T("bind failed with error: %ld\n"), WSAGetLastError());
        WSACleanup();
        return FALSE;
    }

    

    int nRecvBuf = 700 * 1024;//設置爲700K
    if (0 != setsockopt(m_sock, SOL_SOCKET, SO_RCVBUF, (const char*)&nRecvBuf, sizeof(int)))
    {
        TRACE(_T("setsockopt buf size failed.\n"), WSAGetLastError());
        return FALSE;
    }


    if (m_thread == nullptr)
    {
        m_thread = new CThread(this);
        m_running = TRUE;
        m_thread->Start();
    }

    return TRUE;
}

void CUdpClient::Stop()
{
    closesocket(m_sock);
    m_sock = INVALID_SOCKET;
    m_running = FALSE;
    m_thread->WaitFinish();
    delete m_thread;
    WSACleanup();
}

BOOL CUdpClient::SendTo(const char * buf, USHORT len, const char* remoteIp, USHORT remotePort)
{
    if (INVALID_SOCKET == m_sock)
    {
        TRACE(_T("socket is invalid.\n"));
        return FALSE;
    }

    sockaddr_in recvAddr;
    int iResult;

    recvAddr.sin_family = AF_INET;
    recvAddr.sin_port = htons(remotePort);
    recvAddr.sin_addr.s_addr = inet_addr(remoteIp);

    iResult = sendto(m_sock,(const char *)buf, len, 0, (SOCKADDR *)& recvAddr, sizeof(recvAddr));
    if (iResult == SOCKET_ERROR) {
        TRACE(_T("sendto failed with error: %d\n"), WSAGetLastError());
        return FALSE;
    }
    return TRUE;
}


static char s_recvBuf[1024];
void CUdpClient::Run()
{
    TRACE(_T("Run\n"));
    while (m_running)
    {
        int bufLen = 1024;
        sockaddr_in senderAddr;
        int senderAddrSize = sizeof(senderAddr);
        int result = recvfrom(m_sock, s_recvBuf, bufLen, 0, (SOCKADDR *)& senderAddr, &senderAddrSize);
        if (result < 0) 
        {
            TRACE(_T("recvfrom failed with error %d\n"), WSAGetLastError());
            continue;
        }
        
        char *fromip = inet_ntoa(senderAddr.sin_addr);
        if (m_recvCallback != nullptr)
        {
            m_recvCallback->OnRecv(s_recvBuf, result, fromip, senderAddr.sin_port);
        }
    }
}

 

////////////////////Thread.h

#pragma once

class IRunnable
{
public:
    virtual void Run() = 0;
};

class CThread
{
public:
    CThread(IRunnable * run);
    ~CThread();

public:
    void Start();
    void WaitFinish();

public:
    IRunnable* m_run = NULL;
    HANDLE m_hThread = NULL;
};

/////////////////////Thread.cpp

CThread::CThread(IRunnable * run)
{
    m_run = run;
}

CThread::~CThread()
{
    ::CloseHandle(m_hThread);
    m_hThread = NULL;
}

static DWORD WINAPI ThreadFunc(LPVOID param)
{
    CThread* thread = (CThread*)param;
    if (thread->m_run != NULL)
    {
        thread->m_run->Run();
    }
    return 0;
}


void CThread::Start()
{
    if (m_hThread == NULL)
    {
        DWORD dwThreadID = 0;
        m_hThread = ::CreateThread(NULL, 0, ThreadFunc, this, 0, &dwThreadID);
    }
}

void CThread::WaitFinish()
{
    if (m_hThread != NULL)
        ::WaitForSingleObject(m_hThread, INFINITE);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章