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

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

  • 相关阅读:
    ugui点击穿透判断
    c#字符串代码,动态创建编译器
    github项目分享
    unity 2d 版的lookAt
    unity全屏截图
    shader例子
    AcWing 329. 围栏障碍训练场
    AcWing 326. XOR和路径
    AcWing 324. 贿赂FIPA
    AcWing 322. 消木块
  • 原文地址:https://www.cnblogs.com/fx2008/p/2236996.html
Copyright © 2011-2022 走看看