远程控制(1)
先说一下上次的类似qq截图的那个东西,实在有够菜的,见笑了
那么现在我开始做的是一个类似qq远程协助的东西,全屏截图压缩发送这个在所难免的了。对于用Windows Hook进行窗口事件拦截截图这个功能我还是卡在哪里,每次调试都搞到explorer关闭,有次还差点死机了。。。。。。
所以我还是先做传输和控制的部分了,那么就开始吧
一.图片发送,我很蠢的选择了udp作为图片传送方式,最后搞到挺麻烦的(数据整合)
首先我们先截图(废话),同时保存在一个内存流中,就是方便呀
private MemoryStream ImageStream = new MemoryStream();
ScreenImage.Save(ImageStream, System.Drawing.Imaging.ImageFormat.Jpeg);
ScreenImage.Save(ImageStream, System.Drawing.Imaging.ImageFormat.Jpeg);
ScreenImage是内存中截屏后的图片,将它保存到ImageStream这个内存流中,我有想过这是不是多此一举,同是内存里面的东西,何必要转来转去呢?希望高手可以稍微说说这个问题。
下面就到了封包的环节了,这里就需要定义自己的数据包结构了,我做得简单点,请看下面
struct ImageBlock
{
public int Num;
public Byte[] Content;
public int ContentLen;
public ImageBlock(int Num, int Length, Byte[] Content)
{
this.Num = Num;
this.Content = Content;
this.ContentLen = Length;
}
public ImageBlock(int Num)
{
this.Num = Num;
ContentLen = 2040;
Content = new Byte[2040];
}
public Byte[] ToBytes(out int length)
{
Byte[] one = BitConverter.GetBytes(Num);
Byte[] two = BitConverter.GetBytes(ContentLen);
length = one.Length + Content.Length + two.Length;
Byte[] Bytes=new Byte[length];
one.CopyTo(Bytes, 0);
Content.CopyTo(Bytes, one.Length);
two.CopyTo(Bytes, length-two.Length);
return Bytes;
}
}
{
public int Num;
public Byte[] Content;
public int ContentLen;
public ImageBlock(int Num, int Length, Byte[] Content)
{
this.Num = Num;
this.Content = Content;
this.ContentLen = Length;
}
public ImageBlock(int Num)
{
this.Num = Num;
ContentLen = 2040;
Content = new Byte[2040];
}
public Byte[] ToBytes(out int length)
{
Byte[] one = BitConverter.GetBytes(Num);
Byte[] two = BitConverter.GetBytes(ContentLen);
length = one.Length + Content.Length + two.Length;
Byte[] Bytes=new Byte[length];
one.CopyTo(Bytes, 0);
Content.CopyTo(Bytes, one.Length);
two.CopyTo(Bytes, length-two.Length);
return Bytes;
}
}
因为我将缓冲区设定为2048,为什么?我不知道,老师说的。那么我就将包大小设成2048
4(int)+2040(byte[])+4(int)=2048
这个是最大值哦,可以少于这个值,看ContentLen的值决定最后包的大小,一般情况下都是2048
最后一个ToBytes()函数将整个包转成Byte[],因为发送是以字节为单位(说错了别扔鸡蛋)
好了,图片包的数据结构做好了,那么开始封包,无非就是循环循环再循环,ImageStream里面的内容封装到ImageBlock的Content里面,同时给包加上包号(为了客户端接收后按顺序组织)和内容长度。下面是个简单的循环
MemoryStream imagestream = new MemoryStream();
ScreenImage.Save(imagestream, System.Drawing.Imaging.ImageFormat.Jpeg);
long length = imagestream.Length;
int ret = 0;
imagestream.Seek(0, SeekOrigin.Begin);
int begin = 0;
int num = 0;
while (length > 0)
{
ImageBlock block = new ImageBlock(num);
block.ContentLen = imagestream.Read(block.Content, 0, 2040);
length -= block.ContentLen;
if (block.ContentLen < 2040)
block.Num = -1; //读到内存流最后了
else
{
block.Num = num;
num++;
}
int sendlen;
//发送
ret=udpClient.Send(block.ToBytes(out sendlen), sendlen, ClientPoint);
Console.WriteLine(block.ContentLen.ToString());
if (ret < sendlen)
{
//假如发送大小不等于包大小,重发
num--;
imagestream.Seek(-2040, SeekOrigin.Current);
}
}
ScreenImage.Save(imagestream, System.Drawing.Imaging.ImageFormat.Jpeg);
long length = imagestream.Length;
int ret = 0;
imagestream.Seek(0, SeekOrigin.Begin);
int begin = 0;
int num = 0;
while (length > 0)
{
ImageBlock block = new ImageBlock(num);
block.ContentLen = imagestream.Read(block.Content, 0, 2040);
length -= block.ContentLen;
if (block.ContentLen < 2040)
block.Num = -1; //读到内存流最后了
else
{
block.Num = num;
num++;
}
int sendlen;
//发送
ret=udpClient.Send(block.ToBytes(out sendlen), sendlen, ClientPoint);
Console.WriteLine(block.ContentLen.ToString());
if (ret < sendlen)
{
//假如发送大小不等于包大小,重发
num--;
imagestream.Seek(-2040, SeekOrigin.Current);
}
}
嗯,到这里,基本就完成了图片发送了,忘记说了,发送记得要用一个线程独立发送,不然的话,程序就卡在那里了。完整代码我就不给出了,因为我还在做,我自己都觉得实在够乱的,整理麻烦
这里说了文件传送基本流程
获取数据-->设置缓冲区-->定义数据结构-->封包-->发送
希望有高手可以给我指点指点,能让我改进一下,我还是初学者
友情提示:
如需转载本文,请遵守"本站协议"并加入下面声明 且注明原文链接。
作者:kevin wu
来源:kevin wu's corner
by Kevin wu