线程池的Windows下实现---RecvThreadPool.cpp

本文介绍了一个基于C++的监听线程实现方案,通过WSAStartup初始化Winsock,并使用socket、bind及listen等函数创建并配置监听套接字。此外,还详细描述了如何通过accept接收客户端连接请求,以及如何在消息处理中使用多线程来提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include "stdafx.h"
#include "RecvThreadPool.h"

//监听线程
unsigned __stdcall RecvThreadPool::ListenThread(LPVOID Param)
{
 RecvThreadPool* pThis = (RecvThreadPool*)Param;
 pThis->StartProcPool(PROCTHREADNUM);  //将处理消息的线程池吊起
 pThis->SetThreadNum(RECVTHREADNUM);
 pThis->Run();

 WSADATA wsaData;
 int err;
 err = WSAStartup(MAKEWORD(1, 1), &wsaData);
 if ( err != 0 )
 {
  return 1;
 }

 if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
 {
  WSACleanup();
  return 1;
 }

 //创建用于监听的套接字
 SOCKET ListenSock = socket(AF_INET, SOCK_STREAM, 0);

 SOCKADDR_IN addrSrv;
 addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
 addrSrv.sin_family = AF_INET;
 addrSrv.sin_port = htons( PORT );

 int nOpt=1;
 setsockopt(ListenSock, SOL_SOCKET, SO_REUSEADDR, (char *) &nOpt, sizeof(int));//重用端口

 int nRetBind = bind(ListenSock , (SOCKADDR * )&addrSrv, sizeof( SOCKADDR ) );
 if ( SOCKET_ERROR == nRetBind )
 {
  return 1;
 }

 int nListenRet = listen( ListenSock, SOMAXCONN);
 if (SOCKET_ERROR == nListenRet )
 {
  return 1;
 }

 SOCKADDR_IN addrClient;
 int len = sizeof( SOCKADDR );

 fd_set AcceptFdSet;
 struct timeval tv = {0, 100};

 while (!pThis->m_bServerRun)
 {
  //判断监听SOCKET是否关闭
  if (INVALID_SOCKET == ListenSock || SOCKET_ERROR == ListenSock)
  {
   break;
  }
  FD_ZERO(&AcceptFdSet);
  FD_SET(ListenSock, &AcceptFdSet);
  int nRetSelect = select(0, &AcceptFdSet, NULL, NULL, &tv);  //Linux下0应该为ListenSock+1

  if (SOCKET_ERROR == nRetSelect)
  {
   break;
  }
  if (0 == nRetSelect)//超时
  {
   continue;
  }

  //等待客户请求到来
  SOCKET sockConn = accept( ListenSock, ( SOCKADDR * )&addrClient, &len );
  if (INVALID_SOCKET == sockConn || SOCKET_ERROR == sockConn || NULL == sockConn)
  {
   continue;
  }
  
  SOCKET* pSock = new SOCKET;
  *pSock = sockConn;
  pThis->AddTask(pSock);
 }

 AfxMessageBox(_T("Listen thread exit"));
 WSACleanup();
 return 0;
}


//创建线程进行监听
int RecvThreadPool::CreateListenThread()
{
 if (NULL == _beginthreadex(NULL,
        0,
        RecvThreadPool::ListenThread,
        (LPVOID)this,
        0,
        NULL))
 {
  return CreateThreadFailed;
 }

 return CreateThreadSuccess;
}


//返回消息总长度
u_int RecvThreadPool::GetMsgLen(BYTE cArryMsgLen[])
{
 CommonHead_S* pCommon = (CommonHead_S*)cArryMsgLen;
 u_int uMsgLen = ntohl(pCommon->uMsgTotalLen);
 return uMsgLen;
}


//接收线程池实际处理函数
void RecvThreadPool::ProcessFun(SOCKET* pSock)
{
 BYTE* pMsgTotal = new BYTE[MSGTOTALLEN];
 memset(pMsgTotal, 0, MSGTOTALLEN);
 BYTE* pMsgTotalTemp = pMsgTotal;

 //先接收消息头
 int nRecvHeadLen = 0;
 int nRecvHeadTotalLen = 0;
 while (1)
 {
  nRecvHeadLen = recv(*pSock, (char*)(pMsgTotal + nRecvHeadTotalLen), sizeof(CommonHead_S) - nRecvHeadTotalLen, 0);
  if (SOCKET_ERROR == nRecvHeadLen || 0 == nRecvHeadLen)  //0表示对方断开了
  {
   return;
  }
  nRecvHeadTotalLen += nRecvHeadLen;

  if (nRecvHeadTotalLen < sizeof(CommonHead_S))
  {
   Sleep(200);
   continue;
  }
  if (nRecvHeadTotalLen >= sizeof(CommonHead_S))
  {
   break;
  }
 }

 u_int uMsgTotal = GetMsgLen(pMsgTotal);

 if (uMsgTotal > nRecvHeadTotalLen)  //消息总长度>消息头长度,继续接收消息体
 {
  int nRecvBodyLen = 0;
  int nRecvBodyTotalLen = 0;
  int nLeftBodyLen = (uMsgTotal - nRecvHeadTotalLen);
  while (1)
  {
   nRecvBodyLen = recv(*pSock, (char*)(pMsgTotal+nRecvHeadTotalLen+nRecvBodyTotalLen), nLeftBodyLen - nRecvBodyTotalLen, 0);
   if (SOCKET_ERROR == nRecvBodyLen || 0 == nRecvBodyLen)
   {
    return;
   }

   nRecvBodyTotalLen += nRecvBodyLen;
   if (nRecvBodyTotalLen < nLeftBodyLen)
   {
    continue;
   }
   if (nRecvBodyTotalLen >= nLeftBodyLen)
   {
    break;
   }
  }
 }

 MsgInfo* pMsg = new MsgInfo;
 pMsg->m_sock = *pSock;
 memset(pMsg->cArryMsgLen, 0, MSGTOTALLEN);
 memcpy(pMsg->cArryMsgLen, pMsgTotalTemp, MSGTOTALLEN);

 m_ProThreadPool.AddTask(pMsg);

 delete [] pMsgTotalTemp;
 pMsgTotalTemp = NULL;

 delete pSock;
 pSock = NULL;
 return;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值