zoukankan      html  css  js  c++  java
  • [转载]组播

    (1)单播 一对一

    (2)组播/广播 一对多 单点发送 多点接受 固定地址范围

    根据internet NIC关于IP地址的规定,IP地址共分为A-E 共5类,其中A-C类目前应用的普通IP地址,E类地址保留为将来使用,D 类地址即为组播地址,其网络号为固定的1110(第0~3位),第4~31位定义了某一特殊的组播地址,范围为 224.0.0.0~239.255.255.255,共有228个约27亿个地址。 

    本文来自: (http://www.91linux.com/) 详细出处参考:http://www.91linux.com/html/article/network/20080616/12575_2.html

    使用组播有一个很大的好处,消息往只管往里面丢,接受端开个线程,不断地接收就可以了。

    发送端:

                Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                IPEndPoint iep = new IPEndPoint(IPAddress.Parse("224.0.0.1"), 3000);
                EndPoint ep = (EndPoint)iep;

                byte[] b = Encoding.ASCII.GetBytes("just a test!");
                s.SendTo(b, ep);
                s.Close();

    接收端:

                  Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                  IPEndPoint iep = new IPEndPoint(IPAddress.Any, 3000);
                  EndPoint ep=(EndPoint)iep;
                  s.Bind(iep);
                  s.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.AddMembership,new MulticastOption(IPAddress.Parse("224.0.0.1")));
                  byte[]b=new byte[1024];
                  s.ReceiveFrom(b,ref ep);

                  string test;
                  test = System.Text.Encoding.ASCII.GetString(b);

                 Console.WriteLine(test);
                 

                  s.Close();
                  Console.ReadKey();

    ----------------------------------------------------------------------

    上次说服务器的实现。下面说下交换机的实现(有点多):

    分析:服务器和交换机的通信是一对一的。而交换机接收到数据还要把数据转发给机顶盒。而交换机-->机顶盒是通过组播。

    1、交换机接收服务器的实现:

    UINT RecvSendSTB1(void *p)
    {
    struct sockaddr_in addr;
    int MultSock;
    CIPTVSwitchDlg
    *pDlg=(CIPTVSwitchDlg*)p;
    CString strIP;
    CString m_strPort;
    pDlg
    ->m_IPAddr1.GetWindowText(strIP);//从界面获取IP
    pDlg
    ->m_PortEdit.GetWindowText(m_strPort);//从界面获取Port
    pDlg
    ->m_Port=atoi(m_strPort);

    CString strTemp;
    unsigned
    int IP_A;
    strTemp
    =strIP.Mid(0, strIP.Find('.',0));
    IP_A
    =atoi(strTemp);
    if(IP_A<224 || IP_A>239 || pDlg->m_Port>65536)
    {
    AfxMessageBox(
    "组播地址必须是224.0.0.0~239.255.255.254,而端口号必须是0~65535");
    return -1;
    }
    else
    {
    /* create multicast UDP socket */
    if ((MultSock=socket(AF_INET,SOCK_DGRAM,0)) < 0)
    {
    AfxMessageBox(
    "Error create Multisok");
    }
    }
    /* 设置组播地址 */
    memset(
    &addr,0,sizeof(addr));
    addr.sin_family
    =AF_INET;
    addr.sin_addr.s_addr
    =inet_addr(strIP);
    addr.sin_port
    =htons(pDlg->m_Port);

    SOCKET socket1;
    SOCKADDR_IN local;
    SOCKADDR_IN from;
    char buffer[1024];
    char temp[1024];
    memset(buffer,
    0,sizeof(buffer));
    memset(temp,
    0,sizeof(temp));
    char* pBuffer;
    pBuffer
    =new char[4096];
    pBuffer[
    0]='\0';
    char* pBuf=pBuffer;
    long iTemp = 0;
    CString tmpPort;

    pDlg
    ->m_PortEdit4.GetWindowText(tmpPort);
    pDlg
    ->m_Port4=atoi(tmpPort);
      
      //单播接收服务器数据sock
    int fromlen =sizeof(SOCKADDR);
    local.sin_family
    =AF_INET; //地址族,常被赋为AF_INET
    local.sin_port=htons(pDlg->m_Port4); //监听端口
    local.sin_addr.s_addr=INADDR_ANY; //本机IP

    int ret=0;
    ret
    =socket1=socket(AF_INET,SOCK_DGRAM,0);//数据报套接字
    if(ret<0)
    {
    AfxMessageBox(
    "socket创建失败");
    }

    //绑定套接字到一个IP地址和一个端口
    if((bind(socket1,(SOCKADDR*)&local,sizeof(SOCKADDR))==SOCKET_ERROR))
    {
    AfxMessageBox(
    "socket绑定失败");
    }
    //接收并组播发送数据
    while(1)
    {
    int rev=0;
    if((rev= recvfrom(socket1,buffer,sizeof(buffer),0,(SOCKADDR*)&from,&fromlen))<0)
    {
    AfxMessageBox(
    "接收失败");
    }

    //组播发送
    if (sendto(MultSock,buffer, rev, 0, (struct sockaddr *) &addr, sizeof(addr)) < 0)
    {
    AfxMessageBox(
    "发送失败");
    }
    }    

    分析:要组播接收的方式接收交换机的数据。图像要显示出来(由于发送时设定了发送包的大小所以还要组包)。

    接收数据和显示代码如下:

    UINT ReceiveShowCh1(void *p)
    {
    	CMultSocket m_SocketCh;
    	CCh1Dlg *pDlg=(CCh1Dlg*)p;
    	CString m_strIP;
    	CString m_strPort;
    	pDlg->m_IPAddrCh1.GetWindowText(m_strIP);
    	pDlg->m_PortCh1.GetWindowText(m_strPort);
    	pDlg->m_Port1=atoi(m_strPort);
    	
    	CString strTemp;
    	unsigned int IP_A;
    
    	strTemp=m_strIP.Mid(0, m_strIP.Find('.',0));
    	IP_A=atoi(strTemp);
    	if(IP_A<224 || IP_A>239 || pDlg->m_Port1>65536)
    	{
    		AfxMessageBox("地址范围:224.0.0.0~239.255.255.254,端口号范围:0~65535");
    		return -1;
    	}
    	/*设置组播接收*/
        int ret;
        SOCKET SockCh1;
        SOCKADDR_IN localAddr,remoteAddr;
        int len = sizeof SOCKADDR;
        char recvBuf[32000];
        ip_mreq  mcast;  // 设置组播
    
        SockCh1 = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
        if ( INVALID_SOCKET == SockCh1 )
        {
             WSACleanup();
             return 1;
        }
        localAddr.sin_family = AF_INET;
        localAddr.sin_port =  htons(pDlg->m_Port1);
        localAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    
        ret = bind(SockCh1,(SOCKADDR*)&localAddr,len);
        if ( SOCKET_ERROR == ret )
        {
            closesocket(SockCh1);
            return -1;
        }
    
        //用于接收组播所设置,把套接字加入一个组播
        memset(&mcast,0x00,sizeof(mcast));
        mcast.imr_multiaddr.S_un.S_addr = inet_addr(m_strIP);
        mcast.imr_interface.S_un.S_addr = htonl(INADDR_ANY);
        ret = setsockopt(SockCh1,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&mcast,sizeof(mcast));
        if ( SOCKET_ERROR == ret )
        {
            AfxMessageBox("Error IP_Add");//printf("IP_ADD_MEMBERSHIP ERROR! CODE IS : %d\n",WSAGetLastError());
            return -1;
        }
    
        memset(&remoteAddr,0x00,len);
        memset(recvBuf,0x00,sizeof(recvBuf));
    	char *pBuf=new char[320000];
    	int iTemp=0;
    
    	int flags=0;
        while (1)
        {
            ret = recvfrom(SockCh1,recvBuf,sizeof(recvBuf),0,(SOCKADDR*)&remoteAddr,&len);
    		if(flags)
    		{
    			if ( ret > 0 )
    		    {        
    				if(ret==1024)
    				{
    					for (int i=0; i<=ret; i++)
    					{
    						pBuf[i+iTemp] = recvBuf[i];
    					}
    					iTemp+=ret;
    				}
    				else
    				{
    					for (int i=0; i<=ret; i++)
    					{
    						pBuf[i+iTemp] = recvBuf[i];
    					}
    					iTemp+=ret;
    
    					//显示接收内容
    					pDlg->ShowPIC(pBuf,iTemp);
    					iTemp=0;
    				}
    		     }
    		}
    		//过滤掉不完整的第一帧,一旦第一个小于1024的包,
    		//认为为图片的最后一个包,下一个为图片开始,flags置位
    		if(ret<1024)
    		{
    			flags=1; 
    		}
    
       }	
    	return 0;	
    }
    

    其中ShowPIC的代码如下:

    void CCh1Dlg::ShowPIC(char* buf,int iSize)
    {	
    	IStream* m_pStream ;
    	IPicture* m_pPicture ;
    	LONG m_nWidth;
    	LONG m_nHeight;
    	HRESULT hr;

    //上下文环境
        CWnd *pPic =GetDlgItem(IDC_STATIC_Picture1); pPic-> GetDC(); CClientDC dc(pPic);//CClientDC dc(this); CRect rc; HWND pWnd = pPic->GetSafeHwnd(); ::GetWindowRect(pWnd,&rc); m_pStream = NULL; m_pPicture = NULL; HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE,iSize);//开辟内存 hMem=buf; hr = ::CreateStreamOnHGlobal(hMem,TRUE,&m_pStream); ASSERT(SUCCEEDED(hr)); hr= ::OleLoadPicture(m_pStream,iSize,TRUE,IID_IPicture,(LPVOID *)&m_pPicture); ASSERT(hr==S_OK); //long nWidth,nHeight;宽高,MM_HIMETRIC 模式,单位是0.01毫米 m_pPicture->get_Width(&m_nWidth);//宽 m_pPicture->get_Height(&m_nHeight);//高 int w=rc.right-rc.left; int h=rc.bottom-rc.top;
       //根据窗口大小来显示 double tmppx=w*26.46; double tmppy=h*26.46; LONG px=(LONG)tmppx; LONG py=(LONG)tmppy; CSize sz(px,py);//图片显示的大小 dc.HIMETRICtoDP(&sz); // 转换 MM_HIMETRIC 模式单位为 MM_TEXT 像素单位 m_pPicture->Render(dc.m_hDC,0,0,sz.cx,sz.cy,0,m_nHeight,m_nWidth,-m_nHeight,NULL); }

    到此结束了。这里只是贴了些部分实现的代码。自认写的不好很多可以改进的地方。贴出了就是想得到更多的改进

  • 相关阅读:
    HDU 3572 Task Schedule(拆点+最大流dinic)
    POJ 1236 Network of Schools(Tarjan缩点)
    HDU 3605 Escape(状压+最大流)
    HDU 1166 敌兵布阵(分块)
    Leetcode 223 Rectangle Area
    Leetcode 219 Contains Duplicate II STL
    Leetcode 36 Valid Sudoku
    Leetcode 88 Merge Sorted Array STL
    Leetcode 160 Intersection of Two Linked Lists 单向链表
    Leetcode 111 Minimum Depth of Binary Tree 二叉树
  • 原文地址:https://www.cnblogs.com/fx2008/p/2236996.html
Copyright © 2011-2022 走看看