简显易懂的TCP网络通信零起步(java网络画板,山寨腾讯会议)

之前写过一篇QT实习日志,把自己实训期间的学习过程全部记录下来了,近段时期开始学习网络编程相关知识,决定换一种形式,把自己对TCP/通信相关知识讲得大家容易理解一点,欢迎大家交流。

内容简介

在快速起步之前,我们需要了解几个名词的含义:

  • TCP、IP:Transmission Control Protocol,传输控制协议,IP Internet Protocol,网络互连协议,TCP/IP是基于TCP和IP这两个最初的协议之上的不同的通信协议的大的集合,定义了电子设备如何接入互联网以及数据之间如何相互传输。大家都知道,机器不像人这样聪明,没有协议的传输就是一堆没有用的二进制代码、
  • 端口与套接字:端口可以认为是设备与外界通讯交流的出口,一般客户机是通过不同的端口来连到服务器上的不同服务;TCP用主机的IP地址加上主机上的端口号作为TCP连接的端点,这个端点就叫做套接字Socket,其实理解成插口更好,相当于连接装置,用于将程序和端口连接起来。
  • 客户端与服务端:略

快速上手

基本过程

理论知识很多,落到编程这里就只有几行代码了
服务端:

	//建立绑定在指定端口上的服务器对象
	ServerSocket serverSocket = new ServerSocket(port);
	//让服务器进入等待状态
	Socket client = serverSocket.accept();
	//获取输入输出流
	OutputStream out=client.getOutputStream();
	InputStream ins=client.getInputStream();
	//关闭
    client.close();//关闭与客户机的连结

客户端与服务端只有在连接服务端的时候有区别
Socket client = new Socket("127.0.0.1",9999);
启动服务端,服务器会进入等待状态,客户端进来就就能取得连接,中间的一系列过程都封装好了,但是这种写法只能连接一个客户端,如果要连接多个可以采用多个线程,后面会讲到

网络画板实现

界面展示

在这里插入图片描述
在服务端画板画一条线,客户端也能显示,在客户端画板画一条线,服务端也能显示。
由于我比较懒,颜色和形状就没去实现了,思路都差不多,具体实现如下

画图板相关知识

java画图板最重要的是要获取画笔,我采用的是Server类继承JFrame,获取父类画笔,然后用画笔的drawLine方法画线。画线的时候需要获取鼠标的点击时的坐标和松开时的坐标,需要用到鼠标监听器。绘画框和监听器都可以建立一个新的类去继承,再在Server里创建对象去调用,我这里采用public class DrawClient extends JFrame implements MouseListener的类声明方法,避免了一些值传递。

I/O相关知识

楼上代码已经获取了输入输出流,客户端服务端连接后,服务端往outputStream里write()什么,客户端里的inputstream里就可以read()到,反之同理,具体的实现细节已由Socket封装。

bug:画的线不大一样

服务端面板画的线在客户端面板上只在特定区域一样,超过了某一个区域线的起始位置或者结束位置就总有地方不对了,出现这种情况的原因很有可能是传输的数据大于一个字节能表示的内容了
我们来看read()方法的声明

/**
* Reads the next byte of data from the input stream. The value byte is
* returned as an int in the range 0 to
* 255. If no byte is available because the end of the stream
* has been reached, the value -1 is returned. This method
* blocks until input data is available, the end of the stream is detected,
* or an exception is thrown.
*
*

A subclass must provide an implementation of this method.
*
* @return the next byte of data, or -1 if the end of the
* stream is reached.
* @exception IOException if an I/O error occurs.
*/
public abstract int read() throws IOException;

可以看到该方法读一个字节的数据并返回一个int型数据,如果有x或y的数据超过了范围就会取余
处理方法1:
由于int类型变量包含4个字节,可以将一个int变量转换成四个字节,再分别发送,在另一端再转换为int类型。
相关代码:

	public void write(int msg) throws IOException {
		int FirstByte  = msg%256;
		int SecondByte = msg/256%256;
		int ThirdByte  = msg/256/256%256;
		int FouthByte  = msg/256/256/256%256;
		outputStream.write(FirstByte);
		outputStream.write(SecondByte);
		outputStream.write(ThirdByte);
		outputStream.write(FouthByte);
	}
	public int byteToInt(InputStream ins) throws IOException {
		int first = ins.read();
		int second = ins.read();
		int third = ins.read();
		int fourth = ins.read();
		return first+second*256+third*256*256+fourth*256*256*256;
	}

处理方法2:
使用dataInputStream和dataOutputStream的writeInt()和readInt()方法
相关代码:

	DataInputStream dataInputStream;
	DataOutputStream dataOutputStream;
	dataInputStream = new DataInputStream(inputStream);
	dataOutputStream= new DataOutputStream(outputStream);
	dataIntputStream.readInt();
	dataOutputStream.writeInt();
	

源代码1

源代码1.1 DrawServer:
package com.drawServer;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JFrame;

public class DrawServer extends JFrame implements MouseListener{
	int x1;
	int y1;
	int x2;
	int y2;
	OutputStream outputStream;
	public DrawServer(){
		
		this.setSize(720, 480);
		this.setTitle("DrawServer");
		this.setVisible(true);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.addMouseListener(this);
	}
	public int byteToInt(InputStream ins) throws IOException {
		int first = ins.read();
		int second = ins.read();
		int third = ins.read();
		int fourth = ins.read();
		return first+second*256+third*256*256+fourth*256*256*256;
	}
	public void setServer(int port) {
		try {
			//建一个服务器对象
			ServerSocket ss = new ServerSocket(port);
			System.out.println(port+"服务器创建成功");
			//等待客户进来
			Socket client = ss.accept();//让客户机连接上来
			System.out.println("有个客户机连接了");
			InputStream ins = client.getInputStream();
			outputStream = client.getOutputStream();		
			
			while(x1!= 'a') {
				System.out.println("准备开始画了");
				//获取线两端的坐标
				x1 = byteToInt(ins);
				y1 = byteToInt(ins);
				x2 = byteToInt(ins);
				y2 = byteToInt(ins);
				super.getGraphics().drawLine(x1, y1, x2, y2);	
			}
			
			client.close();
			
		}catch (Exception ef) {
			// TODO: handle exception
			ef.printStackTrace();
		}
	}
	
	public void write(int msg) throws IOException {
		int FirstByte  = msg%256;
		int SecondByte = msg/256%256;
		int ThirdByte  = msg/256/256%256;
		int FouthByte  = msg/256/256/256%256;
		outputStream.write(FirstByte);
		outputStream.write(SecondByte);
		outputStream.write(ThirdByte);
		outputStream.write(FouthByte);
		System.out.println(msg);
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		DrawServer ds = new DrawServer();
		ds.setServer(9999);
	}
	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		this.x1 = e.getX();
		this.y1 = e.getY();
	}
	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		this.x2 = e.getX();
		this.y2 = e.getY();
		super.getGraphics().drawLine(x1, y1, x2, y2);

		try {
			write(x1);
			write(y1);
			write(x2);
			write(y2);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}
	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

}

源代码1.2 DrawClient:
package com.qqclient;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
	
import javax.swing.JFrame;

public class DrawClient extends JFrame implements MouseListener{
	int x1;
	int y1;
	int x2;
	int y2;
	OutputStream outputStream;
	Graphics g;
	public DrawClient(){
		this.setSize(720, 480);
		this.setTitle("DrawClient");
		this.setVisible(true);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.addMouseListener(this);
		g = this.getGraphics();
		conn2Server();
	}
	public int byteToInt(InputStream ins) throws IOException {
		int first = ins.read();
		int second = ins.read();
		int third = ins.read();
		int fourth = ins.read();
		return first+second*256+third*256*256+fourth*256*256*256;
	}
	public void conn2Server() {
		try {
			Socket client = new Socket("127.0.0.1",9999);
			System.out.println("连接成功");
			InputStream insInputStream = client.getInputStream();
			outputStream = client.getOutputStream();
			while(x1!= 'a') {
				System.out.println("准备开始画了");
				System.out.println(x1);
				x1 = byteToInt(insInputStream);
				System.out.println(x1);
				y1 = byteToInt(insInputStream);
				x2 = byteToInt(insInputStream);
				y2 = byteToInt(insInputStream);
				super.getGraphics().drawLine(x1, y1, x2, y2);
				System.out.println("此时应该画好了"+x1+y1+x2+y2);
			}
		} catch (Exception ef) {
			// TODO: handle exception
			ef.printStackTrace();
		}
	}
	
	public void write(int msg) throws IOException {
		int FirstByte  = msg%256;
		int SecondByte = msg/256%msg;
		int ThirdByte  = msg/256/256%msg;
		int FouthByte  = msg/256/256/256%msg;
		outputStream.write(FirstByte);
		outputStream.write(SecondByte);
		outputStream.write(ThirdByte);
		outputStream.write(FouthByte);
		System.out.println(msg);
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		DrawClient dcClient = new DrawClient();
	}
	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		this.x1 = e.getX();
		this.y1 = e.getY();
	}
	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		this.x2 = e.getX();
		this.y2 = e.getY();
		g.drawLine(x1, y1, x2, y2);

		try {
			write(x1);
			write(y1);
			write(x2);
			write(y2);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		System.out.println(String.valueOf(x1)+y1+x2+y2);
	}
	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

}

双向多线程通信(山寨腾讯会议)

界面展示

在这里插入图片描述
(一个画图区JPanel,一个消息区JTextArea,一个文本域JTextField,一个发送按钮,还有一个视频)

视频传输(待优化)

视频的获取用到了WebCam,网址:http://webcam-capture.sarxos.pl/,调用摄像头并获取图片需要用到以下几行代码:

	//获取摄像头
		Webcam webcam = Webcam.getDefault();
		webcam.open();
		//获取图片
		BufferedImage img = webcam.getImage();

把每一张图片都画在面板上就能实现上图的效果了
鲁迅先生曾经说过,视频是由一帧一帧的图片组成的,而图片又是由一个又一个像素点组成的。我们只要把图片的颜色信息存储在一个二维数组中,再把一个个int类型数据传输过去,再在客户端把点一个一个画出来就可以了(图片rgb颜色信息占三个字节,可以用img.getGRB(x,y)的方法来获取像素点的信息,具体实现在源代码2.4 WebcamThread中)

多线程通信

前面提到过,代码执行完Socket client = serverSocket.accept();服务器进入等待状态,直到客户机连接,这种方法一次只能连接一台客户机,如果要连接多个客户机可以用多线程,因此我们创建一个客户机线程类:

源代码2.1 ClientThread:
package webcam;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

import javax.swing.JTextArea;

public class ClientThread extends Thread{
	
	ArrayList<Socket> ClientPool;
	ServerSocket serverSocket;
	JTextArea jTextArea;
	
	public ClientThread(ServerSocket serverSocket,JTextArea jTextArea) {
		// TODO Auto-generated constructor stub
		this.serverSocket = serverSocket;
		this.jTextArea = jTextArea;
		ClientPool = new ArrayList<>();
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			try {
				Socket client = serverSocket.accept();
				System.out.println("有个客户机连接了");
				ClientPool.add(client);
				WriteThread writeThread = new WriteThread(client,jTextArea);
				writeThread.start();
				
				
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

服务器连接完一个客户端就进行下一个while循环,如果没有客户机进来就会一直卡在Socket client = serverSocket.accept();上,所以要新开一个线程,此外所有的Socket对象都存在了一个ClientPool里,方便调用。考虑到每一个Client的read()方法都在循环等待服务端的write()方法,所以对应每一个Socket对象都要有一个线程去read(),于是创建了WriteThread类 ,并为每一个client创建writeThread对象(应该写成ClientReadThread类的,这里应该是我笔误了)

源代码2.2 WriteThread
package webcam;

import java.io.IOException;
import java.net.Socket;

import javax.swing.JTextArea;

public class WriteThread extends Thread{
	
	Socket client;
	JTextArea jTextArea;
	
	public WriteThread(Socket client, JTextArea jTextArea) {
		// TODO Auto-generated constructor stub
		this.client = client;
		this.jTextArea = jTextArea;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			byte[] newmsg;
			try {
				//取出字节长度
				newmsg = new byte[client.getInputStream().read()];
				System.out.println(newmsg.length);
				byte temp = (byte) client.getInputStream().read();
				System.out.println(temp);System.out.println(newmsg.length);
				for(int i=0;i<newmsg.length;i++){
					newmsg[i] = temp;
					System.out.println(temp);
					if(i==newmsg.length-1) break;
					temp = (byte) client.getInputStream().read();
				}
				String new_str = new String(newmsg);
				System.out.println(new_str);
				jTextArea.append(new_str+'\n');
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

输入输出流的读写冲突问题

这里为了做一个山寨版腾讯会议,老师能给学生演示,在画板上能跟踪鼠标画图,也让Server实现了MouseMotionListener监听器,在mouseDragged()方法里实时传输鼠标拖拽时的位置信息
由于在鼠标拖拽时和发送信息时都能往inputStream里写数据,I/O流的读写就会起冲突,**这就体现了协议的重要性!**在每次传输数据时可以先将数据包装,即加一个信息头,这里由于只有两个地方写数据,信息头比较简单,我这里用0表示发送的是消息,用1表示发送的是绘图信息,用2表示发送的是视频信息

其余源代码

源代码2.3 Server:
package webcam;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import com.github.sarxos.webcam.Webcam;
import com.sun.org.apache.xerces.internal.impl.io.UTF8Reader;
import com.sun.xml.internal.stream.writers.UTF8OutputStreamWriter;

public class Server extends JFrame implements MouseListener,MouseMotionListener,ActionListener{
	
	Graphics g;
	int[][] data; 
	FlowLayout flowLayout;
	
	//窗体组件 
	JPanel jPanel;//画图板
	JTextField jTextField;//输入框
	JTextArea jTextArea;//消息框
	JButton send_button;//发送按钮
	
	//绘画变量
	int x,y;
	
	//线程
	ClientThread clientThread;

	@SuppressWarnings("deprecation")
	public Server(int port) throws IOException {
		// TODO Auto-generated constructor stub
		
		jTextArea = new JTextArea(10,60);
		jTextField = new JTextField(20);
		send_button = new JButton("发送");
		send_button.addActionListener(this);
		jPanel = new JPanel();
		Dimension preferredSize = new Dimension(660,180);
		jPanel.setPreferredSize(preferredSize);
		jPanel.setBackground(Color.WHITE);
		
		this.add(new JLabel("画图区"));
		this.add(jPanel);
		this.add(new JLabel("消息区"));
		this.add(jTextArea);
		this.add(jTextField);
		this.add(send_button);

		//初始化界面
		this.setSize(720, 500);
		this.setTitle("Teacher");
		this.setVisible(true);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.addMouseListener(this);
		this.addMouseMotionListener(this);

		flowLayout = new FlowLayout();
		this.setLayout(flowLayout);
		
		//获取画笔
		g = this.getGraphics();
		
		//建立服务器对象
		ServerSocket serverSocket = new ServerSocket(port);
		System.out.println("服务器在端口:"+port+"创建成功");
		
		//新建一个进程等待客户机进来
		clientThread = new ClientThread(serverSocket,jTextArea);
		clientThread.start();
		
		//获取摄像头
		Webcam webcam = Webcam.getDefault();
		webcam.open();
		//获取图片
		BufferedImage img = webcam.getImage();
		//用一个线程去将图片分解为像素发给客户机
		WebcamThread webcamThread = new WebcamThread(data, img, g, webcam, clientThread);
		webcamThread.start();
		
	}
	
	public static void main(String[] args) throws IOException {
		Server server = new Server(9999);
	}

	@Override
	public void mouseClicked(MouseEvent e){
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		byte[] msg = jTextField.getText().getBytes();
		for (byte b : msg) {
			System.out.println(b);
		}
		jTextArea.append(jTextField.getText()+'\n');
		
		try {
			//往连接线程池里每一个输出流里写东西
			for (int i = 0; i < clientThread.ClientPool.size(); i++) {
				//将信息包装,先发送一个0代表将要发送的是消息
				clientThread.ClientPool.get(i).getOutputStream().write(0);
				//之后第一个字节为字符串的长度
				clientThread.ClientPool.get(i).getOutputStream().write(msg.length);
				clientThread.ClientPool.get(i).getOutputStream().write(msg);
			}
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}

	@Override
	public void mouseDragged(MouseEvent e) {
		// TODO Auto-generated method stub
		
		x = e.getX();
		y = e.getY();
		g.drawLine(x, y, x, y);
		
		//往连接线程池里每一个输出流里写东西
		for (int i = 0; i < clientThread.ClientPool.size(); i++) {
			try {
				//将信息包装,发送1代表发送的是绘图信息
				clientThread.ClientPool.get(i).getOutputStream().write(1);
				//用dataoutputStream传输int型数据,不然只能画(255,255)范围内的点
				DataOutputStream dataOutputStream = new DataOutputStream(clientThread.ClientPool.get(i).getOutputStream());
				dataOutputStream.writeInt(x);
				dataOutputStream.writeInt(y);
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
	}

	@Override
	public void mouseMoved(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
}

源代码2.4 Client:
package webcam;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import com.github.sarxos.webcam.Webcam;

import sun.security.util.Length;

public class Client extends JFrame implements MouseListener,ActionListener{
	
	DataInputStream dataInputStream;
	DataOutputStream dataOutputStream;
	InputStream inputStream;
	OutputStream outputStream;
	Graphics g;
	FlowLayout flowLayout;
	
	//窗体组件 
	JPanel jPanel;//画图板
	JTextField jTextField;//输入框
	JTextArea jTextArea;//消息框
	JButton send_button;//发送按钮
	
	//绘画变量
	int x,y;
	
	public Client() throws UnknownHostException, IOException{

		jTextArea = new JTextArea(10,60);
		jTextField = new JTextField(20);
		send_button = new JButton("发送");
		send_button.addActionListener(this);
		
		jPanel = new JPanel();
		Dimension preferredSize = new Dimension(660,180);
		jPanel.setPreferredSize(preferredSize);
		jPanel.setBackground(Color.WHITE);
		
		this.add(jTextField);
		this.add(send_button);
		this.add(jTextArea);
		
		this.add(new JLabel("画图区"));
		this.add(jPanel);
		this.add(new JLabel("消息区"));
		this.add(jTextArea);
		this.add(jTextField);
		this.add(send_button);
		
		//初始化界面
		this.setSize(720, 500);
		this.setTitle("Student");
		this.setVisible(true);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.addMouseListener(this);
		flowLayout = new FlowLayout();
		this.setLayout(flowLayout);
		
		
		
		//获取画笔
		g = this.getGraphics();
		//连接服务端
		Socket client = new Socket("127.0.0.1",9999);
		System.out.println("连接成功");
		inputStream = client.getInputStream();
		outputStream = client.getOutputStream();
		
		dataInputStream = new DataInputStream(inputStream);

		//读取数据
		while(true){
			//先阅读1个字节确定发送的是什么类型的信息
			int flag = inputStream.read();
			System.out.println("我读了个"+flag);
			if(flag==0){
				//取出字节长度
				byte[] newmsg = new byte[inputStream.read()];
				System.out.println(newmsg.length);
				byte temp = (byte) inputStream.read();
				System.out.println(temp);System.out.println(newmsg.length);
				for(int i=0;i<newmsg.length;i++){
					newmsg[i] = temp;
					System.out.println(temp);
					if(i==newmsg.length-1) break;
					temp = (byte) inputStream.read();
				}
				String new_str = new String(newmsg);
				System.out.println(new_str);
				jTextArea.append(new_str+'\n');
			}else if(flag==1){
				x = dataInputStream.readInt();
				y = dataInputStream.readInt();
				System.out.println("我获取了x:"+x+" y:"+y);
				g.drawLine(x, y, x, y);
			}else if(flag==2){
				for(int i=0;i<120;i++){
					for(int j=0;j<160;j++){
						System.out.println("我要开始视频了");
						int data = dataInputStream.readInt();
						System.out.println(data);
						Color color = new Color(data);
						g.setColor(color);
						g.drawLine(j,i,j,i);
					}
				}
			}
			
		}

	}
	
	public void write(int msg) throws IOException {
		dataOutputStream.write(msg);
	}
	
	public static void main(String[] args) throws UnknownHostException, IOException {
		// TODO Auto-generated method stub
		Client client = new Client();
	}
	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub	
	}
	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
	}
	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub

	}
	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		byte[] msg = jTextField.getText().getBytes();
		jTextArea.append(jTextField.getText()+'\n');
		try {
			outputStream.write(msg.length);
			outputStream.write(msg);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}
}

源代码2.4 WebcamThread:
package webcam;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.DataOutputStream;
import java.io.IOException;

import com.github.sarxos.webcam.Webcam;

public class WebcamThread extends Thread{
	
	int[][] data; 
	BufferedImage img;
	Graphics g;
	Webcam webcam;
	ClientThread clientThread;
	
	public WebcamThread(int[][] data,BufferedImage img,Graphics g,Webcam webcam,ClientThread clientThread) {
		// TODO Auto-generated constructor stub
		this.clientThread = clientThread;
		this.data = data;
		this.g = g;
		this.webcam = webcam;
		this.img = img;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		data = new int[img.getHeight()][img.getWidth()];
		System.out.println(img.getHeight()+" "+img.getWidth());
		while(true){
			g.drawImage(img, 30, 66, null);
			img = webcam.getImage();
			for(int i=0;i<img.getHeight();i++){
				for(int j=0;j<img.getWidth();j++){
					data[i][j] = img.getRGB(j,i);
					System.out.println(data[i][j]);
					for (int k = 0; k < clientThread.ClientPool.size(); k++){
						try {
							//将信息包装,发送2代表发送的是视频信息
							clientThread.ClientPool.get(k).getOutputStream().write(2);
							//用dataoutputStream传输int型数据,不然只能画(255,255)范围内的点
							DataOutputStream dataOutputStream = new DataOutputStream(clientThread.ClientPool.get(k).getOutputStream());
							dataOutputStream.writeInt(data[i][j]);
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						
					}
				}
			}
		}
	}
}

最终成品演示

在这里插入图片描述
(由于最高只能上传5Mb,这里帧率过低23333,而且线程一多视频效果太差了像个马蜂窝就注释掉了 ,以后再优化)

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值