18,356
社区成员
发帖
与我相关
我的任务
分享
void DSocketServer::OnMessage(SOCKET sock, LPARAM lParam, HWND hWnd)
{
if (WSAGETSELECTERROR(lParam)) {
closesocket(sock);
return;
}
switch (WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT:
{
sockaddr_in clientAddr;
int addr_size = sizeof(sockaddr);
SOCKET clientSock = accept(m_socket_server, (sockaddr*)&clientAddr, &addr_size);
if (INVALID_SOCKET == clientSock)
{
globalUserLog.Error(TEXT("客户端套按字无效!错误码:%ld"), WSAGetLastError());
return;
}
char *clientIp = inet_ntoa(clientAddr.sin_addr);
// 读取数据的结构体,第一次进来先需要读取头信息,描述数据包的大小之类的信息
lp_client_read_info lpReadInfo = new client_read_info{0};
// 保存客户端的IP
_tcscpy_s(lpReadInfo->client_ip, 88, clientIp);
lpReadInfo->client_sock = clientSock;
// 应该接收的数据长度,h_info头信息的结构
lpReadInfo->data_len = sizeof(h_info);
// 接收数据的缓冲
lpReadInfo->data = new TCHAR[lpReadInfo->data_len]{0};
// 将结构体保存到一个list,它是一个类属性
push_client_info(lpReadInfo);
// 绑定READ和CLOSE消息
WSAAsyncSelect(clientSock, hWnd, WM_ASYNC_SOCKET, FD_READ | FD_CLOSE);
break;
}
case FD_READ:
{
WSAAsyncSelect(sock, hWnd, 0, 0);
// 根据SOCKET取出对应的lp_client_read_info结构
lp_client_read_info lpReadInfo = get_client_info(sock);
if (sock != lpReadInfo->client_sock)
{
return;
}
// 计算剩下需要读取的数据
UINT readBufLen = lpReadInfo->data_len - lpReadInfo->readed_len;
// 最多一次读取MAX_READ_BUF个字节
if (readBufLen > MAX_READ_BUF)
{
readBufLen = MAX_READ_BUF;
}
TCHAR tmpBuf[MAX_READ_BUF] = {0};
int recvLen = recv(sock, tmpBuf, readBufLen, 0);
if (SOCKET_ERROR == recvLen)
{
int wsaErrorNo = WSAGetLastError();
if (wsaErrorNo != WSAEWOULDBLOCK && wsaErrorNo != WSAEINTR)
{
switch (wsaErrorNo)
{
case WSAETIMEDOUT:
{
globalUserLog.Error(TEXT("读取数据超时,IP:%s"), lpReadInfo->client_ip);
}
break;
case WSAECONNRESET:
{
globalUserLog.Error(TEXT("远程主机强制断开连接,IP:%s"), lpReadInfo->client_ip);
}
break;
default:
{
globalUserLog.Error(TEXT("读取数据时发生未知网络错误,错误码:%d,IP:%s"), wsaErrorNo, lpReadInfo->client_ip);
}
break;
}
WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_CLOSE);
}
else
{
WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_READ);
}
}
else if (recvLen > 0 && recvLen + lpReadInfo->readed_len > lpReadInfo->data_len)
{
globalUserLog.Error(TEXT("数据可能被篡改,IP:%s"), lpReadInfo->client_ip);
WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_CLOSE);
}
else
{
// 读取到数据后保存到缓冲区
if (recvLen > 0)
{
memcpy_s(lpReadInfo->data + lpReadInfo->readed_len, lpReadInfo->data_len - lpReadInfo->readed_len, tmpBuf, recvLen);
lpReadInfo->readed_len += recvLen;
}
// 如果数据读取完成开始处理数据
if (lpReadInfo->data_len == lpReadInfo->readed_len)
{
// 判断组包后的数据是不是头数据包,如果是头数据包,再继续读实际要用的数据
if (!lpReadInfo->readed_header)
{
h_info header_info = {0};
memcpy_s(&header_info, sizeof(h_info), lpReadInfo->data, sizeof(h_info));
delete[] lpReadInfo->data;
lpReadInfo->data = nullptr;
// 标识为头数据包已经读完了
lpReadInfo->readed_header = TRUE;
lpReadInfo->data_len = ntohl(header_info.data_len);
lpReadInfo->origin_data_len = ntohl(header_info.origin_data_len);
lpReadInfo->readed_len = 0;
try
{
lpReadInfo->data = new TCHAR[lpReadInfo->data_len]{ 0 };
if (NULL == lpReadInfo->data)
{
WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_CLOSE);
globalUserLog.Error(TEXT("内存分配失败,分配大小:%ld"), lpReadInfo->data_len);
}
else
{
WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_READ);
}
}
catch (const std::bad_alloc &memEx)
{
WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_CLOSE);
globalUserLog.Error(TEXT("内存分配发生异常,分配大小:%ld"), lpReadInfo->data_len);
}
}
else
{
// 最后处理数据
EnterCriticalSection(&m_cs);
UINT ret = m_dataHandler.Handler(lpReadInfo->data,lpReadInfo->data_len, lpReadInfo->origin_data_len);
LeaveCriticalSection(&m_cs);
ret = htonl(ret);
int sendRet = send(sock, (const char*)&ret, sizeof(UINT), 0);
if (SOCKET_ERROR == sendRet)
{
globalUserLog.Error(TEXT("返回结果时发生未知网络错误,错误码:%d,IP:%s"), WSAGetLastError(), lpReadInfo->client_ip);
}
WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_CLOSE);
}
}
else
{
WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_READ);
}
}
}
break;
case FD_CLOSE:
{
WSAAsyncSelect(sock, hWnd, 0, 0);
// 移除sock对应的数据结构体
remove_client_info(sock);
closesocket(sock);
}
break;
}
}