传输优化
按之前的发送图片时一张图片假如一个一个遍历发送则要分开发送很多次,若一张图片是400,400,则要进行160000次的dout.writeInt(),这个过程十分耗费时间,效率极低,故可将这个二维数组化成一个一维的byte类型数组,则只需要进行一次从客户端到服务端的过程。同样服务器也只需要接受一次。
这里我是自己写了一个int[][]转成byte[]的方法,但这个方法应该不是最优
我们知道了图片长度,即可知道byte数组的长度应是image.getWidth() * image.getHeight() * 4, 故我们先创建一个这个长度的数组
//创建发送的byte[]数组
byte[] send = new byte[image.getWidth() * image.getHeight() * 4];
然后将每个像素点的int型数组转换成byte[4]后加入到这个提前创建的数组
1、将一个int转换成byte[4]
//将int类型数据转换为byte数组
public static byte[] intToByteArray(int i) {
byte[] result = new byte[4];
// 由高位到低位
result[0] = (byte) ((i >> 24) & 0xFF);
result[1] = (byte) ((i >> 16) & 0xFF);
result[2] = (byte) ((i >> 8) & 0xFF);
result[3] = (byte) (i & 0xFF);
return result;
}
2、将int[i][j]这个数据转成的byte数组添加到send数组中
public void addToArray(byte[] send,byte[] b,int i,int j,int Height) {
for (int k=0; k<4; k++) {
int index = i * Height + j ;
index = index * 4 ;
send[index + k] = b[k];
}
}
总的代码如下
```java
public void sendVideo(BufferedImage image) {
//创建发送的byte[]数组
byte[] send = new byte[image.getWidth() * image.getHeight() * 4];
//用int发送视频
try {
synchronized(dout){
//先发报头,视频的报头是2
dout.writeInt('2');
//先发送长度,再发数据
dout.writeInt(image.getWidth());
dout.writeInt(image.getHeight());
for(int i=0 ; i<image.getWidth();i++) {
for(int j=0 ; j<image.getHeight();j++) {
byte[] b = intToByteArray(image.getRGB(i, j));
addToArray(send,b,i,j,image.getHeight());
}
}
dout.write(send);
dout.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//将int类型数据转换为byte数组
public static byte[] intToByteArray(int i) {
byte[] result = new byte[4];
// 由高位到低位
result[0] = (byte) ((i >> 24) & 0xFF);
result[1] = (byte) ((i >> 16) & 0xFF);
result[2] = (byte) ((i >> 8) & 0xFF);
result[3] = (byte) (i & 0xFF);
return result;
}
//将每一个int转换的byte数组添加到总的数组中
public void addToArray(byte[] send,byte[] b,int i,int j,int Height) {
for (int k=0; k<4; k++) {
int index = i * Height + j ;
index = index * 4 ;
send[index + k] = b[k];
}
}
服务端也是同样类似的操作
线程同步
若需要加入不同的功能,如视频的同时在客户端画一笔线,这个线也在服务器端显示出来。此时用监听器发送数据时,若用同一个输出流,则视频传的字节和画线传的字节相当于同时向杯子倒水,这时候服务器端接受时本来在接受视频数据,下一个可能参杂了画线数据,一个字节乱了后面就都乱了。
所以我们用线程同步关键字synchronized(要锁住的对象){要锁住的东西} 这个时候,将某一对象锁住时,若有多个不同的进程要使用这个对象,则必须要等这个{}中要锁住的东西执行完后才能进行
try {
synchronized(dout){
//先发报头,视频的报头是2
dout.writeInt('2');
//先发送长度,再发数据
dout.writeInt(image.getWidth());
dout.writeInt(image.getHeight());
for(int i=0 ; i<image.getWidth();i++) {
for(int j=0 ; j<image.getHeight();j++) {
byte[] b = intToByteArray(image.getRGB(i, j));
addToArray(send,b,i,j,image.getHeight());
}
}
dout.write(send);
dout.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
双缓存画布
在服务器接受时使用双缓存画布,否则速度非常慢