Java多人视频通信(不定时更新)

Unity3D实时通信实战:Socket.IO客户端集成与多人在线同步指南 实时网络通信是现代游戏和应用开发的核心技术,它基于WebSocket等双向通信协议,实现了服务器与客户端之间的低延迟、全双工数据交换。其技术价值在于突破了传统HTTP请求-响应模式的限制,支持服务器主动推送和高效的双向数据流,为实时互动场景提供了基础支撑。在应用场景上,实时通信广泛用于多人在线游戏、实时数据监控、虚拟社交空间和即时通讯等领域。本文聚焦于Unity3D开发环境,深入探讨如何利用socket.io-client-unity3d库,高效集成Socket.IO协议,解决实时通信中的连接管理、数据序列 阅读详情


前言

2022.1.16

和同学一起做的项目,打算将来写在简历里面,或者就是写着玩玩,前言也会不定时更新,主要是写给自己看,防止自己忘记hhh
以后是打算边写代码边写博客,不然写完再写博客太费劲了,懒

2022.1.19

第二次更新,实现了简单的界面视图,并以直线的形式传递信息,也就是传两个点


一、服务器和客户端

1.创建服务器类和用户类

服务器

package communication2;

import java.io.IOException;
import java.net.ServerSocket;

public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(18888);//需要捕捉异常,好像涉及到网络连接就会强制要求
            System.out.println("等待连接。。。");
            serverSocket.accept();//阻塞式连接,没有连接就不会执行后续代码
            System.out.println("连接成功~");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

用户

package communication2;

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

public class Client {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1",18888);//尝试连接
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

先后运行Server和Client

运行Server时
运行Server时

运行了Client后
在这里插入图片描述
第一次连接尝试成功~~

接下来我们尝试让服务器发点东西给用户,看看能不能接收

2.第一次传输数据

更新代码

package communication2;

import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(18888);//需要捕捉异常,好像涉及到网络连接就会强制要求
            System.out.println("等待连接。。。");
            //获取Socket对象
            Socket socket = serverSocket.accept();//阻塞式连接,没有连接就不会执行后续代码
            System.out.println("连接成功~");
            OutputStream outputStream = socket.getOutputStream();//获取输出流
            outputStream.write(new String("hello my friend").getBytes(StandardCharsets.UTF_8));//写入输出流
            outputStream.close();//关闭输出流,表明输出结束
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package communication2;

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

public class Client {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1",18888);//尝试连接
            //获取从服务器传来的输入
            InputStream inputStream = socket.getInputStream();
            while (true){
                int word = inputStream.read();//这个方法每次只能获取一个字符并为int类型
                if (word == -1)
                    break;
                //转换成char并输出字符
                System.out.print((char)word);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述
芜湖~成功了

3.将用户封装

package communication;

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

public class Client {
    private Socket socket;
    private InputStream inputStream;
    public Client(String ip, int port){
        try {
            this.socket = new Socket(ip,port);
            this.inputStream = socket.getInputStream();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //封装读取信息方法
    public void receiveMsg(){
        int perWord = 0;
        while (true){
            try {
                perWord = this.inputStream.read();
                if (perWord == -1)
                    break;
                System.out.print((char) perWord);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

更新Server代码,使其能够持续接收连接

package communication2;

import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class Server {
    static int index = 0;
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(18888);//需要捕捉异常,好像涉及到网络连接就会强制要求
            System.out.println("等待连接。。。");
            //持续保持等待连接状态
            while (true) {
                //获取Socket对象
                Socket socket = serverSocket.accept();//阻塞式连接,没有连接就不会执行后续代码
                System.out.println("连接成功~");
                index++;
                OutputStream outputStream = socket.getOutputStream();//获取输出流
                outputStream.write(new String("hello my friend you are the "+index+" client").getBytes(StandardCharsets.UTF_8));//写入输出流
                outputStream.close();//关闭输出流,表明输出结束
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

创建一个Test类来写main方法,创建Client对象

package communication2;

public class Test {
    public static void main(String[] args) {
        Client client1 = new Client("127.0.0.1",18888);
        client1.receiveMsg();
        System.out.println();
        Client client2 = new Client("127.0.0.1",18888);
        client2.receiveMsg();
    }
}

![在这里插入图片描述](https://img-blog.csdnimg.cn/8a99f95eb739499aaffb4b534456fdcf.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Y2X5oe_54Oo5pum,size_20,color_FFFFFF,t_70,g_se,x_16
good,现在可以同时连接多个对象了,并且把用户封装好了

二、实现简单可视化界面通信

1.可视化界面和鼠标监听器

可视化界面用JFrame来写,并给该界面加上一个监听器,来监听鼠标按压和释放的点位,以此来画点
Server的封装
连接服务端的connect方法

private Socket connect(){
        Socket socket = null;
        try {
            socket = serverSocket.accept();

        } catch (IOException e) {
            e.printStackTrace();
        }
        return socket;
    }

界面生成方法

private JFrame initUi(Socket socket){
        JFrame jFrame = new JFrame("通信测试界面-服务端");
        jFrame.setSize(400,400);
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.setLocation(790,290);
        jFrame.setVisible(true);
        try {
            //增加监听器,传入画布和输出流
            jFrame.addMouseListener(new ServerUiListener(jFrame.getGraphics(),socket.getOutputStream()));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jFrame;
    }

监听器类的实现

package communication;

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

public class ServerUiListener implements MouseListener {
    private Graphics graphics;
    private OutputStream outputStream;
    //确定两个坐标
    private int x1,y1,x2,y2;
    public ServerUiListener(Graphics graphics,OutputStream outputStream){
        this.graphics = graphics;
        this.outputStream = outputStream;
    }
    @Override
    public void mouseClicked(MouseEvent e) {

    }

    @Override
    public void mousePressed(MouseEvent e) {
        x1 = e.getX();
        y1 = e.getY();
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        //鼠标释放后即开始画线
        x2 = e.getX();
        y2 = e.getY();
        graphics.drawLine(x1,y1,x2,y2);
        //将两个坐标出入输出流
        try {
            outputStream.write(new Integer(x1).byteValue());
            outputStream.write(new Integer(y1).byteValue());
            outputStream.write(new Integer(x2).byteValue());
            outputStream.write(new Integer(y2).byteValue());
//            System.out.println(x1+" "+y1+" "+x2+" "+y2);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }
}

客户端的代码类似,也是加个界面加个监听器,不赘述了

2.运行展示在这里插入图片描述

两边的窗口都可以相互看到画线的地方,在Server窗口画线可以在客户端看到,在客户端画线Server也能接收到

3.写代码时的疑惑

Server的监听器类中有数据传入到输出流,而在Server类中又有Inputstream的接收,同样的Client类里也有Inputstream接收,那到底是哪个Inputstream接收呢?运行后发现只有Client类才会接收,同一个对象不能既发送流又读入流

4.存在的问题

Inputstream在接收信息的时候只能接入0~255的int整数,超过255会溢出,或者小于0也会溢出,
具体表现就是,我在Server的窗口里画一条超范围的直线,在客户端接收到的点位会有明显的偏差
在这里插入图片描述
这个问题我在之后应该会解决

三、解决输入输出流最大只能传送255整数的问题

1.原理即解决方法

由于Inputstream的read()方法只能返回一个0~255的整数,也就是1个字节,8个bit的值,所以,要想准确的传递参数,需要先搞清楚int,byte和bit之间的关系
按理来说这是最基本的东西,但是我以前没咋用,所以记不住,嘿嘿嘿
在java里面,一个int的大小为4个byte即32个bit,所以要想将int完整的表示出来,需要将int拆分成4个部分放入输出流,然后在接收的时候再拼接出来

int用二进制来表示一共有32位,而Outputstream的write方法每次都只取最后8位,所以我们要将int拆分为32-25位,24-17位,16-9位,8-1位,用右移操作即可,接收时再左移回去

先来一个简单的例子

package Test;

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

public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(50000);
            Socket socket = serverSocket.accept();
            OutputStream outputStream = socket.getOutputStream();
            //传10000已经大于255了
            int num = 10000;
            //进行移位操作
            outputStream.write(num>>24);
            outputStream.write(num>>16);
            outputStream.write(num>>8);
            outputStream.write(num>>0);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package Test;

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

public class Client {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1",50000);
            InputStream inputStream = socket.getInputStream();
            //读取拆分的4部分
            int b1 = inputStream.read();
            int b2 = inputStream.read();
            int b3 = inputStream.read();
            int b4 = inputStream.read();
            //拼接
            int x = b1<<24|b2<<16|b3<<8|b4;
            System.out.println(b1+" "+b2+" "+b3+" "+b4);
            System.out.println(x);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

然后分别运行,看输出
在这里插入图片描述
表示的是32到25位为0,24到17位为0,16到9位为39,8到1位为16
拼接过后得出了正确的数值
39和16代表啥意思呢,看看计算器
在这里插入图片描述
在这里插入图片描述
再来看看10000对应的二进制
在这里插入图片描述
这就代表了右移过后的结果

2.方法的封装

好了我们接下来将传int的方法封装起来,方便使用

package communication3;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class StreamMethod {
    public static void writeInt(OutputStream outputStream,int num){
        try {
            outputStream.write(num>>24);
            outputStream.write(num>>16);
            outputStream.write(num>>8);
            outputStream.write(num>>0);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static int readInt(InputStream inputStream){
        try {
            int b1 = inputStream.read();
            int b2 = inputStream.read();
            int b3 = inputStream.read();
            int b4 = inputStream.read();
            //拼接
            return b1<<24|b2<<16|b3<<8|b4;
        } catch (IOException e) {
            e.printStackTrace();
            return 0;
        }

    }
}

3.更新代码即运行结果

Server中的监听方法

private void startListenMgs(JFrame jFrame,Socket socket){
        int x1,y1,x2,y2;
        try {
            InputStream inputStream = socket.getInputStream();
            Graphics graphics = jFrame.getGraphics();
            while (true) {
                x1 = StreamMethod.readInt(inputStream);
                y1 = StreamMethod.readInt(inputStream);
                x2 = StreamMethod.readInt(inputStream);
                y2 = StreamMethod.readInt(inputStream);
                graphics.drawLine(x1,y1,x2,y2);
                System.out.println(x1+" "+y1+" "+x2+" "+y2);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

监听器中的写入方法

public void mouseReleased(MouseEvent e) {
        //鼠标释放后即开始画线
        x2 = e.getX();
        y2 = e.getY();
        graphics.drawLine(x1, y1, x2, y2);
        //将两个坐标出入输出流
        StreamMethod.writeInt(outputStream, x1);
        StreamMethod.writeInt(outputStream, y1);
        StreamMethod.writeInt(outputStream, x2);
        StreamMethod.writeInt(outputStream, y2);
        System.out.println(x1+" "+y1+" "+x2+" "+y2);

    }

运行结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
现在数据算是传入成功了

四、完善功能

现在属于是只能画直线,我们可以多弄几种类型,加上画笔,圆和矩形,并且优化一下实时显示的功能

1.封装字符串传输的方法

要辨别选择的是哪一种类型,就需要通过字符串来区分,一个字符通常是2字节,但是如果是中文的话就是3字节,要是中英混搭的话就不好区分长度,所以直接调用.getBytes().length方法即可

public static void writeStr(OutputStream outputStream,String str){
        try {
            outputStream.write(str.getBytes().length);
            outputStream.write(str.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在接收的时候,字符串有个传入byte数组的构造方法可以直接转换成字符串

    public static String readStr(InputStream inputStream){
        try {
            int length =  inputStream.read();
            byte[] strArray = new byte[length];
            inputStream.read(strArray);
            return new String(strArray);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

2.添加按钮并更新监听器

一些ui上的操作就不用赘述了,直接上代码展示

public static JFrame ServerUI(String title, Socket socket) {
        String[] btnStr = {"画笔", "直线", "圆", "矩形"};
        JFrame jFrame = new JFrame(title);
        try {

            jFrame.setSize(1000, 800);
            jFrame.setLocation(200, 100);
            jFrame.setDefaultCloseOperation(jFrame.EXIT_ON_CLOSE);
            jFrame.setLayout(new FlowLayout());
            jFrame.setVisible(true);

            ServerUiListener serverUiListener = new ServerUiListener(jFrame.getGraphics(), socket.getOutputStream());
            jFrame.addMouseListener(serverUiListener);
            jFrame.addMouseMotionListener(serverUiListener);

            for (int i = 0; i < btnStr.length; i++) {
                JButton jButton = new JButton(btnStr[i]);
                jFrame.add(jButton);
                jButton.addActionListener(serverUiListener);
//                System.out.println("加了一个按钮");
            }
            //setVisible必须放在最后面,否则按钮不会显示
            jFrame.setVisible(true);
            return jFrame;
        } catch (IOException e) {
            e.printStackTrace();
            return jFrame;
        }
    }

监听器方面,画笔的话需要实时拖动,故调用mouseDragged方法。

如何动态显示作图痕迹

在拖动的过程中就应该去绘制线条,并在绘制下一个线条的时候擦除前一个线条,这样就感觉是动态绘制了,擦除方法我选择在原来的点位上绘制与背景相同颜色的线条,这样就相当于是擦除了
另外有个问题,在擦除的过程中可能会擦除之前已经画好的线条,所以我们还需要用数组保留画好的线条的点位,在每次擦除的时候重绘一下
我把点的数组放在了UI这个类里面设置成静态变量来使用
在这里插入图片描述
有关UI的方法都在这个UI类里面封装成了静态方法

public void mouseReleased(MouseEvent e) {
        //鼠标释放后即开始画线
        x2 = e.getX();
        y2 = e.getY();
        //在鼠标释放的时候加入点位
        if(shape.equals("直线")) {
//            System.out.println(x2+" "+y2);
            UI.lineStartPoints.add(new Point(x1,y1));
            UI.lineEndPoints.add(new Point(x2,y2));
            graphics.drawLine(x1, y1, x2, y2);

        }
        if(shape.equals("圆")){
            UI.circleStartPoints.add(new Point(x1,y1));
            UI.circleEndPoints.add(new Point(x2,y2));
            graphics.drawOval(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
        }
        if(shape.equals("矩形")){
            UI.recStartPoints.add(new Point(x1,y1));
            UI.recEndPoints.add(new Point(x2,y2));
            graphics.drawRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
        }
        if(!shape.equals("画笔")) {
            //加入了图形类就要先传类型,直接调用封装好的方法即可
            StreamMethod.writeStr(outputStream, shape);
            //将两个坐标出入输出流
            StreamMethod.writeInt(outputStream, x1);
            StreamMethod.writeInt(outputStream, y1);
            StreamMethod.writeInt(outputStream, x2);
            StreamMethod.writeInt(outputStream, y2);
            System.out.println(x1 + " " + y1 + " " + x2 + " " + y2);
        }
    }
public void mouseDragged(MouseEvent e) {
		//由于画笔是实时加入的,所以画笔的点位在鼠标拖动的时候就加上了
        if (shape.equals("画笔")){
            UI.Points.add(new Point(e.getX(),e.getY()));
            graphics.fillOval(e.getX(),e.getY(),2,2);
            StreamMethod.writeStr(outputStream,shape);
            StreamMethod.writeInt(outputStream,e.getX());
            StreamMethod.writeInt(outputStream,e.getY());
        }
        if(shape.equals("直线")){
            //将之前的线覆盖
            if(prex!=e.getX()||prey!=e.getY()){
                graphics.setColor(new Color(238,238,238));
                graphics.drawLine(x1,y1,prex,prey);
            }
            graphics.setColor(Color.black);

            graphics.drawLine(x1,y1,e.getX(),e.getY());

        }
        if(shape.equals("圆")){
            //将之前的线覆盖
            if(prex!=e.getX()||prey!=e.getY()){
                graphics.setColor(new Color(238,238,238));
                graphics.drawOval(Math.min(x1,prex),Math.min(y1,prey),Math.abs(x1-prex),Math.abs(y1-prey));

            }
            graphics.setColor(Color.black);

            graphics.drawOval(Math.min(x1,e.getX()),Math.min(y1,e.getY()),Math.abs(x1-e.getX()),Math.abs(y1-e.getY()));

        }
        if(shape.equals("矩形")){
            //将之前的线覆盖
            if(prex!=e.getX()||prey!=e.getY()){
                graphics.setColor(new Color(238,238,238));
                graphics.drawRect(Math.min(x1,prex),Math.min(y1,prey),Math.abs(x1-prex),Math.abs(y1-prey));

            }
            graphics.setColor(Color.black);

            graphics.drawRect(Math.min(x1,e.getX()),Math.min(y1,e.getY()),Math.abs(x1-e.getX()),Math.abs(y1-e.getY()));

        }
        //这里是重绘之前的线条
        for (int i = 0; i < UI.Points.size(); i++) {
            graphics.fillOval(UI.Points.get(i).x,UI.Points.get(i).y,1,1);
        }
        for (int i = 0; i < UI.lineStartPoints.size(); i++) {
            graphics.drawLine(UI.lineStartPoints.get(i).x,UI.lineStartPoints.get(i).y,UI.lineEndPoints.get(i).x,UI.lineEndPoints.get(i).y);
        }
        for (int i = 0; i < UI.circleEndPoints.size(); i++) {
            graphics.drawOval(Math.min(UI.circleStartPoints.get(i).x,UI.circleEndPoints.get(i).x),Math.min(UI.circleStartPoints.get(i).y,UI.circleEndPoints.get(i).y),Math.abs(UI.circleStartPoints.get(i).x-UI.circleEndPoints.get(i).x),Math.abs(UI.circleStartPoints.get(i).y-UI.circleEndPoints.get(i).y));
        }
        for (int i = 0; i < UI.recEndPoints.size(); i++) {
            graphics.drawRect(Math.min(UI.recStartPoints.get(i).x,UI.recEndPoints.get(i).x),Math.min(UI.recStartPoints.get(i).y,UI.recEndPoints.get(i).y),Math.abs(UI.recStartPoints.get(i).x-UI.recEndPoints.get(i).x),Math.abs(UI.recStartPoints.get(i).y-UI.recEndPoints.get(i).y));
        }
        prex = e.getX();
        prey = e.getY();
    }

Server类里的信息接收

 private void startListenMgs(JFrame jFrame,Socket socket){
        int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
        String shape;
        try {
            InputStream inputStream = socket.getInputStream();
            Graphics graphics = jFrame.getGraphics();

            while (true) {
                shape = StreamMethod.readStr(inputStream);
                if(!shape.equals("画笔")) {
                    x1 = StreamMethod.readInt(inputStream);
                    y1 = StreamMethod.readInt(inputStream);
                    x2 = StreamMethod.readInt(inputStream);
                    y2 = StreamMethod.readInt(inputStream);
                }else {
                	//画笔只需要接收两个点位,这个在传输的时候可以先协商好
                    x1 = StreamMethod.readInt(inputStream);
                    y1 = StreamMethod.readInt(inputStream);
                    graphics.fillOval(x1,y1,2,2);
                }
                if (shape.equals("直线")) {
                    graphics.drawLine(x1, y1, x2, y2);
                }
                if(shape.equals("圆")){
                    graphics.drawOval(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
                }
                if (shape.equals("矩形")){
                    graphics.drawRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
                }
                System.out.println(x1+" "+y1+" "+x2+" "+y2);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

现在做成这样子了,后续再把消息交流加上去
在这里插入图片描述

java上位机通信协议实现 概述:以前项目中用java写了一个上位机用来观察单片机发送的数据(连续不断的传送图片以形成视频),在实际使用中发现偶尔会发生图片显示错误的问题(每张图片都显示为前一张的下半段和本张图的上半段),最近有时间对这个问题进行了修复。 本文首先会概括的叙述java上位机的原理,然后会说明通信协议的实现思路,最后会附上上位机和下位机通讯部分的代码,方便大家学习。  上位机框架: 阅读详情

相关推荐

OSO多人聊天应用项目实战

本文还有配套的精品资源,点击获取 简介:OSO.rar_多人聊天 qq 是一款与QQ类似的多用户聊天程序压缩包,旨在实现用户与多用户间的实时通信,包括文本聊天、表情发送、群组聊天等功能。该程序不仅提供了基础聊天平台,还允许添加自定义功能,如语音通话、视频聊天、文件传输等,通过网络编程、多线程处理、数据库存储、安全加密等关键技术构建而成。 1. 多人聊天系统的构建与...

weixin_26854475的博客 1372

java版本使用springboot vue websocket webrtc实现视频通话

使用springboot websocket webrtc实现视频通话

weixin_44327322的博客 5896

Java实时通信系统构建实战:源代码与视频教程

Java,作为一种面向对象、平台无关、安全、稳定的编程语言,以其强大的跨平台能力和丰富的API支持,成为构建企业级应用,包括聊天系统的首选语言之一。其特性如自动垃圾回收、良好的异常处理机制和丰富的类库支持,确保了开发的高效率和系统的稳定性。客户端-服务器(C/S)架构是一种应用软件的结构模式,它将应用分为两个独立的部分:客户端(Client)和服务器端(Server)。这种架构允许客户端提出请求,而服务器端则对这些请求进行处理并提供服务。客户端(Client)

weixin_32306683的博客 357

Java实现视频通话

Java实现实时视频通信

学习是一种乐趣 6690

WebRTC+java实现多人视频通讯

通过WebRTC实时通讯技术,配合后端java websocket实现多人视频。局域网内视频没问题,公网需要自行穿透NAT,项目整体为SpringBoot 外置Tomcat 启动

java多人视频聊天室

java代码实现多线程聊天室,分服务器端与客户端

Java千万不能忘记的基础知识总结(不定时更新)

1.Java三大特性Java语言的三大特性即是:封装、继承、多态2.如何理解输入流与输出流概念(IO)东西读入内存就是输入流 东西从内存写到记录存储输出流 而我们本身就以记录存储为原点所有会有不解的感觉~ java io流按照java io流的方向可以分为输入流和输出流输入流是将资源数据读入到缓冲Buffer中,输出流是将缓冲Buffer中的数据按照指定格式写出到一个指定的位置,所以这两个流一般

任何路都没有错,关键是要知道自己在哪 873

java 基于websocket实现的视频聊天

java 基于websocket实现的视频聊天,解压项目到对应位置部署到tomcat8即可使用

java springboot基于微信小程序的多人协同企业员工办公系统小程序(源码+文档+运行视频+讲解视频)

摘要:在数字化办公浪潮下,传统企业办公模式效率低下、信息流通不畅等问题凸显。本文设计并实现基于Java Spring Boot与微信小程序的多人协同企业员工办公系统。系统采用前后端分离架构,后端以Spring Boot为核心,集成MyBatis操作MySQL数据库,实现用户管理、任务分配、文件共享、即时通讯等核心功能;前端依托微信小程序,提供便捷的操作界面,员工可随时随地进行办公。系统引入JWT进行身份认证,保障数据安全,利用WebSocket协议实现实时消息推送。测试表明,系统响应迅速,操作流畅,有效提升

weixin_mrw479640的博客 1140

基于Java视频会议系统的设计与实现 的毕业设计,它可以实现多人视频会议、视频聊天等功能

java小程序 基于Java的视频会议系统是一种基于网络的实时视频会议系统,它可以实现多人视频会议、视频聊天等功能。该系统主要由会议控制器、视频处理器、音频处理器、网络通信模块等组成。 会议控制器负责会议的创建、管理和控制。它可以创建会议、邀请参会者、开始/结束会议、管理参会者的发言权等。视频处理器负责视频数据的采集、编码、解码和处理。它可以采集摄像头的视频数据,对视频数据进行H.264编码,并在会议中对参会者的视频进行解码合成。音频处理器负责音频数据的采集、编码和解码,实现参会者的语音互动。 网络通信模块负责与参会者客户端的网络通信,将视频和音频数据以及控制指令进行传输。它采用TCP协议,通过Socket实现客户端与服务器的连接和数据传输。 该系统采用Java语言进行开发,使用Java Media Framework(JMF)进行视频和音频处理,使用Socket进行网络通信。通过合理的模块设计,实现了视频会议系统的高扩展性和灵活性。实验结果表明,该系统可以实现流畅的多人视频会议,支持1080P高清视频,语音同步性好,用户体验良好。 总体来说,基于Java的视频会议系统设计合理

Python实现微信PC端聊天记录自动化监听与智能回复

本文详细介绍了如何使用Python实现微信PC端聊天记录的自动化监听与智能回复。通过win32api和uiautomation库,模拟人工操作,实时监控聊天窗口并抓取新消息。文章重点讲解了核心代码逻辑、环境搭建步骤,并提供了实现关键词触发自动回复的完整方案,旨在提高工作效率与信息管理自动化水平。

weixin_29092031的博客 347

java毕业设计——基于Java+Socket的视频会议系统设计与实现(毕业论文+程序源码)——视频会议系统

随着人们对视频和音频信息的需求愈来愈强烈,追求远距离的视音频的同步交互成为新的时尚。近些年来,依托计算机技术、通信技术和网络条件的发展,集音频、视频、图像、文字、数据为一体的多媒体信息,使越来越多的人开始通过互联网享受到网上生活、远程医疗、远程通讯的乐趣,缩短了时区和地域的距离。远程通信的各种优势给人们带来的方便也促使人们对这一领域进行更加深入的探索。基于不同平台以及不同开发工具的网络视频会议系统层出不穷。视频会议系统还更广泛的应用于现代企业中。信息技术的迅猛发展,改变了各行各业的传统工作模式。

m0_66238867的博客 2705

华为手环实时心率数据导出到UWP项目中

hello大家好呀O(∩_∩)O最近在做毕设 其中有个小功能要用到实时心率数据。查找网上的资料发现只有小米手环的实时心率数据导出但是没有华为手环的,我试了华为手环但是并不能行得通哈哈哈。现在分享一下华为手环实时心率数据导出的代码。

apple_63713858的博客 1583

java视频通话_Java使用WebSocket和WebRTC视频通话

新版的chrome浏览器,加强了安全性,所以要使用https,同时也有很多修改,这个例子已经过时,不能使用。可以参考新的文章:WebRTC续集这两天终于是抽了时间把WebRTC搞定了,去年就想弄的,但是确实没时间,而且那时候JavaEE的WebSocket还没有规范,网上也都是用的Tomcat自己的WebSocket实现的,或者还使用了一些ajax辅助,JavaEE7中有了WebSocket的规范...

weixin_31542739的博客 3705

LC与RC滤波电路实战对比:从原理到选型指南

本文深入对比了LC与RC滤波电路的核心原理与实战应用。LC滤波利用电感与电容的无损能量搬运,适合高频、大电流电源滤波,效率高但需注意谐振风险;RC滤波通过电阻消耗能量实现滤波,结构简单、成本低,适用于低频信号处理或小电流供电场景。文章提供了从工作原理、性能维度到具体选型的完整指南,帮助工程师根据项目需求(如频率范围、负载电流、效率)做出精准选择。

weixin_29240711的博客 499

CSP-J 入门级第一轮认证 2025 详细解析

2025年CSP-J入门级第一轮认证模拟赛提供10套免费试题,含选择题与解析。选择题涉及计算机科学基础,如32位无符号整数最大值计算(约42.9亿,选A)、C++位运算(255&254=254,选B)、递归函数分析(calc(5)=6,选B)、哈夫曼树构造(带权路径长度186,选B)等。其他题目涵盖图论(有向图边数等于入度/出度和,选B)、组合数学(120种选法,选C)、布尔逻辑(选项C不恒等)、模运算周期性(f[2025]=6,选D)、C++字符串特性(支持string+char,选B)及引用传参

lan_in的博客 2944

如何用Java轻松实现实时音视频通信?webrtc-java完整指南

在数字化时代,实时音视频通信已成为社交、教育、医疗等领域的核心需求。而**webrtc-java**作为一款专为Java开发者打造的实时通信工具,让桌面平台上的音视频开发变得前所未有的简单!本文将带你快速掌握这个强大工具的使用方法,零门槛构建属于你的实时通信应用。 ## ???? 什么是webrtc-java? **webrtc-java**是基于Google WebRTC技术的Java原生接口实...

gitblog_00490的博客 513

python语言下使用opencv接口cv2.VideoCapture()接口调用海康机器人工业相机

文章目录 目录 文章目录 前言 一、opencv接口介绍 二、调用海康机器人工业相机 1.使用海康机器人工业相机的前提 2.调用海康机器人工业相机进行显示 3.调用海康机器人工业相机进行存图 4.调用海康机器人工业相机存视频 5.调用海康机器人工业相机进行简单图像处理 总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是本篇文章正文内容,下.

qq_39570716的博客 1万+

由大学到至今的小作品(不定时更新)

1. 记事本(大二上学期) 描述:用于练习java,使用了substanceUI类库,同时添加了许多系统txt工具没有的功能,例如文字颜色的改变,字体大小,粗体斜体等,同时加入高大上的中英切换,以及人性化的夜间模式 截图: 1. java聊天系统(大二下学期) 描述:局域网内在线多人聊天系统 技术:c/s模式,sql数据库,界面美化 截图:

871

Python 爬虫实战:豆瓣电影海报批量获取(Top250 榜单 + 可视化展示)

在信息爆炸的时代,数据已成为决策的核心,而数据的获取是数据分析的第一步。本文将详细介绍如何利用 Python 爬虫获取豆瓣电影 Top250 榜单的海报,并对数据进行可视化展示,助你更好地了解电影市场的趋势和用户的喜好。

yansideyucsdn的博客 719

手把手教你学simulink(90.1)--直流电动机实例:基于Simulink的基本模型的直流电动机(DC Motor)建模

直流电动机(DC Motor)因其结构简单、控制方便和良好的调速性能,广泛应用于各种工业自动化、机器人技术、家用电器以及航空航天等领域。为了更好地理解和应用直流电动机的工作原理及其控制系统,本项目旨在通过Simulink对直流电动机进行基本模型的建模与仿真。

MHD0815的博客 441

Java实现OPC通信

Java实现OPC通信 不回复任何问题,有问题可以评论。 录屏简单说了一下文章内容,视频地址:https://www.bilibili.com/video/BV13V411f7Ch/ 1.PLC和OPC 使用的PLC:西门子的S7-300,具体型号如下图 使用的OPC server软件: 项目使用KEPServer V6(450M,中文):百度网盘,密码: ykj2 模拟仿真用的 MatrikonOPCSimulation(50M),百度网盘,密码: mcur 2.连接测试.

yuguang的博客 8494

AMBA-CHI协议详解(七)

本节描述该协议包含的支持系统保序需求的机制。

Crazzy_M的博客 1161

深入C++与QT高频面试题(不定时更新)

本文总结了C++、数据库和Qt相关的常见面试题,涵盖以下核心内容: C++特性与智能指针 智能指针(unique_ptr/shared_ptr/weak_ptr)解决内存管理问题 构造函数/析构函数特性,虚函数与纯虚函数区别 STL容器分类与特性(vector/list/set/map等) 多线程编程 线程创建方式(Thread类/moveToThread) 线程同步机制(互斥锁/条件变量/读写锁) 进程间通信方式(管道/共享内存/消息队列) 数据库基础 事务ACID特性与操作流程 索引原理与使用场景 关系

阿博的博客 1255

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

基于Java springboot应急指挥通信系统(源码+文档+运行视频+讲解视频)

本文介绍了一个基于Java SpringBoot的应急指挥通信系统,旨在解决突发事件中信息滞后和资源调度低效问题。系统采用SpringBoot后端框架,整合Netty实现实时通信,使用MySQL和MongoDB存储结构化和非结构化数据。核心功能包括实时通信、资源调度、态势展示和指令追踪,通过WebSocket和GIS技术实现双向通信和事件可视化。测试显示系统指令延迟低于50ms,资源调度效率提升60%。文章详细说明了系统架构、技术栈(Vue前端、MyBatisPlus持久层)以及功能测试方案,包括登录和用户

weixin_mrw479640的博客 1015

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

上一篇: vue+$emit调用父级方法,添加其他参数
下一篇: 一篇博客解决常见的排序
南懿烨曦
博客等级 码龄6年 108粉丝 35原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值