天天看點

區域網路聊天,廣播消息

本類可用來發送廣播消息、區域網路聊天

.h檔案

#pragma once

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 ) {

   //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);

  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);

   }

  }

}

本文來自CSDN部落格,轉載請标明出處:http://blog.csdn.net/wclaccp/article/details/51134224



繼續閱讀