局域网聊天,广播消息

本类可用来发送广播消息、局域网聊天

.h文件

#pragma once
/********************************************************************
 创建时间: 2016/04/12
 文件名称:  BroadcastMsg.h
 创建人:  wanglong
 功能描述: 广播发送消息类
 使用步骤:   1> 初始化SOCKET InitSocket
    2> 发送消息 SendMsg
    3> 设置接受消息回调函数 SetRecvMsgProc
    4> 释放资源 ReleaseRes
 修改历史:  10:4:2015 17:18 |wanglong 添加功能描述
*********************************************************************/

typedef struct tagRecvMsg
{
 void* pVOID;
 LPCSTR lpMsg;

}RECVMSG;

typedef void (_stdcall *RECVMSGPROC) (const RECVMSG& recvMsg);

class CBroadcastMsg
{
public:
 CBroadcastMsg(void);
 ~CBroadcastMsg(void);
public:

 //初始化SOCKET
 BOOL InitSocket();

 //释放资源
 void ReleaseRes();

 //设置接受消息回调函数
 void SetRecvMsgProc(VOID* pVOID,RECVMSGPROC recvMsgProc);

 //发送消息
 void SendMsg(LPCSTR lpMsg);
 
private:
 //接受线程消息
 static unsigned __stdcall RecvMsgProc(LPVOID lpParam);

 //
 void OnRecvMsg();
private:
 RECVMSGPROC m_recvMsgProc;
 RECVMSG m_recvMsg;

 BOOL m_bRunning;
 HANDLE m_hExeEvent[3]; //0 线程句柄 1 退出线程通知  2 有数据可读
 
 SOCKET m_sendSocket;
 SOCKET m_recvSocket;
};

.cpp文件

#include "StdAfx.h"
#include "BroadcastMsg.h"

#define SOCKET_PORT 4567

CBroadcastMsg::CBroadcastMsg(void)
 :m_recvMsgProc(NULL)
 ,m_bRunning(TRUE)
{

}


CBroadcastMsg::~CBroadcastMsg(void)
{

}

BOOL CBroadcastMsg::InitSocket()
{
 //初始化socket
 WSAData wsaData;
 int err;
 err = WSAStartup(MAKEWORD(2,2),&wsaData);
 if(err!=0)
 {
  //OutputStringToDebugView(_T("could not find a usable Winsock.dll\r\n"));
  return FALSE;
 }
 if ( LOBYTE( wsaData.wVersion ) != 2 ||
  HIBYTE( wsaData.wVersion ) != 2 ) {
   /* Tell the user that we could not find a usable */
   /* WinSock DLL.                                  */
   //OutputStringToDebugView(_T("winsock.dll version must 2.0\r\n"));
   WSACleanup( );
   return FALSE;
 }

 
 //创建发送socket
 m_sendSocket = ::socket(AF_INET, SOCK_DGRAM, 0); 
 //设置广播
 BOOL bBroadcast = TRUE; 
 ::setsockopt(m_sendSocket, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL)); 

 //创建接受socket
 m_recvSocket = ::socket(AF_INET, SOCK_DGRAM, 0); 
 bBroadcast = TRUE; 
 ::setsockopt(m_recvSocket, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL)); 

 SOCKADDR_IN sin;  
 sin.sin_family = AF_INET; 
 sin.sin_port = ::htons(SOCKET_PORT); 
 sin.sin_addr.S_un.S_addr = INADDR_ANY; 
 if (::bind(m_recvSocket, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR) 
 { 
  DWORD DW = ::GetLastError();
  return FALSE;
 } 

 //设置接受、发送缓冲区
 int SndBuf,RcvBuf,nSndBuf,nRcvBuf;
 nSndBuf=sizeof(SndBuf);
 nRcvBuf=sizeof(RcvBuf);
 SndBuf=65536;
 RcvBuf=65536;
 setsockopt(m_sendSocket,SOL_SOCKET,SO_SNDBUF,(char*)&SndBuf,sizeof(SndBuf));
 setsockopt(m_recvSocket,SOL_SOCKET,SO_RCVBUF,(char*)&RcvBuf,sizeof(RcvBuf));
 getsockopt(m_recvSocket,SOL_SOCKET,SO_RCVBUF,(char*)&RcvBuf,&nRcvBuf);
 getsockopt(m_sendSocket,SOL_SOCKET,SO_SNDBUF,(char*)&SndBuf,&nSndBuf);

 //使用事件模型
 m_hExeEvent[1] = CreateEvent(NULL,FALSE,FALSE,NULL);
 m_hExeEvent[2] = WSACreateEvent();
 WSAEventSelect(m_recvSocket,m_hExeEvent[2],FD_READ | FD_WRITE |FD_CONNECT | FD_CLOSE);

 //线程接受数据
 unsigned int dwThread;
 m_hExeEvent[0] = (HANDLE)_beginthreadex(NULL,0,RecvMsgProc,(LPVOID)this,0,&dwThread);
 
 return TRUE;
}

void CBroadcastMsg::ReleaseRes()
{
 m_bRunning = FALSE;

 //发送关闭线程信号
 if( m_hExeEvent[1] )
  SetEvent(m_hExeEvent[1]) ;

 if( m_hExeEvent[0]  )
  WaitForSingleObject(m_hExeEvent[0] ,INFINITE);

 for(int j = 0; j < 3; j++)
 {
  if( m_hExeEvent[j] )
  {
   CloseHandle( m_hExeEvent[j] ) ;
   m_hExeEvent[j] = NULL ;
  }
 }

 //
 WSACleanup();
}


void CBroadcastMsg::SetRecvMsgProc( VOID* pVOID, RECVMSGPROC recvMsgProc )
{
 m_recvMsgProc = recvMsgProc;
 m_recvMsg.pVOID = pVOID;
}

void CBroadcastMsg::SendMsg( LPCSTR lpMsg )
{
 if (lpMsg)
 {
  //设置广播地址 
  SOCKADDR_IN bcast; 
  bcast.sin_family = AF_INET; 
  bcast.sin_port = htons(SOCKET_PORT); 
  bcast.sin_addr.S_un.S_addr = INADDR_BROADCAST;
  ::sendto(m_sendSocket, lpMsg, strlen(lpMsg), 0, (sockaddr*)&bcast, sizeof(bcast)); 
 }
}

unsigned __stdcall CBroadcastMsg::RecvMsgProc( LPVOID lpParam )
{
 CBroadcastMsg* pThis = (CBroadcastMsg*)lpParam;
 
 while(pThis->m_bRunning)
 {
  DWORD dwWait = ::WSAWaitForMultipleEvents(3,pThis->m_hExeEvent,FALSE,WSA_INFINITE,FALSE) - WSA_WAIT_EVENT_0;
  switch(dwWait)
  {
  case 2:  //read
   {
    WSANETWORKEVENTS NetworkEvents;
    WSAEnumNetworkEvents(pThis->m_recvSocket,pThis->m_hExeEvent[2],&NetworkEvents);
    if(NetworkEvents.lNetworkEvents & FD_CONNECT)
    {
    
    }
    if(NetworkEvents.lNetworkEvents & FD_READ)
    {
     pThis->OnRecvMsg();
    }
    if(NetworkEvents.lNetworkEvents & FD_WRITE)
    {
     
    }
    if(NetworkEvents.lNetworkEvents & FD_CLOSE)
    {
     
    }
   }
   break;
  case 1: //
   
   break;

  case WSA_WAIT_FAILED:
   
   break;
  }
 }

 return 1;
}

void CBroadcastMsg::OnRecvMsg()
{
 char sz[1024] = {0}; 
 SOCKADDR_IN addrRemote; 
 int nLen = sizeof(SOCKADDR_IN);
 /*while (1)  //大量数据,要考虑多次接收
 {  */
  int nRet = ::recvfrom(m_recvSocket, sz, sizeof(sz), 0, (sockaddr*)&addrRemote, &nLen); 
  if (nRet > 0) 
  { 
   sz[nRet] = '\0';   
   if (m_recvMsgProc)
   {
    m_recvMsg.lpMsg = sz;
    m_recvMsgProc(m_recvMsg);
   }
  }

 /* break;
 }  */
}


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wclaccp/article/details/51134224


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值