windows下使用WSAEVENTSELECT实现同步发送异步接收

// SyncSocket.h
#pragma once
#include <WinSock2.h>// for socklib
#include <afxmt.h>// for lock
#include <cstdlib>
#include <cstring>
#include <string>



#pragma comment(lib,"ws2_32.lib")
using namespace std;

#define WSA_RET_OK  (0)

#define SS_START    (WM_USER + 100)     
#define SS_END          (SS_START + 100)

#define SS_NOT_INIT     (SS_START + 1)
#define SS_LOAD_LIB_OK  (SS_START + 2)
#define SS_INIT_OK      (SS_END  - 1)


#define ERROR_START     (WM_USER + 1000)
#define ERROR_LOAD_WS32_LIB_FAIL    (ERROR_START + 1)   // 加载网络库失败
#define ERROR_WS32_LIB_VESION_ERROR (ERROR_START + 2)   // 网络库版本不匹配


#define MESSAGE_BUF_LENGTH      (1024*10)


#define REGISTER_SOCKET_EVENTS  (FD_READ | FD_CLOSE)


struct st_socket_event
{
    WSAEVENT    m_sockevent;
    WSAEVENT    m_threadExitEvent;
};

// 辅助的消息类,为了可以在CArray中使用,实现了operator=
class st_sock_message
{
public:
    st_sock_message():m_length(0),m_message(nullptr){}
    st_sock_message(const char *arr, const int len) :m_length(len)
    {
        m_message = new char[m_length];
        memcpy(m_message, arr, sizeof(char)*m_length);
    }

    ~st_sock_message() { delete[] m_message; }

    st_sock_message &operator=(const st_sock_message &rhl)
    {
        if (m_message == rhl.m_message)
        {
            return *this;
        }
        delete[] m_message;
        m_length = rhl.m_length;
        m_message = new char[m_length];
        memcpy(m_message, rhl.m_message, sizeof(char)*m_length);
        return *this;
    }

private:
    int m_length;
    char *m_message;
};


typedef CArray<st_sock_message, st_sock_message &> stSockMessageArray;

class CAsynSocket
{
public:
    CAsynSocket(const string &strIp);
    ~CAsynSocket();

    bool fnConnect();
private:
    bool fnWsaStartUp();        // 加载网络库
    bool fnCreateSockThread();  // 创建后台处理线程
    static DWORD WINAPI fnSocketThreadProc(void *lparam);// 
    bool fnCreateSocket();
    bool fnCreateEvents();
    bool fnOnRead(const int ierrorcode);



    char    m_msgBuf[MESSAGE_BUF_LENGTH];
    SOCKET  m_sockHandle;
    HANDLE  m_hThreadHandle;
    INT     m_nSocketStatus;
    int     m_iErrorCode;
    st_socket_event m_events;
    string m_strIp;
    string m_strPort;
    static const string m_strSplit;
    stSockMessageArray m_sockMessageArray;
    CCriticalSection m_msgLock;     // 锁m_sockMessageArray,防止被同时读写
};
// AsynSocket.cpp
#include "stdafx.h"
#include "AsynSocket.h"

const std::string CAsynSocket::m_strSplit = ":";

CAsynSocket::CAsynSocket(const string &strIp)
{
    string::size_type pos = strIp.find(m_strSplit);
    if (string::npos != pos)
    {
        m_strIp = strIp.substr(pos);
        m_strPort = strIp.substr(pos + 1);
    }
    m_sockHandle = INVALID_SOCKET;
    m_hThreadHandle = NULL;
    m_iErrorCode = ERROR_START;
}

CAsynSocket::~CAsynSocket()
{
}

bool CAsynSocket::fnWsaStartUp()
{
    WSADATA data;
    int iRet = WSAStartup(MAKEWORD(2,2),&data);

    if (iRet != WSA_RET_OK)
    {
        m_iErrorCode = ERROR_LOAD_WS32_LIB_FAIL;
        return false;
    }

    if (HIBYTE(data.wVersion) != 2 || LOBYTE(data.wVersion) != 2)
    {
        WSACleanup();
        m_iErrorCode = ERROR_WS32_LIB_VESION_ERROR;
        return false;
    }

    m_nSocketStatus = SS_LOAD_LIB_OK;
    return true;
}


bool CAsynSocket::fnConnect()
{
    if (!fnWsaStartUp())
    {
        return false;
    }

    if (!fnCreateSockThread())
    {
        return false;
    }

    if (!fnCreateSocket())
    {
        return false;
    }
    return true;
}

bool CAsynSocket::fnCreateSockThread()
{
    if (!fnCreateEvents())
    {
        return false;
    }

    m_hThreadHandle = CreateThread(0, 0, fnSocketThreadProc, this, 0, 0);
    if (m_hThreadHandle == nullptr)
    {
        return false;
    }

    return true;
}

DWORD WINAPI CAsynSocket::fnSocketThreadProc(void *lparam)
{
    CAsynSocket *psocket = (CAsynSocket *)lparam;
    if (psocket == nullptr)
    {
        return false;
    }

    WSAEVENT pevents[] = { psocket->m_events.m_threadExitEvent,psocket->m_events.m_sockevent };
    WSANETWORKEVENTS netevents;
    DWORD dwRet = 0;
    while (true)
    {
        dwRet = WSAWaitForMultipleEvents(2, pevents, FALSE, WSA_INFINITE, FALSE);
        if (dwRet == WSA_WAIT_FAILED)
        {
            break;
        }

        if (dwRet == WSA_WAIT_EVENT_0)//退出线程
        {
            break;
        }

        if (dwRet == (WSA_WAIT_EVENT_0 + 1))
        {
            dwRet = WSAEnumNetworkEvents(psocket->m_sockHandle, psocket->m_events.m_sockevent, &netevents);
            if (dwRet != WSA_RET_OK)
            {
                continue;
            }

            if (netevents.lNetworkEvents & FD_READ)
            {
                psocket->fnOnRead(netevents.iErrorCode[FD_READ_BIT]);
            }

            if (netevents.lNetworkEvents & FD_CLOSE)// 
            {
                break;//做一些退出事件     
            }
        }
    }
    return 0;// 退出时需要关闭套接字、卸载网络库等,自行实现
}

bool CAsynSocket::fnCreateSocket()
{
    if (m_strIp.empty() || m_strPort.empty())
    {
        return false;
    }

    sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(m_strPort.c_str()));
    addr.sin_addr.S_un.S_addr = inet_addr(m_strIp.c_str());
    if (addr.sin_addr.S_un.S_addr == 0xFFFFFFFF)// 忘了那个宏了...
    {
        return false;
    }

    m_sockHandle = socket(AF_INET, SOCK_STREAM, 0);
    if (m_sockHandle == INVALID_SOCKET)
    {
        return false;
    }

    BOOL bOpt = FALSE;
    // 即使调用了closesocket,也只是立即返回,缓冲区的数据将尽可能的发送后再关闭套接字
    if (WSA_RET_OK != setsockopt(m_sockHandle, SOL_SOCKET,SO_DONTLINGER,(const char *)&bOpt,sizeof(bOpt)))
    {
        return false;
    }
    // 
    if (WSA_RET_OK != setsockopt(m_sockHandle, SOL_SOCKET, SO_DONTROUTE, (const char *)&bOpt, sizeof(bOpt)))
    {
        return false;
    }

    if (WSA_RET_OK != setsockopt(m_sockHandle, IPPROTO_TCP, TCP_NODELAY, (const char *)&bOpt, sizeof(bOpt)))
    {
        return false;
    }

    if (WSA_RET_OK != connect(m_sockHandle,(const sockaddr *)&addr,sizeof(addr)))
    {
        return false;
    }
    // 绑定套接字与事件
    if (WSA_RET_OK != WSAEventSelect(m_sockHandle, m_events.m_sockevent, REGISTER_SOCKET_EVENTS))
    {
        return false;
    }

    return true;
}

bool CAsynSocket::fnCreateEvents()
{
    m_events.m_sockevent = WSACreateEvent();
    m_events.m_threadExitEvent = WSACreateEvent();
    if (m_events.m_sockevent == WSA_INVALID_EVENT || m_events.m_threadExitEvent == WSA_INVALID_EVENT)
    {
        return false;
    }

    return true;
}
// 按照自己的需要读取数据,放到消息池中
bool CAsynSocket::fnOnRead(const int ierrorcode)
{
    return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值