• 屏幕广播的实现(二)


    上次说到屏幕广播可以通过屏幕差别对比来减小数据传输量。这样虽然有效果,但是如果PC端一多的话,作用还是显得乏力。所以,这只能运用于PC少的情况的下。

    在我们组大神昊哥的提醒下,我决定用winsock2写一个IP组播。

    IP组播是对硬件组播的抽象,是对标准IP网络层协议的扩展。它通过使用特定的IP组播地址,按照最大投递的原则,将IP数据包传输到一个组播群组的主机集合。它的基本方法是:当某一个人向一组人发送数据时,它不必将数据向每一个人都发送数据,只需将数据发送到一个特定的预约的组地址,所有加入该组的人均可以收到这份数据。这样对发送者而言,数据只需发送一次就可以发送到所有接收者,大大减轻了网络的负载和发送者的负担。

     

    关于组播的地址:

    224.0.0.0--239.255.255.255,没有像单播ip段那样有广播地址和网络地址之分了。
     
    具体:224.0.0.0--224.0.0.255 本地保留,给知名协议使用,ttl=1。其中224.0.0.1是本网所有主机接收,224.0.0.2是本网所有路由器接收。
     
    224.0.1.0~238.255.255.255 预留组播地址,[1]多播地址应从此范围内选择。
     
    239.0.0.0--239.255.255.255 私有组播地址。
     
    232.0.0.0--232.255.255.255 特定源多播

     

    在组播里面是没有明确的服务器和客户机的概念。就相当于大家加进了一个小组。只要一个组员发布消息,其他的都能知道。

    不过在屏幕广播里面只有一台PC需要发送数据。所以我还是分成两部分来写,服务端发,客户端收。

     

    // 组播(服务器).cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <sys/types.h>
    #include <WinSock2.h>
    #include <windows.h>
    #include <iostream>
    #include <ws2tcpip.h>
    using namespace std;
    #pragma comment(lib,"ws2_32.lib")
    #define  BUFFSIZE  2048  
    #define  MCASTADDR            "224.8.8.8"            
    #define  MCASTPORT                  8888  
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	//定义变量
    	int sockfd,sockr;
    	struct sockaddr_in addr,local;
    	char szError[100];
    	char buf[]="Hellp,World!";
    	int ttl = 255;//随便改
    
    
    	//初始化
    	WSADATA WSAData;
    	WORD wVersionRequested;
    	wVersionRequested = MAKEWORD(2,2);
    	if (WSAStartup(wVersionRequested,&WSAData)!=0)
    	{
    		printf("WinSock启动失败
    ");
    		exit(1);
    	}
    
    
    	if ((sockfd = WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_MULTIPOINT_C_LEAF|WSA_FLAG_MULTIPOINT_D_LEAF|WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)
    	{
    		printf("socket failed with:%d
    ",WSAGetLastError());
    		WSACleanup();
    		return -1;
    	}
    
    
    	addr.sin_family = AF_INET;
    	addr.sin_port = htons(8888);
    	addr.sin_addr.s_addr = inet_addr("224.8.8.1");
    
    
    
    	if ((sockr = WSAJoinLeaf(sockfd,(SOCKADDR*)&addr,sizeof(addr),NULL,NULL,NULL,NULL,JL_SENDER_ONLY)==INVALID_SOCKET))
    	{
    		printf("WSAJoinLeaf() failed:%d
    ",WSAGetLastError());
    		closesocket(sockfd);
    		WSACleanup();
    		return -1;
    	}
    
    
    	while (TRUE)
    	{
    		memset(buf,0,sizeof(buf));
    		cin>>buf;
    
    		if  (sendto  (sockfd,  buf,  sizeof(buf)  ,  0,  (struct  sockaddr  *)&addr,  sizeof(addr))  
    			==  SOCKET_ERROR)  
    		{  
    			wsprintf  ((LPWSTR)szError,  TEXT("sendto  failed!  Error:  %d"),    
    			WSAGetLastError  ());  
    			MessageBox  (NULL,  (LPCWSTR)szError,  TEXT("Error"),  MB_OK);  
    			closesocket  (sockfd);  
    			return  FALSE;  
    		}  
    		else  
    		{  
    			printf("send  ok
    ");  
    		}  
    	}
    
    	closesocket  (sockfd);  
    	closesocket  (sockr);  
    	WSACleanup  ();  
    	return  0;  
    }  
    
    


    接下来是客户端

    // 组播(客户端).cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <sys/types.h>
    #include <ws2tcpip.h>
    #include <WinSock2.h>
    #include <windows.h>
    #include <iostream>
    using namespace std;
    #pragma comment(lib,"ws2_32.lib")
    #define  BUFFSIZE  2048  
    #define  MCASTADDR            "224.8.8.8"            
    #define  MCASTPORT    8888  
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int sockfd,sockr;
    	int sock_reuse = 1;
    	struct  sockaddr_in  recver_addr,local;  
    	struct ip_mreq multicast;
    	char szError[100];
    	struct ip_mreq mcast;
    	int index = 0,iRecvLen;
    	char szMessageA[1024*320];
    
    	WSADATA WSAData;
    	WORD wVersionRequested;
    	wVersionRequested = MAKEWORD(2,2);
    
    
    	if  (WSAStartup  (wVersionRequested  ,  &WSAData)  !=  0)    
    	{
    		printf  ("recver:Initialize  Winsock  error!");  
    		exit(1);  
    	}
    
    
    
    	if ((sockfd=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,
    		WSA_FLAG_MULTIPOINT_C_LEAF|WSA_FLAG_MULTIPOINT_D_LEAF|WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)
    	{
    		printf("socket failed with:%d
    ",WSAGetLastError());
    		WSACleanup();
    		return -1;
    	}
    
    
    
    // 	local.sin_family  =  AF_INET;  
    // 	local.sin_port  =  htons(MCASTPORT);  
    // 	local.sin_addr.s_addr  = INADDR_ANY;
    // 
    
    
    	recver_addr.sin_family = AF_INET;
    	recver_addr.sin_port = htons(MCASTPORT);
    	recver_addr.sin_addr.s_addr = inet_addr(MCASTADDR);
    
    
    	if (sockr = WSAJoinLeaf(sockfd,(SOCKADDR*)&recver_addr,sizeof(recver_addr),NULL,NULL,NULL,NULL,JL_RECEIVER_ONLY)==INVALID_SOCKET)
    	{
    		printf("WSAJoinLeaf() failed:%d
    ",WSAGetLastError());
    		closesocket(sockfd);
    		WSACleanup();
    		return -1;
    	}
    
    
    
    
    	printf("Receive  on  %s:%d
    ",  MCASTADDR,MCASTPORT);  
    	iRecvLen  =  sizeof  (recver_addr);  
    	memset(szMessageA,  0,  sizeof(szMessageA));  
    
    	while (true)
    	{
    
    		if  (recvfrom  (sockfd,    
    			szMessageA,  
    			sizeof(szMessageA),                    
    			0,  
    			(struct  sockaddr  FAR  *)  &recver_addr,  
    			&iRecvLen)  ==  SOCKET_ERROR)  
    		{  
    			wsprintf  ((LPWSTR)szError,  TEXT("recvfrom  failed!  Error:  %d"),    
    				WSAGetLastError  ());  
    			MessageBox  (NULL,  (LPCWSTR)szError,  TEXT("Error"),  MB_OK);  
    			closesocket  (sockfd);  
    			return  FALSE;  
    		}  
    
    		else  
    		{  
    			cout<<szMessageA<<endl;
    		}  
    	}
    
    	shutdown  (sockfd,  0x00);  
    	closesocket  (sockfd);  
    	closesocket(sockr);
    	WSACleanup  ();  
    	return  0;  
    }  


     

    这两个代码就是服务器发送数据到224.8.8.8:8888,客户端再从224.8.8.8:8888接收。

    这样一来,大大的减少了数据传输量。 不过IP组播用的是UDP协议,这是不可靠的协议,可能会丢包。至于解决方法,明天再写吧。~~

    PS:两个代码不能在同一台电脑运行,会出现套接字冲突。

    参考文章:http://xue23.blog.163.com/blog/static/9793442005614355170/

  • 相关阅读:
    C++中获取高精度时间差
    有关宏的一个问题
    HDU 2504 又见GCD
    .NET中统一的存储过程调用方法(收藏)
    如何让你的SQL运行得更快
    最赚钱的5种成功创业可行方式
    SQL语句优化技术分析
    js document.getElementByID("aa")的位置
    写SQL时尽量不要对字段进行运算操作
    连接池的问题
  • 原文地址:https://www.cnblogs.com/zkkkkkky/p/4423004.html
Copyright © 2020-2023  润新知