|
下面是WSAAsyncSelect的处理代码,但是总感觉别扭。
1.如果有无聊的人连接上来不发送数据也不关闭连接就永远不会有FD_CLOSE消息,导致存储lp_client_read_info的信息永远会保存在list里面。
2.用list保存组包缓冲区,这种方式合不合适呢,一般WSAAsyncSelect模式怎么保存SOCKET组包缓冲区的?
- 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;
- }
- }
复制代码 |
上一篇: 自己建一个对话框里面的控件变量找不到下一篇: VS2013制作电子相册,按钮往左后退怎么处理
|