VC驿站

 找回密码
 加入驿站

QQ登录

只需一步,快速开始

搜索
查看: 105|回复: 0

WSAAsyncSelect模型接收数组包的问题

[复制链接]
05_avatar_middle
最佳答案
0 
online_vip 发表于 2020-9-15 11:44:40 | 显示全部楼层 |阅读模式
下面是WSAAsyncSelect的处理代码,但是总感觉别扭。
1.如果有无聊的人连接上来不发送数据也不关闭连接就永远不会有FD_CLOSE消息,导致存储lp_client_read_info的信息永远会保存在list里面。
2.用list保存组包缓冲区,这种方式合不合适呢,一般WSAAsyncSelect模式怎么保存SOCKET组包缓冲区的?

  1. void DSocketServer::OnMessage(SOCKET sock, LPARAM lParam, HWND hWnd)
  2. {
  3.         if (WSAGETSELECTERROR(lParam)) {
  4.                 closesocket(sock);
  5.                 return;
  6.         }
  7.         switch (WSAGETSELECTEVENT(lParam))
  8.         {
  9.         case FD_ACCEPT:
  10.         {
  11.                 sockaddr_in clientAddr;
  12.                 int addr_size = sizeof(sockaddr);
  13.                 SOCKET clientSock = accept(m_socket_server, (sockaddr*)&clientAddr, &addr_size);
  14.                 if (INVALID_SOCKET == clientSock)
  15.                 {
  16.                         globalUserLog.Error(TEXT("客户端套按字无效!错误码:%ld"), WSAGetLastError());
  17.                         return;
  18.                 }
  19.                 char *clientIp = inet_ntoa(clientAddr.sin_addr);
  20.                
  21.                 // 读取数据的结构体,第一次进来先需要读取头信息,描述数据包的大小之类的信息
  22.                 lp_client_read_info lpReadInfo = new client_read_info{0};
  23.                 // 保存客户端的IP
  24.                 _tcscpy_s(lpReadInfo->client_ip, 88, clientIp);
  25.                 lpReadInfo->client_sock = clientSock;
  26.                 // 应该接收的数据长度,h_info头信息的结构
  27.                 lpReadInfo->data_len = sizeof(h_info);
  28.                 // 接收数据的缓冲
  29.                 lpReadInfo->data = new TCHAR[lpReadInfo->data_len]{0};
  30.                 // 将结构体保存到一个list,它是一个类属性
  31.                 push_client_info(lpReadInfo);
  32.                 // 绑定READ和CLOSE消息
  33.                 WSAAsyncSelect(clientSock, hWnd, WM_ASYNC_SOCKET, FD_READ | FD_CLOSE);
  34.                 break;
  35.         }
  36.         case FD_READ:
  37.         {
  38.                 WSAAsyncSelect(sock, hWnd, 0, 0);
  39.                 // 根据SOCKET取出对应的lp_client_read_info结构
  40.                 lp_client_read_info lpReadInfo = get_client_info(sock);
  41.                 if (sock != lpReadInfo->client_sock)
  42.                 {
  43.                         return;
  44.                 }
  45.                
  46.                 // 计算剩下需要读取的数据
  47.                 UINT readBufLen = lpReadInfo->data_len - lpReadInfo->readed_len;
  48.                 // 最多一次读取MAX_READ_BUF个字节
  49.                 if (readBufLen > MAX_READ_BUF)
  50.                 {
  51.                         readBufLen = MAX_READ_BUF;
  52.                 }

  53.                 TCHAR tmpBuf[MAX_READ_BUF] = {0};
  54.                 int recvLen = recv(sock, tmpBuf, readBufLen, 0);
  55.                 if (SOCKET_ERROR == recvLen)
  56.                 {
  57.                         int wsaErrorNo = WSAGetLastError();
  58.                         if (wsaErrorNo != WSAEWOULDBLOCK && wsaErrorNo != WSAEINTR)
  59.                         {
  60.                                 switch (wsaErrorNo)
  61.                                 {
  62.                                 case WSAETIMEDOUT:
  63.                                 {
  64.                                         globalUserLog.Error(TEXT("读取数据超时,IP:%s"), lpReadInfo->client_ip);
  65.                                 }
  66.                                 break;
  67.                                 case WSAECONNRESET:
  68.                                 {
  69.                                         globalUserLog.Error(TEXT("远程主机强制断开连接,IP:%s"), lpReadInfo->client_ip);
  70.                                 }
  71.                                 break;
  72.                                 default:
  73.                                 {
  74.                                         globalUserLog.Error(TEXT("读取数据时发生未知网络错误,错误码:%d,IP:%s"), wsaErrorNo, lpReadInfo->client_ip);
  75.                                 }
  76.                                 break;
  77.                                 }
  78.                                 WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_CLOSE);
  79.                         }
  80.                         else
  81.                         {
  82.                                 WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_READ);
  83.                         }
  84.                 }
  85.                 else if (recvLen > 0 && recvLen + lpReadInfo->readed_len > lpReadInfo->data_len)
  86.                 {
  87.                         globalUserLog.Error(TEXT("数据可能被篡改,IP:%s"), lpReadInfo->client_ip);
  88.                         WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_CLOSE);
  89.                 }
  90.                 else
  91.                 {
  92.                         // 读取到数据后保存到缓冲区
  93.                         if (recvLen > 0)
  94.                         {
  95.                                 memcpy_s(lpReadInfo->data + lpReadInfo->readed_len, lpReadInfo->data_len - lpReadInfo->readed_len, tmpBuf, recvLen);
  96.                                 lpReadInfo->readed_len += recvLen;
  97.                         }
  98.                         // 如果数据读取完成开始处理数据
  99.                         if (lpReadInfo->data_len == lpReadInfo->readed_len)
  100.                         {
  101.                        
  102.                                 // 判断组包后的数据是不是头数据包,如果是头数据包,再继续读实际要用的数据
  103.                                 if (!lpReadInfo->readed_header)
  104.                                 {
  105.                                         h_info header_info = {0};
  106.                                         memcpy_s(&header_info, sizeof(h_info), lpReadInfo->data, sizeof(h_info));
  107.                                         delete[] lpReadInfo->data;
  108.                                         lpReadInfo->data = nullptr;

  109.                                         // 标识为头数据包已经读完了
  110.                                         lpReadInfo->readed_header = TRUE;
  111.                                         lpReadInfo->data_len = ntohl(header_info.data_len);
  112.                                         lpReadInfo->origin_data_len = ntohl(header_info.origin_data_len);
  113.                                         lpReadInfo->readed_len = 0;
  114.                                         try
  115.                                         {
  116.                                                 lpReadInfo->data = new TCHAR[lpReadInfo->data_len]{ 0 };
  117.                                                 if (NULL == lpReadInfo->data)
  118.                                                 {
  119.                                                         WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_CLOSE);
  120.                                                         globalUserLog.Error(TEXT("内存分配失败,分配大小:%ld"), lpReadInfo->data_len);
  121.                                                 }
  122.                                                 else
  123.                                                 {
  124.                                                         WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_READ);
  125.                                                 }
  126.                                         }
  127.                                         catch (const std::bad_alloc &memEx)
  128.                                         {
  129.                                                 WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_CLOSE);
  130.                                                 globalUserLog.Error(TEXT("内存分配发生异常,分配大小:%ld"), lpReadInfo->data_len);
  131.                                         }
  132.                                 }
  133.                                 else
  134.                                 {
  135.                                     // 最后处理数据
  136.                                         EnterCriticalSection(&m_cs);
  137.                                         UINT ret = m_dataHandler.Handler(lpReadInfo->data,lpReadInfo->data_len, lpReadInfo->origin_data_len);
  138.                                         LeaveCriticalSection(&m_cs);
  139.                                         ret = htonl(ret);
  140.                                         int sendRet = send(sock, (const char*)&ret, sizeof(UINT), 0);
  141.                                         if (SOCKET_ERROR == sendRet)
  142.                                         {
  143.                                                 globalUserLog.Error(TEXT("返回结果时发生未知网络错误,错误码:%d,IP:%s"), WSAGetLastError(), lpReadInfo->client_ip);
  144.                                         }
  145.                                         WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_CLOSE);
  146.                                 }
  147.                         }
  148.                         else
  149.                         {
  150.                                 WSAAsyncSelect(sock, hWnd, WM_ASYNC_SOCKET, FD_READ);
  151.                         }
  152.                 }
  153.         }
  154.                 break;
  155.         case FD_CLOSE:
  156.         {
  157.                 WSAAsyncSelect(sock, hWnd, 0, 0);
  158.                 // 移除sock对应的数据结构体
  159.                 remove_client_info(sock);
  160.                 closesocket(sock);
  161.         }
  162.                 break;
  163.         }
  164. }
复制代码




上一篇:自己建一个对话框里面的控件变量找不到
下一篇:VS2013制作电子相册,按钮往左后退怎么处理
您需要登录后才可以回帖 登录 | 加入驿站 qq_login

本版积分规则

×【发帖 友情提示】
1、请回复有意义的内容,请勿恶意灌水;
2、纯数字、字母、表情等无意义的内容系统将自动删除;
3、若正常回复后帖子被自动删除,为系统误删的情况,请重新回复其他正常内容或等待管理员审核通过后会自动发布;
4、感谢您对VC驿站一如既往的支持,谢谢合作!

关闭

站长提醒上一条 /2 下一条

QQ|小黑屋|手机版|VC驿站 ( 辽ICP备09019393号 )|网站地图wx_jqr

GMT+8, 2020-9-28 20:49

Powered by CcTry.CoM

© 2009-2020 cctry.com

快速回复 返回顶部 返回列表