屏幕广播的实现(二)

上次说到屏幕广播可以通过屏幕差别对比来减小数据传输量。这样虽然有效果,但是如果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启动失败\n");
		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\n",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\n",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\n");  
		}  
	}

	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\n",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\n",WSAGetLastError());
		closesocket(sockfd);
		WSACleanup();
		return -1;
	}




	printf("Receive  on  %s:%d\n",  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/

转载于:https://www.cnblogs.com/zkkkkkky/p/4423004.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.屏幕广播 除了原来的全屏和窗口广播模式外,增加了绑定窗口模式。老师可以选择屏幕的某个部分广播给学生,以增加教学的直观性。 2.监控转播 监控时抓取快照。老师可以在监控学生的时候,对学生画面拍快照,保存学生画面的截图。 3.班级模型管理 新增加班级模型管理按钮,并设计了单独的管理界面,实现对班级模型的统一管理。 4.屏幕录制 屏幕录制经过全面技术革新,可以直接录制成 ASF 文件,也可以用 Windows 自带的 Media Player 直接播放。 屏幕录制的音视频不再分两个文件存放,保证了录制的文件的音视频同步性。 屏幕录制可以选择质量方案,以便客户在录制的文件尺寸和质量上,根据需要取舍。 屏幕录制提示小红点闪烁,录制过程更加直观。 提供屏幕录制转换器,以便早期的客户把老版本的文件转换为 ASF 文件。 5.远程设置 远程设置新增桌面主题设置,桌面背景设置,屏幕保护方案设置。 远程设置可以设置学生的频道号和音量。 远程设置可以设置学生的卸载密码,是否启用进程保护,断线锁屏,热键退出。 6.远程命令 新增可以远程关闭所有学生正在执行的应用程序。 7.分组管理 分组管理可以新建,删除,重命名分组。添加和删除分组中的成员。 分组信息随班级模型永久保存,下次上课可以直接使用保存的分组。 8.随堂小考 使用此功能,教师可以启动快速的单题考试或随堂调查,并立即给出结果。 9.系统日志 显示和自动保存系统运行过程中的关键事件,包括学生登录登出,电池电量,资源不足,提交文件等。 极域电子教室 注意事项 1.安装本产品前,如果已安装我公司以前的版本或同类软件,请先将以前版本或同类软件移除后,再进行安装。 2.安装本软件后,请一定要重新启动计算机才可使用。如果不重新启动计算机,有可能会造成本软件的某些功能不能正常使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值