win-socket类
2021-07-14 21:14
标签:校验码 tags private 列表 == nts 检测 server ldb win-socket类 标签:校验码 tags private 列表 == nts 检测 server ldb 原文地址:https://www.cnblogs.com/osbreak/p/9533369.html#pragma once
#pragma warning(disable: 4786)
#include "winsock2.h"
#include
#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