初涉通讯的一些感受和想法4 远程控制
初涉通信的一些感受和想法4 远程控制
远程控制算是进入通信以来最用心的一个小项目吧,遇到了不少困难,但都凭自己的努力解决了,看着基本功能都实现了的程序(虽然结构有点丑),感觉还挺不错。刚开始的时候就觉得书上的方法很看不懂,怎么搞也觉得不满意,心想:靠,自己搞!于是便抛开了书本,开始了my远程控制的编写。
花了一天半时间,终于把所有问题都解决了,和书上的一比较,差别还挺大
差别1:
书上是用了把屏幕图片根据控制端窗口大小的变化而变化显示的思路,而我是用了JScrollPane的思路,感觉JScrollPane思路的用户体验应该会更好。同时也解决了两端屏幕大小适配的问题。
差别2:
书上是直接发送了事件对象数据,而我是根据事件的不同,定义了不同的byte,并把所需参数一并传过去 感觉书上的更符合面向对象的思维吧。
当然,遇到的问题也是各种各样的
问题1:怎么把在控制端窗口JScrollPane界面上的鼠标位置来计算出请求端屏幕的真实位置?
测试步骤1:把监听器加在JScrollPane/JFrame上,得到的数据是JFrame的对应位置,无法解决问题。
测试步骤2:查找比较调试JScrollPane在API的各种方法,终于得到了解决方法:
问题2:错误代码
运行之后的结果就是图片显示之后就再也不改变了,大家知道是为什么吗?这个问题很恶心,让我纠结了很久。
测试步骤1:在dos.flush()后加上System.out.println("发送"+imgBytes.length);输出数据摘取如下:
发送148660
发送297320
发送447005
发送597210
(以前测试的时候还报了一个Java heap的错误)
仔细的朋友一定发现了,发送的字节数很相似一个等差数列!根据逻辑来说,每张屏幕图片的大小都应该差不多才对!
测试步骤2:翻阅API,发现ByteArrayOutputStream的解释是这么说的:
此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。
关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。 而我定义的ByteArrayOutputStream在while循环外,每次ImageIO都往ByteArrayOutputStream写入一个图像数组,而ByteArrayOutputStream也没write出去,所以得到的数组大小才会成等差数列,再加上字节数组前面组成一幅图片的字节根本没变,所以收到的图片也一直不变。
解决的方法有两个:一个是把bout = new ByteArrayOutputStream();写入到while循环内,一个是用该类提供的reset方法 将此 byte 数组输出流的 count 字段重置为零,从而丢弃输出流中目前已累积的所有输出。个人还是比较倾向于第二种方式吧,毕竟不用多次创建ByteArrayOutputStream对象。
其余的一些小问题和解决方法:
1.KeyListener要添加在JFrame上而不能添加在JScrollPane上
2.鼠标事件是左键还是右键可以通过控制端的e.getButton()来区分(左键是1,右键是3),而请求端的robot对象区分鼠标左右键是通过InputEvent.BUTTON1_MASK InputEvent.BUTTON3_MASK来区分的,从常量字段值查到左键是16,右键是4,写一个公式转化成1和3对应的值,ok
总的来说,这个小项目不单止让我巩固了通信的知识,还让我懂得了面对困难怎么解决困难的方法,同时也让我增加了面对困难的信心。遇到困难时,先分析可能碰到的错误,再通过API文档搜集资料,再写Test程序来调试验证,最终解决困难。
觉得通信真的是越来越有意思了。
ps:附上今天问胡_总的问题,怎么获得本地IP地址
远程控制算是进入通信以来最用心的一个小项目吧,遇到了不少困难,但都凭自己的努力解决了,看着基本功能都实现了的程序(虽然结构有点丑),感觉还挺不错。刚开始的时候就觉得书上的方法很看不懂,怎么搞也觉得不满意,心想:靠,自己搞!于是便抛开了书本,开始了my远程控制的编写。
花了一天半时间,终于把所有问题都解决了,和书上的一比较,差别还挺大
差别1:
书上是用了把屏幕图片根据控制端窗口大小的变化而变化显示的思路,而我是用了JScrollPane的思路,感觉JScrollPane思路的用户体验应该会更好。同时也解决了两端屏幕大小适配的问题。
差别2:
书上是直接发送了事件对象数据,而我是根据事件的不同,定义了不同的byte,并把所需参数一并传过去 感觉书上的更符合面向对象的思维吧。
当然,遇到的问题也是各种各样的
问题1:怎么把在控制端窗口JScrollPane界面上的鼠标位置来计算出请求端屏幕的真实位置?
测试步骤1:把监听器加在JScrollPane/JFrame上,得到的数据是JFrame的对应位置,无法解决问题。
测试步骤2:查找比较调试JScrollPane在API的各种方法,终于得到了解决方法:
int vMove = jcp.getVerticalScrollBar().getValue();//得到纵向滚动条偏移像素 int hMove = jcp.getHorizontalScrollBar().getValue();//得到横向滚动条偏移像素再分别加上鼠标相对于JFrame的位置(e.getX(),e.getY())即可得到请求端鼠标的真实坐标
问题2:错误代码
Robot robot = new Robot(); bout = new ByteArrayOutputStream(); while(true){ BufferedImage screenImage = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())); //将图片发送出去 //将图像写入到字节数组输出流 ImageIO.write(screenImage, "jpeg", bout); //得到图片的字节数组 byte[] imgBytes = bout.toByteArray(); dos.writeInt(imgBytes.length); dos.write(imgBytes); dos.flush(); }
运行之后的结果就是图片显示之后就再也不改变了,大家知道是为什么吗?这个问题很恶心,让我纠结了很久。
测试步骤1:在dos.flush()后加上System.out.println("发送"+imgBytes.length);输出数据摘取如下:
发送148660
发送297320
发送447005
发送597210
(以前测试的时候还报了一个Java heap的错误)
仔细的朋友一定发现了,发送的字节数很相似一个等差数列!根据逻辑来说,每张屏幕图片的大小都应该差不多才对!
测试步骤2:翻阅API,发现ByteArrayOutputStream的解释是这么说的:
此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。
关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。 而我定义的ByteArrayOutputStream在while循环外,每次ImageIO都往ByteArrayOutputStream写入一个图像数组,而ByteArrayOutputStream也没write出去,所以得到的数组大小才会成等差数列,再加上字节数组前面组成一幅图片的字节根本没变,所以收到的图片也一直不变。
解决的方法有两个:一个是把bout = new ByteArrayOutputStream();写入到while循环内,一个是用该类提供的reset方法 将此 byte 数组输出流的 count 字段重置为零,从而丢弃输出流中目前已累积的所有输出。个人还是比较倾向于第二种方式吧,毕竟不用多次创建ByteArrayOutputStream对象。
其余的一些小问题和解决方法:
1.KeyListener要添加在JFrame上而不能添加在JScrollPane上
2.鼠标事件是左键还是右键可以通过控制端的e.getButton()来区分(左键是1,右键是3),而请求端的robot对象区分鼠标左右键是通过InputEvent.BUTTON1_MASK InputEvent.BUTTON3_MASK来区分的,从常量字段值查到左键是16,右键是4,写一个公式转化成1和3对应的值,ok
总的来说,这个小项目不单止让我巩固了通信的知识,还让我懂得了面对困难怎么解决困难的方法,同时也让我增加了面对困难的信心。遇到困难时,先分析可能碰到的错误,再通过API文档搜集资料,再写Test程序来调试验证,最终解决困难。
觉得通信真的是越来越有意思了。
ps:附上今天问胡_总的问题,怎么获得本地IP地址
String addr = InetAddress.getLocalHost().getHostAddress();//得到主机地址