现在的位置: 首页 > 综合 > 正文

桌面共享的实现

2013年01月01日 ⁄ 综合 ⁄ 共 3392字 ⁄ 字号 评论关闭

1.大二暑假在东软做了个项目“一起上课吧”,是一个linux下的电子教室系统。在局域网内使用,要做两个程序,一个教师端,一个学生端。主要功能是桌面共享、文件收发、即时通讯、监视学生机桌面、控制学生机的功能。用途主要用于教师授课、学生管理等,用c语言做的,使用gtk+来做的界面。

2.我主要负责屏幕共享这块,主要思想就是不断的截取屏幕图像,广播到其他机器上。

3.为了达到更好的效果,我使用了差位算法的思想,把整个屏幕分成若干个区域,每次只是把发生图像发生变化的区域发送出去。具体的怎么划分,划分多少块最好,是没有标准的,并不是说划分的越细就越好,因为划分,以及判断图像是否变化也需要消耗时间,这个时间和网络传输时间要找到一个最高效的点,我们当时的思路是,电子教室主要是用来讲课,演示ppt的,所以就模拟这个场景进行不断测试,最后得到一个效率最高的屏幕划分方法,竖着分8块横着分10块。

教师端:

主要是利用gtk库中对应的api首先获取屏幕截图,然后分块,每次把发生变化的发送出去(我只是通过计算图形二进制数据的大小来判断是否改变,基本没有问题。如果想更精确判断图形是否变化,则涉及到图形学里的分布取像素点的比较算法,这里不赘述)。

项目中相关具体代码如下:

while(1) //just send the blocks changed
	{
		gdk_threads_enter();
		for(x=0;x<V_BLOCKS;x++)
		{
			start_x=block_height*x;//	figure the block's x point 
			
			for(y=0;y<H_BLOCKS;y++)
			{   
				start_y=block_wigth*y;//	figure the block's y point 
				//get pixbuf of the scrren block
				pixbuf= gdk_pixbuf_get_from_drawable (NULL, window,NULL,start_y,
					start_x, 0, 0,block_wigth,block_height);
				pixbuf_simple=gdk_pixbuf_scale_simple(pixbuf,100,100,GDK_INTERP_BILINEAR);
				//GET the char data of picture
				gdk_pixbuf_save_to_buffer(pixbuf_simple, &pic_buf,&pic_buf_size, "jpeg", NULL, 
						"quality","60", NULL);
				if(old_size[x][y]!=pic_buf_size &&pic_buf_size<=BLOCK) //changed  
				{
					old_size[x][y]=pic_buf_size;//save the char data's size
					//set the data to the grid 
					send_grid.x=x;
					send_grid.y=y;
					send_grid.total_size=pic_buf_size; 
					memcpy(send_grid.data,pic_buf,pic_buf_size);
					//send the grid
					sendto(socket_fd, &send_grid, sizeof_grid, 0, (struct sockaddr *)&addr_teacher, len); 
				}

				//free the memory
				free(pic_buf);
				g_object_unref (pixbuf_simple);
				g_object_unref (pixbuf);  //free pixbuf
			}
		}
		gdk_threads_leave();
	}


学生端:

就是不断的去接受数据,接收到数据后转成对应的图片格式填入到相应的屏幕位置。

我的项目中具体代码如下:

void * receive_pixbuf(void * arg)
{
	int sizeof_grid=sizeof(grid); //grid's size
	grid receive_grid={0}; //temp grid to save the data rececived
	int x,y,start_x,start_y;
	gint a, b;
	int receive_num,socket_fd,len,maxfdp;
	GdkPixbuf* pixbuf=NULL;
	GdkPixbufLoader* pixloader;
	struct sockaddr_in addr_client; 
	fd_set fds; 
	struct timeval timeout={5,0}; //select等待1秒,1秒轮询 

	socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
	maxfdp=socket_fd+1;
	
	if(socket_fd ==1)  
	{  
		printf("socket error");  
	}
	len = sizeof(addr_client);
	bzero(&addr_client, len);

	addr_client.sin_family = AF_INET;  
	addr_client.sin_port = htons(PORT);    //set port
	addr_client.sin_addr.s_addr = htonl(INADDR_ANY);  //set ipaddr

	if(bind(socket_fd, (struct sockaddr *)&addr_client, len) < 0)  
	{  
		printf("bind error:");  
	}


	while(1)
	{
		gdk_threads_enter();
		FD_ZERO(&fds); //每次循环都要清空集合,否则不能检测描述符变化
		FD_SET(socket_fd,&fds); //添加描述符 

		switch(select(maxfdp,&fds,NULL,NULL,&timeout))   //select使用 
		{ 
			case 0:
				break; //再次轮询
			default: 
				if(FD_ISSET(socket_fd,&fds)) //测试sock是否可读,即是否网络上有数据
				{ 
					//receive the data and save to receive_grid
					recvfrom(socket_fd, &receive_grid, sizeof_grid, 0,
							(struct sockaddr *)&addr_client, (socklen_t *)&len);

					pixloader=gdk_pixbuf_loader_new_with_type("jpeg",NULL);//init a pixloader

					//get coordinate x and y
					x=receive_grid.x;
					start_x=BLOCK_HEIGHT*x;
					y=receive_grid.y;
					start_y=BLOCK_WIGTH*y;
					
					//get pixbuf from pixloader
					gdk_pixbuf_loader_write(pixloader,receive_grid.data, receive_grid.total_size, NULL);
					pixbuf=gdk_pixbuf_loader_get_pixbuf(pixloader); 
					//show the pixture in imagebox
					gtk_image_set_from_pixbuf(GTK_IMAGE(ourgif[x][y]),pixbuf);
					
					//free the memory
					g_object_unref(pixbuf);
					gdk_pixbuf_loader_close (pixloader,NULL);
				}// end if break; 
		}// end switch 
		gdk_threads_leave();
	}
}

每块大小是64×64。测试阶段将变化块直接输出到图形文件(居然没删),win7下打开效果如下:

                                                                  

桌面的空白区域你懂得                           Terminal 上的一小块变化区域

注:

@代码没有多少价值,主要是差位传输图像的思想比较有用。

@所以这里没有贴出全部代码,一些变量的定义,函数的解释,和头文件中的一些宏定义也没列出。

@如果有兴趣,或则有需要可以联系我共同探讨。

PS:个人比较喜欢中文注释,但是当时在红帽上开发,中文输入法总是出问题,用着不爽,所以用了一些简单的英文注释大笑

抱歉!评论已关闭.