我编了一个局域网聊天工具,现在想采用流动服务器的方法。所以没有程序开启的时候都要在局域网上发广播,以寻找服务器并获得相应的信息。请高手指点如何在局域网上发广播和截获广播谢谢了

解决方案 »

  1.   

    #if !defined(AFX_MULTICASTSOCKET_H__269E2C7F_2037_11D3_8EF3_0000C0FD25F8__INCLUDED_)
    #define AFX_MULTICASTSOCKET_H__269E2C7F_2037_11D3_8EF3_0000C0FD25F8__INCLUDED_#if _MSC_VER >= 1000
    #pragma once
    #endif // _MSC_VER >= 1000
    // MulticastSocket.h : header file
    ///////////////////////////////////////////////////////////////////////////////
    // CMulticastSocket command target
    #define MAXCLIENT  64
    /*
    MSG_SENID
    MSG_SENIP
    */
    class CMulticastSocket : public CAsyncSocket
    {
    // Attributes
    public:// Operations
    public:
    CMulticastSocket();
    virtual ~CMulticastSocket();// Overrides
    public:
    BOOL bDataReceived;
    BOOL SendTo(char * , char*, int);
    void SetLoopBack(BOOL);
    BOOL SetTTL(UINT nTTL);
    void SetServerID( int id ) ;
    BOOL StartServer() ;
    BOOL StartClient( char *serip ) ;
    BOOL EndServer();
    BOOL EndClient();
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CMulticastSocket)
    public:
    virtual void OnReceive(int nErrorCode);
    //}}AFX_VIRTUAL // Generated message map functions
    //{{AFX_MSG(CMulticastSocket)
    // NOTE - the ClassWizard will add and remove member functions here.
    //}}AFX_MSG// Implementation
    private:
    int GetClientListNO();
    void GetHostName( char *hostip ) ;
    BOOL JoinGroup(CString, UINT, UINT, BOOL);
    BOOL LeaveGroup();
    BOOL CreateSendingSocket(UINT, BOOL);
    BOOL CreateReceivingSocket(LPCTSTR, UINT);public:
    char m_strBuffer[3*1024]; // Receiving buffer for the packet that has arrived
    SOCKADDR_IN m_saHostGroup; // SOCKADDR structure to hold IP/Port of the Host group to send data to it
    ip_mreq m_mrMReq; // Contains IP and interface of the host group
    UINT m_nSendersPort; // Holds Port No. of the socket from which last packet was received
    CString m_strSendersIP; // Hold IP of the socket from which the last packet was received
    UINT m_nLocalPort; // Ephemeral port number of the sending port
    CString m_strLocalIP; // IP Address of the local host or your machine
    BOOL bForceNoLoopback; // If interface does not support lopback and the service is required, the bool is set to true
    CAsyncSocket m_SendSocket; // Socket for sending data to the host group
    BOOL  bAsServer ; 
    CString m_strClientList[MAXCLIENT] ;
    int ServerID ;
    char Serverip[20] ;
    char m_strBuf[4*1024] ;
    char m_strLocalip[16] ;
    BOOL bMsgRec ; // to test
    };///////////////////////////////////////////////////////////////////////////////{{AFX_INSERT_LOCATION}}
    // Microsoft Developer Studio will insert additional declarations immediately before the previous line.#endif // !defined(AFX_MULTICASTSOCKET_H__269E2C7F_2037_11D3_8EF3_0000C0FD25F8__INCLUDED_)
      

  2.   

    // MulticastSocket.cpp : implementation file
    //#include "stdafx.h"
    #include "CMulticastSocket.h"
    #include "MulticastSocket.h"#ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif/////////////////////////////////////////////////////////////////////////////
    // CMulticastSocketCMulticastSocket::CMulticastSocket()
    {
    bForceNoLoopback = FALSE;
    bMsgRec = FALSE ;
    bDataReceived = FALSE; /* Variable defined for this project. Not necessarily part of CMulticastSocket */
    bAsServer = FALSE ;
    for ( int i = 0 ; i < MAXCLIENT ; i++ )
    {
    m_strClientList[i] = "0" ;
    }
    ServerID = -1 ;
    GetHostName( m_strLocalip ) ;
    }CMulticastSocket::~CMulticastSocket()
    {
    }
    // Do not edit the following lines, which are needed by ClassWizard.
    #if 0
    BEGIN_MESSAGE_MAP(CMulticastSocket, CAsyncSocket)
    //{{AFX_MSG_MAP(CMulticastSocket)
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    #endif // 0/////////////////////////////////////////////////////////////////////////////
    // CMulticastSocket member functionsBOOL CMulticastSocket::CreateReceivingSocket(LPCTSTR strGroupIP, UINT nGroupPort)
    {
    /* Create socket for receiving packets from multicast group */
    if(!Create(nGroupPort, SOCK_DGRAM, FD_READ))
    {
    AfxMessageBox( "Create receive socket error " ) ;
    return FALSE;
    }
    BOOL bMultipleApps = TRUE; /* allow reuse of local port if needed */
    SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET); /* Fill m_saHostGroup_in for sending datagrams */
    memset(&m_saHostGroup, 0, sizeof(m_saHostGroup)); m_saHostGroup.sin_family = AF_INET;
    m_saHostGroup.sin_addr.s_addr = inet_addr(strGroupIP);
    m_saHostGroup.sin_port = htons((USHORT)nGroupPort); /* Join the multicast group */
    m_mrMReq.imr_multiaddr.s_addr = inet_addr(strGroupIP); /* group addr */ 
    m_mrMReq.imr_interface.s_addr = htons(INADDR_ANY); /* use default */  if(setsockopt(m_hSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char FAR *)&m_mrMReq, sizeof(m_mrMReq)) == SOCKET_ERROR )
    {
    AfxMessageBox( "set receive socket opt error" ) ;
    return FALSE;
    } return TRUE;
    }BOOL CMulticastSocket::CreateSendingSocket(UINT nTTL, BOOL bLoopBack)
    {
    if(!m_SendSocket.Create(0, SOCK_DGRAM, 0))
    {
    // Create an unconnected UDP socket
    AfxMessageBox( "Create send socket error" ) ;
    return FALSE;
    } if(!SetTTL(nTTL)) // Set Time to Live as specified by user
    AfxMessageBox("Warning! Error Setting TTL"); SetLoopBack(bLoopBack); // Enable/Disable Loopback return TRUE;
    }BOOL CMulticastSocket::SetTTL(UINT nTTL)
    {
    /* Set Time to Live to parameter TTL */
    if(m_SendSocket.SetSockOpt(IP_MULTICAST_TTL, &nTTL, sizeof(int), IPPROTO_IP) == 0)
    return FALSE; /* Error Setting TTL */
    else
    return TRUE; /* else TTL set successfully */
    }void CMulticastSocket::SetLoopBack(BOOL bLoop)
    {
    /* Set LOOPBACK option to TRUE OR FALSE according to IsLoop parameter */
    int nLoopBack = (int)bLoop;
    if(m_SendSocket.SetSockOpt(IP_MULTICAST_LOOP, &nLoopBack, sizeof(int), IPPROTO_IP) == 0)
    {
    if(!bLoop) /* if required to stop loopback */
    {
    bForceNoLoopback = TRUE; /* Internally making a note that loopback has to be disabled forcefilly */

    // Get IP/Port for send socket in order to disable loopback forcefully */
    char localHost[255] ;
    gethostname(localHost, 255) ;
    struct hostent *host = gethostbyname(localHost) ; /* Get local host IP */
    m_strLocalIP = inet_ntoa (*(struct in_addr*)*host->h_addr_list) ;
    CString Dummy ; // Dummy string to be passed to the GetSockName function
    m_SendSocket.GetSockName(Dummy, m_nLocalPort) ; /* Get Port Number for Sending Port */
    }
    }
    }
      

  3.   


    void CMulticastSocket::OnReceive(int nErrorCode)
    {
    int nError = ReceiveFrom (m_strBuffer, 32000, m_strSendersIP, m_nSendersPort);
    memcpy( m_strBuf , m_strBuffer + 40 , 1024 * 4 ) ;
    if(nError == SOCKET_ERROR)
    {
    AfxMessageBox("Error receiving data from the host group");
    return ;
    }
    if ( strcmp( m_strLocalip , m_strBuffer ) == 0 )
    {
    if ( bAsServer )
    {
    if ( strcmp( m_strBuffer + 40 , "MSG_SNDIP" ) == 0 )
    {
    int id = GetClientListNO() ;
    m_strClientList[id] = m_strBuffer + 20 ;
    char strSnd[255] ;
    char iid[16] ;
    sprintf( iid , "%d" , ServerID ) ;
    // strcpy( strSnd , m_strBuffer + 35 ) ;
    strcpy( strSnd , "MSG_SNDID" ) ;
    strcpy( strSnd + 15 , iid ) ;
    bMsgRec = TRUE ;
    SendTo( m_strBuffer + 20 , strSnd , 255 ) ;
    bDataReceived = FALSE ;
    return ;
    }

    else if ( strcmp( m_strBuffer + 40 , "MSG_CLOIP" ) == 0 )
    {
    for ( int i = 0 ; i < MAXCLIENT ; i++ )
    {
    if ( m_strClientList[i] == m_strBuffer + 20 )
    {
    m_strClientList[i] = "0" ;
    bDataReceived = FALSE ;
    bMsgRec = TRUE ;
    return ;
    }
    }
    }
    else if ( strcmp( m_strBuffer + 20 , "MSG_SNDID" ) == 0 )
    {
    bDataReceived = FALSE ;
    return ;
    }
    else
    {
    if (!bForceNoLoopback || (bForceNoLoopback && !(m_strSendersIP == m_strLocalIP && m_nSendersPort == m_nLocalPort)))
    {
    // 1. If loopbackback is not to be forced then interface handles the loopback itself
    // 2. If you have to loopback and SOCKOPT LOOPBACK fails, no problem, interfaces loopback by default
    // 3. If you have to stop loopback and SOCKOPT LOOPBACK fails, ignore messages coming from your own sending socket

    // TODO : Add your code for here. The packet received is in m_strBuffer
    bDataReceived = TRUE; /* Making note that a message has arrived */
    }
    }
    }
    else
    {
    if ( strcmp( m_strBuffer + 40 , "MSG_SNDID" ) == 0 )
    {
    if ( ServerID == -1 )
    {
    ServerID = atoi( m_strBuffer + 55 ) ;
    }
    bDataReceived = FALSE ;
    return ;
    }
    else if ( strcmp( m_strBuffer + 20 , "MSG_SNDIP" ) == 0 )
    {
    bDataReceived = FALSE ;
    return ;
    }
    else if ( strcmp( m_strBuffer + 20 , "MSG_CLOIP" ) == 0 )
    {
    bDataReceived = FALSE ;
    return ;
    }
    else
    {
    if (!bForceNoLoopback || (bForceNoLoopback && !(m_strSendersIP == m_strLocalIP && m_nSendersPort == m_nLocalPort)))
    {
    // 1. If loopbackback is not to be forced then interface handles the loopback itself
    // 2. If you have to loopback and SOCKOPT LOOPBACK fails, no problem, interfaces loopback by default
    // 3. If you have to stop loopback and SOCKOPT LOOPBACK fails, ignore messages coming from your own sending socket

    // TODO : Add your code for here. The packet received is in m_strBuffer
    bDataReceived = TRUE; /* Making note that a message has arrived */
    }
    }
    }
    }
    CAsyncSocket::OnReceive(nErrorCode); 
    }BOOL CMulticastSocket::LeaveGroup()
    {
    if(setsockopt (m_hSocket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char FAR *)&m_mrMReq, sizeof(m_mrMReq)) < 0)
    return FALSE;

    m_SendSocket.Close(); // Close sending socket
    Close(); // Close receving socket
    return TRUE;
    }BOOL CMulticastSocket::SendTo(char* ip , char* strMessage, int nSize)
    {
    char *str = new char[4*1024] ;
    memcpy( str , ip , 18 ) ;
    memcpy( str + 20 , m_strLocalip , 18 ) ;
    memcpy( str + 40 , strMessage , nSize ) ;
    if(m_SendSocket.SendTo( str , nSize + 40 , (SOCKADDR*)&m_saHostGroup, sizeof(SOCKADDR), 0) == SOCKET_ERROR)
    return FALSE;
    else
    return TRUE;
    }BOOL CMulticastSocket::JoinGroup(CString GroupIP, UINT nGroupPort, UINT nTTL, BOOL bLoopback)
    {
    if(!CreateReceivingSocket(GroupIP, nGroupPort)) /* Create Socket for receiving and join the host group */
    return FALSE;
    if(!CreateSendingSocket(nTTL, bLoopback)) /* Create Socket for sending */
    return FALSE;
    return TRUE;
    }BOOL CMulticastSocket::StartServer()
    {
    if(!JoinGroup( "228.5.6.7", (UINT)6789 , (UINT)10 , FALSE ) )
    {
    AfxMessageBox("Error joining host group") ;
    return FALSE ;
    }
    unsigned long id = inet_addr ( m_strLocalip ) ;
    SetServerID( abs( id ) ) ;
    bAsServer = TRUE ;
    return TRUE ;
    }BOOL CMulticastSocket::StartClient( char *serip )
    {
    if(!JoinGroup( "228.5.6.7", (UINT)6789 , (UINT)10 , FALSE ) )
    {
    AfxMessageBox("Error joining host group") ;
    return FALSE ;
    }
    bAsServer = FALSE ;
    char ip[25] ;
    GetHostName( ip ) ;
    // AfxMessageBox( ip ) ;
    char strSend[200] ;
    strcpy( Serverip , serip ) ; memcpy( strSend , "MSG_SNDIP" , 12 ) ; //message type
    SendTo( Serverip , strSend , 255 ) ;
    return TRUE ;
    }void CMulticastSocket::GetHostName( char *hostip )
    {
      char szHostname[256];
      if ( gethostname( szHostname , sizeof( szHostname ) ) )
      {
        TRACE( _T( "Failed in call to gethostname, WSAGetLastError returns %d\n" ) , WSAGetLastError() ) ;
        return ;
      }  //get host information from the host name
      HOSTENT* pHostEnt = gethostbyname( szHostname ) ;
      if ( pHostEnt == NULL )
      {
        TRACE( _T( "Failed in call to gethostbyname, WSAGetLastError returns %d\n" ) , WSAGetLastError( ) ) ;
        return ;
      }  //check the length of the IP adress
      if ( pHostEnt->h_length != 4 )
      {
        TRACE( _T( "IP address returned is not 32 bits !!\n" ) ) ;
        return ;
      }  //call the virtual callback function in a loop
      int nAdapter = 0 ;
      unsigned long  ip2 = *( unsigned long * )( pHostEnt->h_addr_list[nAdapter] ) ;
      in_addr tmp ; 
      tmp =  *( in_addr * )&ip2 ;
      strcpy( hostip , inet_ntoa( tmp ) ) ;
    }void CMulticastSocket::SetServerID( int id )
    {
    ServerID = id ;
    }int CMulticastSocket::GetClientListNO()
    {
    for ( int i = 0 ; i < MAXCLIENT ; i++ )
    {
    if ( m_strClientList[i] == "0" )
    {
    return i ;
    }
    }
    return -1 ;
    }BOOL CMulticastSocket::EndClient()
    {
    if(setsockopt (m_hSocket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char FAR *)&m_mrMReq, sizeof(m_mrMReq)) < 0)
    {
    return FALSE;
    }
    char strSnd[255] ;
    strcpy( strSnd , "MSG_CLOIP" ) ;
    char ip[25] ;
    GetHostName( ip ) ;
    SendTo( Serverip , strSnd , 255 ) ;
    m_SendSocket.Close(); // Close sending socket
    Close(); // Close receving socket
    ServerID = -1 ;
    return TRUE;
    }BOOL CMulticastSocket::EndServer()
    {
    if(setsockopt (m_hSocket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char FAR *)&m_mrMReq, sizeof(m_mrMReq)) < 0)
    {
    return FALSE;
    }
    m_SendSocket.Close(); // Close sending socket
    Close(); // Close receving socket
    return TRUE;}
      

  4.   

    发送数据到广播地址。广播地址是(DWORD)-1