码迷,mamicode.com
首页 > Windows程序 > 详细

win-socket类

时间:2018-08-25 14:16:03      阅读:259      评论:0      收藏:0      [点我收藏+]

标签:校验码   tags   private   列表   ==   nts   检测   server   ldb   

#pragma once
#pragma warning(disable: 4786)


#include "winsock2.h"
#include <map>
using namespace std;

#define MAX_CONNECTION_NUMBER    2 // 最大连接数

typedef struct tagSvrSocket
{
    int     objectId;    // 对象编号
    int     port;        // Socket端口号
    char    ip[20];      // IP地址
    bool    bRegister;   // 注册
    bool    bTrace;      // 跟踪
    SOCKET  sock;        // Socket

    tagSvrSocket()
    {
        objectId    = 0;
        sock        = NULL;
        port        = 0;
        bRegister    = false;
        bTrace        = false;
        memset(ip, 0, sizeof(ip));
    }
} SvrSocket, *LPSvrSocket;

typedef map<SOCKET, LPSvrSocket> MapSvrSocket,*LPMapSvrSocket;
typedef MapSvrSocket::value_type vtSvrSocket;
typedef MapSvrSocket::iterator itSvrSocket;

class CServerSocket
{
public:
    CServerSocket(void);
public:
    ~CServerSocket(void);

public:
    SOCKET            m_hSocket;                    // 监听socket 句柄
    SOCKET            m_hClientSocketLast;          // 客户端最后一次连接的socket 句柄
    
    sockaddr_in       m_addr;                       // 每次客户端连接时,客户端的地址
    UINT              m_uPort;                      // 端口号
    BOOL              m_bInit;                      // 初始化winsock的信号
    MapSvrSocket      m_mapSvrSocket;               // 客户端的winsock的map

    CRITICAL_SECTION m_CriticalSection;

public:
    int InitAndListen(UINT nPort);
    virtual int CheckSocketReadable(SOCKET sock);
    virtual int CheckSocketWriteable(SOCKET sock);
    virtual int SendMsg(char *buff, USHORT len, SOCKET sock);
    virtual int ReceiveMsg(char* buff, SOCKET sock);
    virtual void CloseClientSocket(SOCKET sock);
    void GetSvrSockMap(MapSvrSocket & mapSevSocket);

private:
    int InitSocket();
    void GetError(DWORD error);
};

 

#include "StdAfx.h"
#include "ServerSocket.h"

#define PACKHEAD_LEN            22
#define MAXDELAYTIME            2        // 最大延时2秒
#define MAX_LEN                 1024     // 最大长度

CServerSocket::CServerSocket(void)
{
    m_bInit = TRUE;
    m_hSocket = NULL;
    m_hClientSocketLast = NULL;
    m_uPort = 0;

    InitSocket();
    InitializeCriticalSection(&m_CriticalSection);
}

CServerSocket::~CServerSocket(void)
{
    for (itSvrSocket itsvrsock = m_mapSvrSocket.begin();
         itsvrsock != m_mapSvrSocket.begin(); ++itsvrsock)
    {
        LPSvrSocket pSvrSocket = (LPSvrSocket)itsvrsock->second;
        CloseClientSocket(pSvrSocket->sock);
    }

    WSACleanup();
    DeleteCriticalSection(&m_CriticalSection);
}

/* ===========================================
初始化

参数:
    无
返回值:
    0 成功.
    1 失败,在返回1以前,显示错误原因。
*///==========================================
int CServerSocket::InitSocket()
{

    WSADATA wsaData;
    WORD version = MAKEWORD(2,2);

    int ret = WSAStartup(version, &wsaData);
    if (ret != 0)
    {
        TRACE("Initilize Error!\n");
        m_bInit = FALSE;
        TRACE("socket 初始化错误\r\n");
    }

    return ret;
}

/* ==========================================
服务侦听函数,绑定端口等待连接

参数:
    nPort:服务器端口号
返回值:
    0 成功.
    -1 失败在返回1以前,显示错误原因。
*///=========================================
int CServerSocket::InitAndListen(UINT nPort)
{
    SOCKET tmpsock;

    if (!m_bInit)
        return -2;

    if (m_hSocket == NULL)
    {
        m_hSocket = socket(AF_INET, SOCK_STREAM, 0);
        ASSERT(m_hSocket != NULL);

        m_addr.sin_family = AF_INET;
        m_addr.sin_addr.S_un.S_addr = INADDR_ANY;
        m_addr.sin_port = htons(nPort);

        int ret = 0;
        int error = 0;

        // 绑定一个套接字到本机地址
        ret = bind(m_hSocket, (LPSOCKADDR)&m_addr, sizeof(m_addr));

        if (ret == SOCKET_ERROR)
        {
            closesocket(m_hSocket);
            m_hSocket = NULL;
            GetError(GetLastError());
            return -1;
        }

        // 开始侦听过程,等待客户的连接
        ret = listen(m_hSocket, 5);
        if (ret == SOCKET_ERROR)
        {
            closesocket(m_hSocket);
            m_hSocket = NULL;
            GetError(GetLastError());
            return -1;
        }
    }

    SOCKADDR_IN saddr;
    int len = sizeof(saddr);
    tmpsock = accept(m_hSocket, (PSOCKADDR)&saddr, &len);

    if (tmpsock == INVALID_SOCKET)
    {
        GetError(GetLastError());
        return -1;
    }

    CString strIP;
    strIP.Format(inet_ntoa(saddr.sin_addr));

    // 连接数是否最大
    EnterCriticalSection(&m_CriticalSection);

    if (m_mapSvrSocket.size() < MAX_CONNECTION_NUMBER)
    {
        // 保存最后一次连接成功的CDU的SOCKECT信息
        m_hClientSocketLast = tmpsock;

        LPSvrSocket pSvrSocket = new SvrSocket;
        pSvrSocket->sock = tmpsock;
        pSvrSocket->port = saddr.sin_port;
        strcpy(pSvrSocket->ip, strIP);

        m_mapSvrSocket.insert(vtSvrSocket(tmpsock, pSvrSocket));
        LeaveCriticalSection(&m_CriticalSection);
    }
    else
    {
        GetError(100);
        LeaveCriticalSection(&m_CriticalSection);
        return -3;
    }

    return 0;
}


/* ==============
函数功能:检测套接字是否可读
参数:
    无
返回值:
0 可读
    其他数值不可读
*///=============
int CServerSocket::CheckSocketReadable(SOCKET sock)
{
    fd_set fdset;
    struct timeval tv;
    tv.tv_sec=0;
    tv.tv_usec=1000;
    FD_ZERO(&fdset);
    FD_SET(sock,&fdset);

    int iRet = select(sock + 1, &fdset, NULL, NULL, &tv);
    if (iRet == 0)
    {
        return -1;
    }

    return 0;
}

/* ==============
函数功能:检测套接字是否可写
参数:
    无
返回值:
    0 可写
其他数值不可写
*///=============
int CServerSocket::CheckSocketWriteable(SOCKET sock)
{
    fd_set fdset;
    struct timeval tv;
    tv.tv_sec=0;
    tv.tv_usec=5000;
    FD_ZERO(&fdset);
    FD_SET(sock,&fdset);

    int iRet = select(sock + 1, NULL, &fdset, NULL, &tv);
    if (iRet == 0)
    {
        return -1;
    }
    return 0;
}

/* ==============
发送消息函数 参数: buff:发送的数据缓冲区。 返回值: 0 成功. -1 失败
*///============= int CServerSocket::SendMsg(char *buff, USHORT len, SOCKET sock) { ASSERT(buff != NULL); if (!m_bInit) return -1; int end = send(sock, buff, len, 0); if (end == SOCKET_ERROR) { GetError(GetLastError()); return -1; } return end; } /* ============== 接收发来的消息 参数: buff: 接收到的数据,即填满实参内存,实参需要是一个已经分配内存的缓冲区. whichSocket: 表示哪一个套接字开始接收,对应于m_SvrSocketBody的下标。 返回值: ret 成功,数据包长度. 负数 失败,在返回以前,显示错误原因。 *///============= int CServerSocket::ReceiveMsg(char* buff, SOCKET sock) { ASSERT(buff != NULL); if (!m_bInit) return -4; int iTotal = 0; int iRet = 0; time_t startTime = time(NULL); while (1) {// 收取包头标志4A 79 iRet = recv(sock, buff+iTotal, 1, 0); if (iRet <= 0) { return -1; } if (*(char*)buff == 0x4A) { iTotal = 1; iRet = recv(sock, buff+iTotal, 1, 0); if (iRet <= 0) { return -1; } if (*(char*)(buff+1) == 0x79) { iTotal = 2; break; } } iTotal = 0; if (time(NULL) - startTime > MAXDELAYTIME) { // printf("接收报头文超时\n"); return -2; } } iRet = recv(sock, buff+iTotal, PACKHEAD_LEN - 2, 0); // 收取包头 if (iRet <= 0) { return -1; } iTotal = iTotal + iRet; USHORT nDataLen = *(USHORT*)(buff+PACKHEAD_LEN-2); // 数据长度 if (nDataLen > MAX_LEN) { return -3; } startTime = time(NULL); iRet = 0; int nCheck = 0; while (1) { iRet = recv(sock, buff+iTotal, 2+nDataLen-nCheck, 0); // 收取数据和校验码 if (iRet <= 0) { return -1; } iTotal = iTotal + iRet; nCheck += iRet; if (nCheck == nDataLen + 2) break; if (time(NULL) - startTime > MAXDELAYTIME) { return -4; } } return iTotal; } /* ============== 获取SOCKET列表信息 参数: mapSevSocket:SOCKET信息结构 返回值: 无 *///============= void CServerSocket::GetSvrSockMap(MapSvrSocket & mapSevSocket) { EnterCriticalSection(&m_CriticalSection); mapSevSocket = m_mapSvrSocket; LeaveCriticalSection(&m_CriticalSection); } /* ============== 关闭Socket连接 返回值: sock SOCKET套接字 参数: 无 *///============= void CServerSocket::CloseClientSocket(SOCKET sock) { EnterCriticalSection(&m_CriticalSection); itSvrSocket itSocket = m_mapSvrSocket.find(sock); if (itSocket != m_mapSvrSocket.end()) { delete (LPSvrSocket)itSocket->second; m_mapSvrSocket.erase(itSocket); } closesocket(sock); LeaveCriticalSection(&m_CriticalSection); } /* ============== 服务器接收消息函数。 参数: buff: 接收到的数据,即填满实参内存,实参需要是一个已经分配内存的缓冲区. whichSocket: 表示哪一个套接字开始接收,对应于m_SvrSocketBody的下标。 返回值: 0 成功. 1 失败,在返回1以前,显示错误原因。 *///============= void CServerSocket::GetError(DWORD error) { char strError[256] = {\0}; switch(error) { case WSANOTINITIALISED: strcpy(strError,"初始化错误"); break; case WSAENOTCONN: strcpy(strError,"对方没有启动"); break; case WSAEWOULDBLOCK : strcpy(strError,"对方已经关闭"); break; case WSAECONNREFUSED: strcpy(strError,"连接的尝试被拒绝"); break; case WSAENOTSOCK: strcpy(strError,"在一个非套接字上尝试了一个操作"); break; case WSAEADDRINUSE: strcpy(strError,"特定的地址已在使用中"); break; case WSAECONNRESET: strcpy(strError,"与主机的连接被关闭"); break; case 2: strcpy(strError,"对方已经有一个套接字在连接状态,对于同一个用户不能进行多个套接字连接。"); break; case 3: strcpy(strError,"套接字非空,检查是否已经使用该socket进行了侦听?"); break; case 100: strcpy(strError,"连接队列已满,请稍候!"); break; case 101: strcpy(strError,"队列空,操作非法"); break; default: strcpy(strError,"低级错误"); break; } TRACE("SOCKET 错误:%s\r\n", strError); }

 

win-socket类

标签:校验码   tags   private   列表   ==   nts   检测   server   ldb   

原文地址:https://www.cnblogs.com/osbreak/p/9533369.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!