文章目录

  • 网络的连接
  • 服务器连接部分
  • 客户端连接部分
  • socket模块
  • 传输视频模块
  • 总结


网络的连接

首先构建网络连接模块。

服务器连接部分

要实现两个人的视频通话,首先我们需要将两个台设备通过互联网连接起来,使他们之间可以通讯。

  1. 一台电脑要作为服务器端口,等待其它电脑的连接。
  2. Java代码如下:
public boolean connet2server() {
		try {
			ServerSocket ss = new ServerSocket(9999);
			Socket client = ss.accept();
			System.out.println("等待客户连接");
			InputStream input = client.getInputStream();
			DataInputStream data = new DataInputStream(input);
			OutputStream out = server.getOutputStream();
			DataOutputStream dataout = new DataOutputStream(out);
			return true;
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
}

客户端连接部分

  1. 另一台电脑要作为接入端,通过服务器的ip地址和端口号接入服务器。
  2. Java代码如下:
public boolean connet2server() {
		try {
			server = new Socket("127.0.0.1", 9999);
			System.out.println("连接服务器成功");
			InputStream input = client.getInputStream();
			DataInputStream data = new DataInputStream(input);
			OutputStream out = server.getOutputStream();
			DataOutputStream dataout = new DataOutputStream(out);
			return true;
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
	}

socket模块

这里调用socket模块来实现网络的连接过程。在初步连接的时候也就是服务器代码ServerSocket ss = new ServerSocket(9999);,Socket client = ss.accept();和客户server = new Socket(“127.0.0.1”, 9999); 就是根据IP地址和端口号将服务器和客户端通过网络连接起来。这里socket调用的是tcp/IP协议。连接的时候客户端先向给出的IP地址和端口号发送一段信息,这里面包括一些简历连接时候需要的一些初始化信息,然后服务器根据这些信息初始化连接,然后返回消息告诉客户端收到消息,在返回的消息中附带自己的信息发送给客户端,当客户端收到信息后,再向服务器返回一条信息告知服务器,已经收到消息。这就是tcp/ip连接时候的三次握手。这样客户端与服务器就建立了连接,接下来就可以互相传递消息了。之后我们就可以调用socket模块中的输入输出流来传递数据了。

数据再网络中的传输形式就是一些二进制的数据。当服务器发送给客户端一组二进制的数据,客户端怎么知道这些0,1数字要表达什么意思呢?这就需要协议了。两方再最开始的时候就规定好了,怎么去解读这些数据。就像是两个都懂英语的人在对话,他们说的什么,他们自己和对方都很清楚。而英语的语法规则就看作是一个协议。而我们再现在所写的规则是再应用层的规则,我们只管对传过来的数据进行翻译和操作。而对于这些数据是怎么传输的,我们这里不需要关心,我们将数据打包好后,交给socket模块去传输这些数据。socket模块就相当于快递公司。我们传输的数据就相当于要邮递的包裹。

传输视频模块

  1. 安装视频模块
    首先下载Webcam包。配置环境:

java开发视频聊天室 java 视频聊天框架_java


java开发视频聊天室 java 视频聊天框架_数据_02


将Webcam解压后包中的3个扩展文件加入进来。

java开发视频聊天室 java 视频聊天框架_java开发视频聊天室_03


java开发视频聊天室 java 视频聊天框架_客户端_04


按上述步骤,我们就可以使用Webcam这个工具包了。使用这个包之前要确保摄像头是连接可用状态

  1. 传输视频
    首先调用Webcam,获得摄像头拍摄的照片。
    传输视频的Java代码:
import com.github.sarxos.webcam.Webcam;
Webcam webcam = Webcam.getDefault();
webcam.open();
//因为视频是很多照片组成的所以要想成为视频,就必须要一直获得照片
while(true){
	BufferedImage image = webcam.getImage();
	//将照通过网络发送
	trans(image);	
}
public void trans(BufferedImage picture) {
			int w = picture.getWidth(null);
			int h = picture.getHeight(null);
			try {
				dataout.writeInt(w);
				dataout.writeInt(h);
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}			
			for (int i = 0; i < h; i ++) {
				for(int j = 0 ; j < w ; j ++ ) {
					int a= picture.getRGB(j,i);
					try {
						dataout.writeInt(a);
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}

这样我们就发送了一组二进制数组。而接收方也需要按照一定的规则去接受,接收方的代码如下:

// 读图片
		public BufferedImage trans() {
			BufferedImage image;
			try {
				//w是宽 h 是高
				int w = data.readInt();
				int h = data.readInt();
				image = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB); 
				Graphics g = image.getGraphics();

				for (int i = 0; i < h; i ++) {
					for(int j = 0 ; j < w ; j ++ ) {
						int a = data.readInt();
						Color  color=new Color(a);
						g.setColor(color);
						g.drawLine(j, i, j, i);
					}
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				image = new BufferedImage(100,100,BufferedImage.TYPE_INT_RGB); 
				e.printStackTrace();
			}
			return image;
		}

这里我们写完一会,当视频传输的时候会非常的卡顿,这时候我们需要将这个传输方式进行优化
4. 视频传输时候的问题以及改进
这里优化的方式就涉及到了tcp协议中的分包规则了。一个大文件当发送的时候不能整个文件一起发送,而是将一个文件拆开成一个个文件包发送,一次发送一个文件包。每个文件包的大小是有上限的。因为网络传输的原因,不一定先发的就先到,所以我们再发送前要为包标好序号,等到了接收端,再将包的数据按照包的顺序拼接好。同时我们再发送包的时候,也不能收到一个数据就发送,如果这个数据只有1bit,这时候我们发送文件的效率就会很低,将一些文件一起发送这样就会提高传输速率,当数据进入到待发送的缓冲区的时候,计算机还会等一等,尽量的多凑一些数据一起发送。当然也不会一直等,当等了一段时间后,不管包中数据多少,都会将包发送出去。
还有就是,接收方再取包的时候,一次一次的从缓存中将文件取出来这种IO操作也是很费时间的。如果一次多取一些出来,这样可以加快传输效率。
所以我们希望尽可能的一次多的将信息传入发送缓冲区,一个包的数据也尽可能的多一些,也希望一次尽可能多的从缓冲区中取数据,减少IO操作。
优化后的代码如下:

public void trans(BufferedImage image) {

		int w = image.getWidth();
		int h = image.getHeight();
		BufferedImage picture = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
		Graphics g = picture.getGraphics();
		g.drawImage(image, 0, 0, w, h, null);
		try {
			dataout.writeInt(w);
			dataout.writeInt(h);
			Object data = null;
			data = picture.getRaster().getDataElements(0, 0, w, h, null);
			int size = w * h;
			int[] da = (int[]) data;
			System.out.print(",传输大小:" + size / 256 + "KB");
			byte outcontent[] = new byte[size * 4];
			for (int i = 0; i < size; i++) {
				int index = i * 4;
				outcontent[index++] = (byte) ((da[i] >>> 24) & 0xFF);
				outcontent[index++] = (byte) ((da[i] >>> 16) & 0xFF);
				outcontent[index++] = (byte) ((da[i] >>> 8) & 0xFF);
				outcontent[index] = (byte) ((da[i]) & 0xFF);
			}
			out.write(outcontent);
			out.flush();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}
// 读图片
	public BufferedImage trans() {
		BufferedImage image;
		try {
			// w是宽 h 是高
			int w = data.readInt();
			int h = data.readInt();
			image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
			Graphics g = image.getGraphics();			
			byte[] b = new byte[w*h*4];
			data.readFully(b);
			int[] v = new int[w*h];
			for (int j = 0; j < w*h; j++) {
				int index = j*4;		
				v[j] = ((b[index] << 24) + (b[index+1] << 16) + (b[index+2] << 8) + (b[index+3] << 0));
				}
			image.getRaster().setDataElements(0, 0, w, h, v);
			g.drawImage(image, 0, 0, w, h, null);
			System.out.println("====");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
			e.printStackTrace();
		}

总结

网络的传输通讯的根本是在于协议,无论是浏览器中的http协议还是这篇代码中的视频传输协议,都是再应用层上的协议,只对传输过来的数据进行出来,而具体网络是如何传输的,都交给socket模块取处理。但我们还是要了解网络传输的基本规则,这可以让我们再制定应用层协议的时候更好的利用底层协议的规则,提升传输效率。