网络编程之channel

2023-11-12

介绍

  • Channel 是一个对象,可以通过它读取和写入数据。
  • 拿 NIO 与原来的 I/O 做个比较,通道就像是流。
  • 所有数据都通过 Buffer 对象来处理。您永远不会将字节直接写入通道中,相反,您是将数据写入包含一个或者多个字节的缓冲区。
  • 同样,您不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。

各种Channel

FileChannel

package com.yangmin.study.io.nio.channel;

import java.io.*;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @author yangmin
 * @version 1.0
 * @description: Channel 是一个对象,可以通过它读取和写入数据。
 * 拿 NIO 与原来的 I/O 做个比较,通道就像是流。
 * 所有数据都通过 Buffer 对象来处理。您永远不会将字节直接写入通道中,相反,您是将数据写入包含一个或者多个字节的缓冲区。
 * 同样,您不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。
 * @date 2022/5/10 14:22
 */
public class ChannelTest {

    public static void main(String[] args) {
        ChannelTest channelTest = new ChannelTest();
//        channelTest.fileChannelRead();
//        channelTest.fileChannelWrite();
        channelTest.transferFrom();
    }

    /**
     * 有时可能需要在 FileChannel 的某个特定位置进行数据的读/写操作。可以通过调用position()方法获取 FileChannel 的当前位置。
     * 也可以通过调用 position(long pos)方法设置 FileChannel 的当前位置。
     *
     * 这里有两个例子:
     *
     * long pos = channel.position();//获取当前位置
     * channel.position(pos +123);//设置当前位置
     *
     * 如果将位置设置在文件结束符之后,然后试图从文件通道中读取数据,读方法将返回-1 (文件结束标志)。
     *
     * 如果将位置设置在文件结束符之后,然后向通道中写数据,文件将撑大到当前位置并写入数据。这可能导致“文件空洞”,磁盘上物理文件中写入的数据间有空隙。
     *
     FileChannel 实例的 size()方法将返回该实例所关联文件的大小。如:
     long fileSize = channel.size();

     可以使用 FileChannel.truncate()方法截取一个文件。截取文件时,文件将中指定长度后面的部分将被删除。如:
     channel.truncate(1024);
     */


    /**
     * FileChannel 从文件中读数据。
     */
    void fileChannelRead() {

        /*1.打开fileChannel
        在使用 FileChannel 之前,必须先打开它。但是,我们无法直接打开一个FileChannel,
        需要通过使用一个 InputStream、OutputStream 或RandomAccessFile 来获取一个 FileChannel 实例*/
        FileInputStream fileInputStream = null;
        FileChannel channel = null;
        try {
            fileInputStream = new FileInputStream("src/main/resources/read.text");
            channel = fileInputStream.getChannel();
            /*
             * 调用 FileChannel.read()方法。
             * 该方法将数据从 FileChannel 读取到 Buffer 中。
             * read()方法返回的 int 值表示了有多少字节被读到了 Buffer 中。如果返回-1,表示到了文件末尾。*/
            ByteBuffer buffer = ByteBuffer.allocate(14);
            while (channel.read(buffer) != -1) {
                //第一次进来的时候,buffer为:[pos=7 lim=14 cap=14]
                System.out.println(buffer.toString());
                System.out.println(new String(buffer.array()));
                buffer.clear();
            }
            System.out.println(channel.position());
            System.out.println(channel.size());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (channel != null) {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }


    /**
     * 写数据
     */
    void fileChannelWrite() {
        FileOutputStream fileOutputStream = null;
        FileChannel channel = null;
        try {
            fileOutputStream = new FileOutputStream("src/main/resources/write.text");
            channel = fileOutputStream.getChannel();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            buffer.clear();
            buffer.put(("注意 FileChannel.write()是在 while 循环中调用的。因为无法保证 write()方法一次能向 " +
                    "FileChannel 写入多少字节,因此需要重复调用 write()方法," +
                    "直到 Buffer 中已经没有尚未写入通道的字节。").getBytes());
            System.out.println(buffer.toString());
            //切换为读模式,切换后可以读取buffer中的数据
            // H T T P / 1 ... ! _  _
            //                   P(L)
            // P                 L
            buffer.flip();
            System.out.println(buffer.toString());
            while (buffer.hasRemaining()) { //当position==limit时,说明已经把buffer中的数据读完了
                channel.write(buffer);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //用完 FileChannel 后必须将其关闭。如:  inChannel.close();
            if (channel != null) {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * FileChannel 的 transferFrom()方法可以将数据从源通道传输到 FileChannel 中(译者注:这个方法在 JDK 文档中的解释为将字节从给定的可读取字节通道传输到此通道的文件中)。
     * 下面是一个 FileChannel 完成文件间的复制的例子:
     */
    void transferFrom() {
        RandomAccessFile readFile = null;
        RandomAccessFile writeFile = null;
        try {
            readFile = new RandomAccessFile("src/main/resources/read.text", "rw");
            writeFile = new RandomAccessFile("src/main/resources/write.text", "rw");
            FileChannel fromChannel = readFile.getChannel();
            FileChannel toChannel = writeFile.getChannel();
            /**
             * 这会导致fromChannel中的数据被读到buffer中,导致fromChannel中没有数据
             */
            /*ByteBuffer buffer = ByteBuffer.allocate(3);
            fromChannel.read(buffer);*/
            //设置起始/结束位置
            long position = 0;
            long count = fromChannel.size();
            /**
             *  将fromChannel中全部的数据传到toChannel中
             * 方法的输入参数 position 表示从 position 处开始向目标文件写入数据,count 表示最多传输的字节数。
             *
             * 如果源通道的剩余空间小于 count 个字节,则所传输的字节数要小于请求的字节数。
             *
             * 此外要注意,在 SoketChannel 的实现中,SocketChannel 只会传输此刻准备好的数据(可能不足 count 字节)。
             *
             * 因此,SocketChannel 可能不会将请求的所有数据(count 个字节)全部传输到 FileChannel 中。
             */
            //long l = toChannel.transferFrom(fromChannel, position, count);

            /**
             * transferTo()方法将数据从 FileChannel 传输到其他的 channel 中。
             */
            long l = fromChannel.transferTo(position, count, toChannel);
            System.out.println(l);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (readFile != null) {
                    readFile.close();
                }
                if (writeFile != null) {
                    writeFile.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

ServerSocketChannel

  • nio服务端
  • ServerSocketChannel 是一个基于通道的 socket 监听器(本身不传数据,而是一个监听器)。
  • 由于 ServerSocketChannel 没有 bind()方法,因此有必要取出对等的 socket 并使用它来绑定到一个端口以开始监听连接。我们也是使用对等 ServerSocket 的 API 来根据需要设置其他的 socket 选项。
package com.yangmin.study.io.nio.channel;

import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

/**
 * @author yangmin
 * @version 1.0
 * @description:  nio服务端
 * ServerSocketChannel 是一个基于通道的 socket 监听器(本身不传数据,而是一个监听器)。
 * 由于 ServerSocketChannel 没有 bind()方法,因此有必要取出对等的 socket 并使用它来绑定到一个端口以开始监听连接。我们也是使用对等 ServerSocket 的 API 来根据需要设置其他的 socket 选项。
 * @date 2022/5/10 17:49
 */
public class ServerSocketChannelTest {


    public static void main(String[] args) {

        ServerSocketChannelTest serverSocketChannelTest = new ServerSocketChannelTest();
        serverSocketChannelTest.test1();
    }

    void test1() {
        try {
            /**
             * 打开 ServerSocketChannel
             * 通过调用 ServerSocketChannel.open() 方法来打开 ServerSocketChannel.
             */
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            /**
             *由于 ServerSocketChannel 没有 bind()方法,因此有必要取出对等的 socket 并使用它来绑定到一个端口以开始监听连接。
             * 我们也是使用对等 ServerSocket 的 API 来根据需要设置其他的 socket 选项。
             */
            ServerSocket serverSocket = serverSocketChannel.socket();
            serverSocket.bind(new InetSocketAddress(8888));
            /**
             * ServerSocketChannel 可以设置成非阻塞模式。在非阻塞模式下,accept() 方法会立刻返回,
             * 如果还没有新进来的连接,返回的将是 null。 因此,需要检查返回的SocketChannel 是否是 null.
             */
            serverSocketChannel.configureBlocking(false);
            /**
             *字节缓冲区
             */
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            for (; ; ) {
                /**
                 * 通过 ServerSocketChannel.accept() 方法监听新进的连接。当 accept()方法返回时候,
                 * 它返回一个包含新进来的连接的 SocketChannel。因此, accept()方法会一直阻塞到有新连接到达。
                 * 阻塞模式: SocketChannel sc = ssc.accept();这里阻塞住进程。
                 *
                 * 非阻塞模式:ServerSocketChannel 可以设置成非阻塞模式。在非阻塞模式下,accept() 方法会立刻返回,
                 * 如果还没有新进来的连接,返回的将是 null。 因此,需要检查返回的SocketChannel 是否是 null.
                 */
                //我们这里采用的是非阻塞模式
                SocketChannel socketChannel = serverSocketChannel.accept();
                if (socketChannel == null) {
                    System.out.println("null");
                    Thread.sleep(2000);
                    continue;
                }
                /**
                 * 读取请求传过来的信息
                 */
                socketChannel.read(buffer);
                System.out.println("this is a data from client, "+new String(buffer.array()));
                //重置position=0,进行写操作
                buffer.rewind();
                buffer.put("hello client, i am server".getBytes());
                //切换为读操作
                buffer.flip();
                /**
                 * 向客户端响应数据
                 */
                socketChannel.write(buffer);
                buffer.clear();
                socketChannel.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

SocketChannel

nio客户端
1、SocketChannel 介绍
Java NIO 中的 SocketChannel 是一个连接到 TCP 网络套接字的通道。操作面向Buffer缓冲区
A selectable channel for stream-oriented connecting sockets,这是 Java docs 中对于 SocketChannel 的描述:SocketChannel 是一种面向流连接sockets 套接字的可选择通道。从这里可以看出:

  • SocketChannel 是用来连接 Socket 套接字
  • SocketChannel 主要用途用来处理网络 I/O 的通道
  • SocketChannel 是基于 TCP 连接传输
  • SocketChannel 实现了可选择通道,可以被多路复用的
  • 用于TCP的网络I/O套接字的通道
    2、SocketChannel 特征:
    (1)对于已经存在的 socket 不能创建 SocketChannel
    (2)SocketChannel 中提供的 open 接口创建的 Channel 并没有进行网络级联,需要使用 connect 接口连接到指定地址
    (3)未进行连接的 SocketChannle 执行 I/O 操作时,会抛出NotYetConnectedException
    (4)SocketChannel 支持两种 I/O 模式:阻塞式和非阻塞式
    (5)SocketChannel 支持异步关闭。如果 SocketChannel 在一个线程上 read 阻塞,另一个线程对该 SocketChannel 调用 shutdownInput,则读阻塞的线程将返回-1 表示没有读取任何数据;如果 SocketChannel 在一个线程上 write 阻塞,另一个线程对该SocketChannel 调用 shutdownWrite,则写阻塞的线程将抛出AsynchronousCloseException
    (6)SocketChannel 支持设定参数
    SO_SNDBUF 套接字发送缓冲区大小
    SO_RCVBUF 套接字接收缓冲区大小
    SO_KEEPALIVE 保活连接
    O_REUSEADDR 复用地址
    SO_LINGER 有数据传输时延缓关闭 Channel (只有在非阻塞模式下有用)
    TCP_NODELAY 禁用 Nagle 算法
package com.yangmin.study.io.nio.channel;

import jdk.nashorn.internal.ir.Block;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

/**
 * @author yangmin
 * @version 1.0
 * @description: nio客户端
 * 1、SocketChannel 介绍
 * Java NIO 中的 SocketChannel 是一个连接到 TCP 网络套接字的通道。操作面向Buffer缓冲区
 *
 * A selectable channel for stream-oriented connecting sockets.
 *
 * 以上是 Java docs 中对于 SocketChannel 的描述:SocketChannel 是一种面向流连接sockets 套接字的可选择通道。从这里可以看出:
 *
 * SocketChannel 是用来连接 Socket 套接字
 * SocketChannel 主要用途用来处理网络 I/O 的通道
 * SocketChannel 是基于 TCP 连接传输
 * SocketChannel 实现了可选择通道,可以被多路复用的
 * 用于TCP的网络I/O套接字的通道
 * 2、SocketChannel 特征:
 * (1)对于已经存在的 socket 不能创建 SocketChannel
 *
 * (2)SocketChannel 中提供的 open 接口创建的 Channel 并没有进行网络级联,需要使用 connect 接口连接到指定地址
 *
 * (3)未进行连接的 SocketChannle 执行 I/O 操作时,会抛出NotYetConnectedException
 *
 * (4)SocketChannel 支持两种 I/O 模式:阻塞式和非阻塞式
 *
 * (5)SocketChannel 支持异步关闭。如果 SocketChannel 在一个线程上 read 阻塞,另一个线程对该 SocketChannel 调用 shutdownInput,则读阻塞的线程将返回-1 表示没有读取任何数据;如果 SocketChannel 在一个线程上 write 阻塞,另一个线程对该SocketChannel 调用 shutdownWrite,则写阻塞的线程将抛出AsynchronousCloseException
 *
 * (6)SocketChannel 支持设定参数
 *
 * SO_SNDBUF 套接字发送缓冲区大小
 * SO_RCVBUF 套接字接收缓冲区大小
 * SO_KEEPALIVE 保活连接
 * O_REUSEADDR 复用地址
 * SO_LINGER 有数据传输时延缓关闭 Channel (只有在非阻塞模式下有用)
 *
 * TCP_NODELAY 禁用 Nagle 算法
 * @date 2022/5/10 18:51
 */
public class SocketChannelTest {

    public static void main(String[] args) {

        SocketChannelTest socketChannelTest = new SocketChannelTest();
       // socketChannelTest.unBlock();
        socketChannelTest.block();
    }

    /**
     * 阻塞模式
     */
    void block(){
        System.out.println("connect start");
        SocketChannel socketChannel = null;
        try {

            /**
             * 创建 SocketChannel
             */
            socketChannel = SocketChannel.open();
            socketChannel.connect(new InetSocketAddress("127.0.0.1",8888));

            //SocketChannel.open(new InetSocketAddress("127.0.0.1",8888));

            /**
             * 连接校验
             * socketChannel.isOpen(); // 测试 SocketChannel 是否为 open 状态
             * socketChannel.isConnected(); //测试 SocketChannel 是否已经被连接
             * socketChannel.isConnectionPending(); //测试 SocketChannel 是否正在进行连接
             * socketChannel.finishConnect(); //校验正在进行套接字连接的 SocketChannel是否已经完成连接
             */
            if (socketChannel.isConnected()){
                System.out.println("connect server success");
            }
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            buffer.put("hello server\r\n".getBytes());
            buffer.flip();
            socketChannel.write(buffer);
            System.out.println("send data to server");
            buffer.clear();
            socketChannel.read(buffer);
            System.out.println("accept data from server :"+new String(buffer.array()));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socketChannel!=null){
                try {
                    socketChannel.close();
                    System.out.println("aaaaaaaa");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 阻塞模式
     */
    void unBlock(){
        System.out.println("connect start");
        SocketChannel socketChannel = null;
        try {
            socketChannel = SocketChannel.open();
            socketChannel.connect(new InetSocketAddress("127.0.0.1",8888));
            //设置 SocketChannel 的读写模式。false 表示非阻塞,true 表示阻塞
            socketChannel.configureBlocking(false);
            if (socketChannel.isConnected()){
                System.out.println("connect server success");
            }
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            buffer.put("hello server\r\n".getBytes());
            buffer.flip();
            socketChannel.write(buffer);
            System.out.println("send data to server");
            buffer.clear();
            socketChannel.read(buffer);
            System.out.println("accept data from server :"+new String(buffer.array()));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (socketChannel!=null){
                try {
                    socketChannel.close();
                    System.out.println("aaaaaaaa");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 设置和获取参数
     * socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE,Boolean.TRUE)  保持连接
     * socketChannel..setOption(StandardSocketOptions.TCP_NODELAY,Boolean.TRUE); 默认缓冲区大小:8192byte。
     */
}

DatagramChannel

发包

package com.yangmin.study.io.nio.channel;


import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

/**
 * @author yangmin
 * @version 1.0
 * @description: 基于UDP协议,无连接
 * 向地址ip端口号发送内容;接收ip端口号发送来的内容
 * <p>
 * 正如 SocketChannel 对应 Socket,ServerSocketChannel 对应 ServerSocket,每一个 DatagramChannel 对象也有一个关联的 DatagramSocket 对象。
 * <p>
 * 正如SocketChannel 模拟连接导向的流协议(如 TCP/IP),DatagramChannel 则模拟包导向的无连接协议(如 UDP/IP)。DatagramChannel 是无连接的,每个数据报(datagram)都是一个自包含的实体,拥有它自己的目的地址及不依赖其他数据报的数据负载。与面向流的的 socket 不同,DatagramChannel 可以发送单独的数据报给不同的目的地址。
 * <p>
 * 同样,DatagramChannel 对象也可以接收来自任意地址的数据包。每个到达的数据报都含有关于它来自何处的信息(源地址)
 * <p>
 * 1、打开 DatagramChannel
 * DatagramChannel server = DatagramChannel.open();
 * server.socket().bind(new InetSocketAddress(10086));
 * <p>
 * 此例子是打开 10086 端口接收 UDP 数据包
 * <p>
 * 2、接收数据
 * 通过 receive()接收 UDP 包
 * <p>
 * ByteBuffer receiveBuffer = ByteBuffer.allocate(64);
 * receiveBuffer.clear();
 * SocketAddress receiveAddr = server.receive(receiveBuffer);
 * <p>
 * SocketAddress 可以获得发包的 ip、端口等信息,用 toString 查看,格式如下
 * /127.0.0.1:57126
 * <p>
 * 3、发送数据
 * 通过 send()发送 UDP 包
 * <p>
 * DatagramChannel server = DatagramChannel.open();
 * ByteBuffer sendBuffer = ByteBuffer. wrap ("client send".getBytes());//发送的内容
 * server.send(sendBuffer, new InetSocketAddress("127.0.0.1",10086));
 * <p>
 * 4、连接
 * UDP 不存在真正意义上的连接,这里的连接是向特定服务地址用 read 和 write 接收发送数据包。
 * <p>
 * client.connect(new InetSocketAddress("127.0.0.1",10086));
 * int readSize= client.read(sendBuffer);
 * server.write(sendBuffer);
 * <p>
 * read()和 write()只有在 connect()后才能使用,不然会抛NotYetConnectedException 异常。
 * <p>
 * 用 read()接收时,如果没有接收到包,会抛PortUnreachableException 异常。
 * @date 2022/5/11 15:28
 */
public class DatagramChannelSendTest {

    public static void main(String[] args) {
        DatagramChannelSendTest datagramChannelTest = new DatagramChannelSendTest();
        datagramChannelTest.sendData();
    }

    /**
     * 发送数据
     */
    private void sendData() {
        try {
            DatagramChannel datagramChannel = DatagramChannel.open();
            /**
             * 发送的地址
             */
            InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 8888);
            datagramChannel.send(ByteBuffer.wrap("发包".getBytes()), inetSocketAddress);
            Thread.sleep(2000);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

收包

package com.yangmin.study.io.nio.channel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

/**
 * @author yangmin
 * @version 1.0
 * @description: 收包
 * @date 2022/5/11 15:41
 */
public class DatagramChannelAcceptTest {
    public static void main(String[] args) throws IOException {
        DatagramChannel server = DatagramChannel.open();
        InetSocketAddress socketAddress = new InetSocketAddress(8888);
        server.bind(socketAddress);
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while (true){
            buffer.clear();
            server.receive(buffer);
            System.out.println(new String(buffer.array()));
            System.out.println("发来信息的ip地址:"+socketAddress.toString());
        }

    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

网络编程之channel 的相关文章

随机推荐

  • Windows Terminal + wsl 之调整ls命令颜色、底色方法

    1 显示预设置 执行 cd dircolors p gt dircolors 2 接着修改 用vi 可预览效果 vi dircolors 找到如下条目 修改字体颜色和背景色如下 STICKY OTHER WRITABLE 30 46 dir
  • Matplotlib

    文章目录 1 什么是matplotlib 2 实现一个简单的matplotlib绘图 3 matplotlib图像结构 4 matplotlib基础绘图 多个坐标系显示 plt subplots 面向对象的画图方法 5 常见图形种类 1 什
  • 浏览器控制台反调试

    反反调试 常规方法 前文所提到的几个反调试方法 除debugger方式外 均判断是否打开开发者工具 破解的方式也很简单 基本只需两步就可以搞定 将开发者工具以独立窗口形式打开 打开开发者工具后再打开网址 反反调试 debugger方法 若使
  • Django框架的源码解析

    简述 从django admin startproject name 开始 小结 django core management init py 1 5个方法 2 ManagementUtility 类 小结 base py 1 2个方法 2
  • super.onCreate(savedInstanceState);

    super onCreate savedInstanceState 是调用父类的onCreate构造函数 savedInstanceState是保存当前Activity的状态信息 onCreate方法的参数是一个Bundle类型的参数 Bu
  • Facebook存储65亿张照片的存储框架

    Facebook存储65亿张照片的存储框架 从未用过Facebook 但是还是对Facebook应对大容量的非结构化数据存储方案感兴趣 本文是通过在线网络广播 webcast 经本人翻译得来的 因此 本人并不能确保本文中叙述的内容与原文we
  • C++中结构体、公用体在内存单元占用字节数计算

    一 数据类型所占存储空间对比 数据类型 64位机 32位机 char 1个字节 1个字节 short 2个字节 2个字节 int 4个字节 4个字节 long 8个字节 4个字节 float 4个字节 4字节 double 8个字节 8个字
  • 软件外包开发代码管理工具

    软件代码规范是为了提高代码质量 可读性和可维护性而制定的一系列编程规则和约定 代码管理工具则是用于协助团队成员共享 跟踪和合并代码的工具 今天和大家分享这方面的知识 希望对大家有所帮助 北京木奇移动技术有限公司 专业的软件外包开发公司 欢迎
  • 魅族大数据可视化平台建设之路

    本文是根据魅族科技大数据平台架构师赵天烁3月31日在msup携手魅族主办的第十二期魅族技术开放日 魅族大数据可视化平台建设之路 演讲中的分享内容整理而成 内容简介 本文主要从现状 问题 当前目标 实现方案三个方面介绍了可视化平台的建设之路
  • Python点云处理(二)点云数据可视化

    目录 0 简述 1 matplotlib 1 1 安装 1 2 点云可视化 2 Mayavi 3 Open3D 4 Vispy 5 VTK 6 结语 0 简述 点云可视化是数据分析 数据展示及程序集成的基础性功能 Python提供了许多强大
  • Error:Abnormal build process termination:

    Error Abnormal build process termination C Program Files Java jdk1 8 0 121 bin java Xmx700m Djava awt headless true Djav
  • 分布式计算框架Spark集群实战

    一 Spark整体架构 1 Spark集群架构 从集群部署的角度看 Spark集群由集群管理器 Cluster Manager 工作节点 Worker 执行器 Executor 驱动器 Driver 应用程序 Application 等部分
  • 1.8,strerror和perror

    这个例子主要是报错 其实 我不大注重报错的差异 只要知道大概在哪里出错就行了 先抄代码 运行 ok
  • clone()

    深复制 浅复制
  • css选择器

    css选择器 1 选择器的作用 找到特定的HTML标签元素 选择所需要的标签 2 基础选择器 2 1标签选择器 作用 可以把一类标签全部选择出来 比如div span标签 快速的为页面中同类型的标签统一化 但是不能设计差异化的样式 div
  • WIN10应用程序无法正常启动(0xc0000142)。请单击‘确认’关闭应用程序

    在网上找了好久解决方法 有说用命令行for 1 in windir system32 dll do regsvr32 exe s 1 来重新注册系统组件 有说删除 appdata microsoft templates 这个目录下的文件 还
  • 软件产品license的简单实现java

    目录 软件License简介 License控制内容 实现方案 代码示例讲解 注意事项 源码 软件License简介 我们在使用一些需要购买版权的软件产品时 或者我们做的商业软件需要进行售卖 为了收取费用 一般需要一个软件使用许可证 然后输
  • 基于Arduino开发板和20×4 I2C LCD显示屏制作一款实时时钟

    当我们在制作一个有趣的硬件项目时 可能会需要使用到一款显示屏 但选择显示屏的尺寸和控制它所需的引脚都令人困惑 在上一篇文章中 我们介绍了0 96寸I2C OLED显示屏 在本篇文章中 我们将介绍使用I2C 20 4字符显示屏 所需的零件 本
  • You are running the esm-bundler build of vue-i18n. It is recommended to configure your bundler to ex

    vue3项目启动之后 会提示如下警告 You are running the esm bundler build of vue i18n It is recommended to configure your bundler to expl
  • 网络编程之channel

    介绍 Channel 是一个对象 可以通过它读取和写入数据 拿 NIO 与原来的 I O 做个比较 通道就像是流 所有数据都通过 Buffer 对象来处理 您永远不会将字节直接写入通道中 相反 您是将数据写入包含一个或者多个字节的缓冲区 同