昨天的简单的计算已经告诉了我们
用TCP/IP来发送服务器桌面信息
服务器端发出一张图片大概需要的时间是200MS
(所谓发出,即打包完成到发送结束----调用输出流的flush()方法截止)
那我们其实能做到的也就是一秒钟发送5张图片
把服务器端发送图片的时间间隔改成200MS后
发现服务器端和客户端的屏幕传输还算是比较正常
能够及时看到服务器端的操作
恩
基本改良咱是实现了
可是,咱不能满足
好吧,服务器端看电影,
客户端连接看看情况怎么样
额,客户端连上后
发现看到的电影里的人动作是不连贯的
WHY?
大伙都做到
电影是24帧每秒
而我们现在用TCP/IP就算用多线程
发挥网络最大能量(我们寝室的网络)
一秒也就传了5帧
这肯定是没办法正常看电影的
好了
现在问题提出来了
这种情况下
我们应该怎么样继续改良呢?
恩
大伙都知道
TCP/IP是面向连接、可靠的传输
用TCP/IP只要网络是通的
咱就可以放心,不怕数据传布过去
过去了不怕它收不到
可是出来混,总得有代价嘛
其中的3次握手,差错重传等等功能开销都是很大的
TCP/IP提供了可靠性以后
传输速度啥的自然就受到了很大的影响
而UDP是无连接、不可靠的传输
它不需要提供负责的连接机制,不需要理会差错控制
UDP只管作死的一个劲往外发
至于收不收的到,收到多少,则是跟哥无关的事
在对实时性要求很多的情况下
我们都只想能尽可能的多传输一些数据过去
就顾不上考虑那么多差错控制啥的了
(你这边在看直播,如果传输有差错了,总不能暂停一下,回过头来再回放,然后继续吧?)
这个时候,适当的差错是可以容忍的
实时是第一位的
好吧
既然一堆废话解析已经说的差不多了
现在
就正式开始通过UDP传输来改造俺们滴远程控制系统
其实在原有系统的基础上
基本上可以什么都不用变
改几行代码就差不多了
首先
其他的操控类信息还是要求要准确的
所以我们继续保留原有的TCP/IP连接中的SOCKET连接
这一部分都不动
原有系统协议,构架都不动
我们要实施UDP传输改良性能
无非就是把图片传输这个绝对巨头用UDP处理掉
所以
我们需要该的代码其实只是如下
在服务器端,用UDP发送取代用SOCKET发送
// 原有的用Socket发送图片的语句
// clientInfo.getThread().sendMessage(_screenImageMessage);
//用UDP发送的语句
java.net.InetAddress clientIP = clientInfo.getIPaddress();
int port=10000;//设置UDP端口为10000
byte[] data = _screenImageMessage.pack();
//封装为DatagramPacket
DatagramPacket datapacke = new DatagramPacket(data,data.length,clientIP,port);
//用来发送的DatagramSocket对象
DatagramSocket castSocket = new DatagramSocket(11000);
castSocket.send(datapacke);
Log.recordTime("结束发送截屏图像");
在客户端,用UDP接收,取代用SOCKET接收,至于什么接收图片监听啥的都不用改了
把用UDP接收图片独立开一个线程,连接成功后,自动启动该线程
代码如下
public class ReciveScreenImageUDP extends Thread{
Client _client;
public ReciveScreenImageUDP(Client client) {
_client = client;
}
public void run(){
reciveUDPMessage();
}
public void reciveUDPMessage() {
while (true) {
try {
DatagramSocket reciveImageSocket = new DatagramSocket(10000);
// 定义缓冲区大小
byte[] buffer = new byte[250000];
DatagramPacket recivedPacket = new DatagramPacket(buffer,
buffer.length);
reciveImageSocket.receive(recivedPacket);
// 接收完字节数组,开始解封,处理
MessageHead message = UnpackMessageTools
.unpackUDPimageMessage(buffer);
_client.UDPMessageHandle(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
好了
问题出来了
咱又得开始说废话,讲道理,玩数学了
首先,我想大家应该明白一点
UDP中传输数据都是以DatagramPacket为单位传的
也就是说,我们接收也是一个pachet一个packet的来接收
那么,接收之前,我们怎么知道每个packet里面数据量的大小呢?
恭喜你
答对了
我们就是不知道
所以
我们必须用到缓冲区数组buffer来接收packet
buffer设置小了,那么剩下的那部分数据你是收不到的
人家发送方是不对你负责的,谁叫你Y自己小气,舍不得把buffer设大一点呢
于是有人说
我们就把buffer设大一点吧
你还真是大方。。。
只有一小杯水,你开一辆卡车去运,有必要吗?
我们得通过算数来解决问题的
要算数
我们首先得知道我们到底需要多大的缓冲区
才能够完整的接收packet,同时还不能太浪费,注意,我说的是太浪费
恩,那我们还是先知道每次对方传来的数据有多大吧
好,那我们就测试,每次生成的图片大概有多大
需要测试这个,无非就是,截个屏,化为数组,看下大小
测试代码如下,比较简单,就不废话来解释了
/**
* 用来测试每次截屏生成图片大小的类
* @author mzd
*/
public class ImageSizeTest {
/**
* @param args
* @throws AWTException
*/
public void getImageSize() throws AWTException {
java.awt.Robot rb = new java.awt.Robot();
Dimension d = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
Rectangle rt = new Rectangle(0, 0, (int) d.getWidth(), (int) d
.getHeight());
byte[] data = null;
for (int i = 0; i < 1000; i++) {
BufferedImage image = rb.createScreenCapture(rt);
data = bufferedImageTobytes(image);
System.out.println(i + "--------图片--------->" + data.length);
}
}
private byte[] bufferedImageTobytes(BufferedImage image) {
BufferedImage bImage = new BufferedImage(image.getWidth(null), image
.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics bg = bImage.getGraphics();
bg.drawImage(image, 0, 0, null);
bg.dispose();
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
ImageIO.write(bImage, "jpeg", out);
} catch (IOException e) {
e.printStackTrace();
}
return out.toByteArray();
}
public static void main(String args[]) throws Exception {
ImageSizeTest test = new ImageSizeTest();
test.getImageSize();
}
}
我运行了1000次来观测,在这里就不可能贴出1000次的结果了
随机截取一部分吧
299--------图片--------->184001
300--------图片--------->183878
301--------图片--------->183825
302--------图片--------->183796
303--------图片--------->183710
304--------图片--------->183705
305--------图片--------->183705
306--------图片--------->183827
307--------图片--------->183827
308--------图片--------->183827
309--------图片--------->183921
310--------图片--------->184064
311--------图片--------->184040
312--------图片--------->183792
313--------图片--------->183809
314--------图片--------->183900
315--------图片--------->183867
316--------图片--------->183789
317--------图片--------->183871
318--------图片--------->183691
319--------图片--------->183685
320--------图片--------->183666
321--------图片--------->183666
322--------图片--------->183666
323--------图片--------->183666
324--------图片--------->183666
325--------图片--------->183666
326--------图片--------->183666
327--------图片--------->183666
328--------图片--------->183961
329--------图片--------->183961
330--------图片--------->183961
331--------图片--------->183961
332--------图片--------->183961
333--------图片--------->184059
|
很明显,我们发现每个图片的应该在200000左右
为了保险起见,
我们把缓冲区再设大点
250000
好了
废话完了
代码改完了
咱执行一次看看?
java.net.SocketException: The message is larger than the maximum supported by the underlying transport: Datagram send failed
at java.net.PlainDatagramSocketImpl.send(Native Method)
at java.net.DatagramSocket.send(DatagramSocket.java:612)
at cn.javaeye.java_mzd.Monitor.Server.CastScreenImageUDP.castScreenImage(CastScreenImageUDP.java:49)
at cn.javaeye.java_mzd.Monitor.Server.CastScreenImageUDP.run(CastScreenImageUDP.java:22)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
|
我勒个去……………………
辛辛苦苦,看我废话半天
改了半天
结果不行?
这也太恶心
太丢脸了
哎
我没办法
别急
咱再慢慢分解
首先
咱看报的错误
The message is larger than the maximum supported by the underlying transport: Datagram send failed
大家英语都比我好
都看的明白
简单的说
就是传的文件比Datagram允许的大了
这是怎么回事?
人家几个G都能传
我这么小个图片竟然不能传?
TCP/IP都能传
我UDP还不能传?
嘿
恭喜你答对了
TCP/IP能传
你用UDP直接用packet还就是传不了
(注意,我是说直接用packet)
恩
这是为什么呢?
还记得前面我废话过TCP/IP可以差错控制什么的嘛?
用TCP的时候
协议会把大文件分块成许多小块
发表路由发送至目的地后
再通过标识来重组,对没有成功发送的提供差错控制
完成重传
而UDP不提供此功能(当然,你可以直接去完善,那不是我今天讨论的内容)
好了
回到正题
为什么UDP会传不了呢?
我们知道
不管用UDP还是TCP最后得被封住成IP数据包
而一个IP数据报的总长度只是用16位来表示
16位,什么概念呢
也就是最多可以放64KB的数据
再回头看看我们截屏的图片大小
200KB
所以……………………
好了
休息会
下期分解
JAVA中图片有损压缩
分享到:
相关推荐
在远程监控系统中,UDP 可能是更适合的选择,特别是在需要处理大量并发连接、实时性要求高或者需要穿透NAT(Network Address Translation)的场景。 首先,让我们分析一下TCP和UDP在远程监控系统中的应用场景和优劣...
在本项目中,我们主要关注的是使用C#编程语言实现基于UDP协议的远程监控摄像头功能。UDP(User Datagram Protocol)是一种无连接的、不可靠的传输层协议,适合于需要实时性但对数据完整性要求不高的应用,如视频监控...
【基于UDP的远程屏幕监控】...总的来说,基于UDP的远程屏幕监控系统利用C++Builder的开发能力,结合网络编程和图形处理技术,实现了高效、实时的屏幕共享功能。这种技术在远程协助、监控、教育等多个领域都有广泛应用。
基于JAVA C/S远程监控系统软件突破了空间的限制,使用者不用亲临,在自己的电脑面前就能轻松的实现对被监控端机器的监控。本系统采用Java网络编程和Java图形编程实现。笔者在开发过程中将网络技术与远程监控理论基础...
本文所提到的Web远程电源监控系统,是一个典型的使用UDP协议的场景。这种系统通常需要将电源设备的数据实时传输到远程监控中心,以便监控人员可以实时了解设备的电源状态。由于实时性要求非常高,系统往往需要在尽...
JAVACS远程监控系统中使用了多种网络通信协议,包括TCP/IP、UDP以及Telnet。TCP/IP是互联网上最广泛使用的网络协议,提供可靠的数据传输。UDP则是一种无连接的协议,适用于传输不需要可靠传输保证的数据。Telnet是一...
### 基于Android的远程监控系统综合课程设计的关键知识点 #### 一、设计背景与概述 本设计针对当前视频监控技术的需求和发展趋势,提出了一个基于Android系统的远程监控方案。随着科技的进步,尤其是网络技术和...
在IT领域,基于VC(Visual C++)的远程监控系统是一种常见的应用,它结合了计算机视觉、网络通信和多媒体处理技术,使得用户可以实时监控远端的摄像头画面。本项目提供的是一个服务器端与客户端(接受端)的完整工程...
【标题】"用C++语言编写的远程监控系统"揭示了这个项目的核心是利用C++编程语言构建一个能够实现远程监控功能的系统。C++是一种强大的、面向对象的编程语言,广泛应用于系统软件、游戏开发、实时金融系统以及各种...
基于LabVIEW的远程监控系统设计与实现,是一个集成了现代通信技术、计算机科学与控制理论的综合项目。本文档详细介绍了如何利用LabVIEW这一强大的图形化编程环境来构建一个高效、可靠的远程监控系统,适用于工业自动...
4. **实际应用**:UDP远程控制可能被用在设备监控、智能家居系统、分布式计算等场景,允许用户远程控制和管理设备或系统。 5. **开发注意事项**: - **防火墙配置**:确保服务器的UDP端口在防火墙中开放,允许...
"基于Android的远程监控系统的设计与实现" 本文主要介绍了一种基于Android的远程监控系统的设计与实现。该系统旨在解决当前数控机床操控具有局限性的问题,提供了一种功能强大、操作简单的远程监控解决方案。 首先...
javaTCP、UDP和RMI实现的远程监控,可以语音通信javaTCP、UDP和RMI实现的远程监控,可以语音通信
在这个场景中,我们关注的是一个使用VC++(Visual C++)开发的远程监控系统。VC++是Microsoft开发的一个集成开发环境,支持C++语言,提供了丰富的库和工具,适合构建复杂的桌面应用程序,包括系统级和网络通信程序。...
/// 发送器所使用的编码 /// public Encoding Encoding { get; set; } /// /// 启动发送器 /// /// <returns>UDP发送器 public UdpSender Start() { if (!IsRunning) { IsRunning = ...
综上所述,基于VC++的远程桌面监控系统涉及的技术范围广泛,包括但不限于MFC库的使用、客户端-服务器通信、UDP协议、屏幕捕捉与图像处理、网络编程以及可能的视频处理技术。在实际开发过程中,还需要考虑安全性、...
在C#中,我们可以利用.NET Framework或.NET Core提供的丰富的库和API来构建远程监控系统。 1. **基础架构**:构建远程监控系统的第一步是设计合适的架构。通常包括客户端(监测和发送请求)、服务器端(接收请求并...
【基于UDP的聊天室监控系统】是一个利用UDP协议实现的实时通信系统,它不仅具备基本的聊天功能,还集成了服务器对客户端的监控能力。在这个系统中,服务器不仅可以接收和发送消息,还可以监控客户端的屏幕活动,实现...
对于开发者来说,理解和掌握这些知识点,能够帮助他们构建自己的远程监控系统,满足特定需求。同时,源码分析和学习也是一个很好的实践机会,可以帮助提升编程技能,尤其是网络编程和多媒体处理方面的能力。