• Dockerfile.md


    Docker 使用

    前提条件

    • Docker目前只能在64位CPU架构的计算机上运行(目前只能是x86_64 、amd64)。

    • Linux 3.8 或 更高版本的内核。3.8之前的版本也能运行,但效果不同,遇到问题时大家都建议你升级。

    • 在运行CentOS 6.5及以后版本时,需要内核版本>=2.6.32-431,因为这些内核包含了运行Docker的一些特定修改。

    • 内核必须支持一些是和的存储驱动(strage drive),例如:

      • Device Manage

      • AUFS

      • vfs

      • btrfs

      • 默认存储驱动通常是Device

    • 内核必须支持并开启cgroup和命名空间(banespace)功能

    安装

    这里安装测试是在CentOS 7中进行。
    Docker RPM包已经包含在CentOS-Extra仓库中,所以我们可以直接使用Yum安装:

    $ sudo yum install docker
    

    也可以用 DaoCloud 的安装脚本

    curl -sSL https://get.daocloud.io/docker | sh
    

    命令使用

    Docker 命令使用可以从下面的变迁图所示:

     


     

     

    选项

    • --config=~/.docker:客户端配置文件的位置

    • -D, --debug:启用debug 模块

    • -H, --host=[]:要连接的守护程序套接字

    • -l, --log-level=info:设置log级别

    • --tls:使用TLS; 隐含的--tlsverify

    • --tlscacert=~/.docker/ca.pem:仅由此CA签署的信任证书

    • --tlscert=~/.docker/cert.pem

    • --tlskey=~/.docker/key.pem

    • --tlsverify:使用TLS并验证远程

    镜像仓库

    login

    登陆到一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub
    格式

    docker login [OPTIONS] [SERVER]
    

    子选项

    • -p, --password string Password

    • -u, --username string Username

    logout

    登出一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub。
    格式

    docker logout [SERVER]
    

    从Docker Hub查找镜像。
    格式

    docker search [OPTIONS] TERM
    

    子选项

    • -f, --filter value:基于提供的条件过滤输出

    • --limit int:搜索结果的最大数量(默认为25)

    # docker search  --limit 2 --filter=stars=10 centos 
    NAME      DESCRIPTION                     STARS     OFFICIAL   AUTOMATED
    centos    The official build of CentOS.   3005      [OK]
    

    pull

    从镜像仓库中拉取镜像或repository。
    格式

    docker pull [OPTIONS] NAME[:TAG|@DIGEST]
    

    子选项

    • -a, --all-tags:下载镜像仓库中的所有标记的镜像

    • --disable-content-trust:跳过镜像验证(默认为true)

    下面是在官方仓库下载最近版本的官方镜像,所以在pull镜像是最好是指定版本。

    # docker pull nginx:1.10.0
    1.10.0: Pulling from library/nginx
    51f5c6a04d83: Pull complete 
    a3ed95caeb02: Pull complete 
    14ef99dba46e: Pull complete 
    3e91b3ec524a: Pull complete 
    Digest: sha256:7224f0a40f2110889889f47dcafa972a8658b7bdd3b50cfa12fd5f80364cbcfe
    Status: Downloaded newer image for nginx:1.10.0
    

    当然也可以从官方镜像中下载别人自己制作好的镜像,形如docker pull username/repository<:tag_name>
    我们也可以在自己搭建的私有仓库中进行获取镜像,例如:docker pull registry.domain.com:5000/repos:<tag_name>

    push

    将本地的镜像上传到镜像仓库,要先登陆到镜像仓库。
    格式

    docker push [OPTIONS] NAME[:TAG]
    

    子选项

    • --disable-content-trust:跳过镜像验证(默认为true)

    上传本地镜像到仓库中:

    # docker push nginx:1.10.0
    

    本地镜像管理

    images

    列出本地镜像。
    格式

    docker images [OPTIONS] [REPOSITORY[:TAG]]
    

    子选项

    • -a, --all:显示所有镜像(默认隐藏中间镜像)

    • --digests:显示DIGEST信息

    • -f, --filter value:基于提供的条件过滤输出(默认[])

    • -q, --quiet:仅显示数字ID

    # docker images
    REPOSITORY                              TAG                    IMAGE ID            CREATED             SIZE
    registry                                latest                 182810e6ba8c        2 weeks ago         37.6 MB
    nginx                                   1.11.8                 01f818af747d        2 weeks ago         181.6 M
    # docker images -q
    182810e6ba8c
    01f818af747d
    

    rmi

    删除本地一个或多少镜像。
    格式

    docker rmi [OPTIONS] IMAGE [IMAGE...]
    

    子选项

    • -f :强制删除;

    • --no-prune :不移除该镜像的过程镜像,默认移除;

    tag

    标记本地镜像,将其归入某一仓库。
    格式

    docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
    

    使用
    将镜像ubuntu:latest标记为 ubuntu:16.04 镜像。

    # docker tag ubuntu:latest ubuntu:16.04
    

    build

    根据Dockerfile创建镜像。
    格式

    docker build [OPTIONS] PATH | URL | -
    

    子选项

    • --build-arg=[] :设置镜像创建时的变量;

    • -c, --cpu-shares int :设置 cpu 使用权重;

    • --cpu-period :限制 CPU CFS周期;

    • --cpu-quota :限制 CPU CFS配额;

    • --cpuset-cpus :指定使用的CPU id;

    • --cpuset-mems :指定使用的内存 id;

    • --disable-content-trust :忽略校验,默认开启;

    • -f, --file string:指定要使用的Dockerfile路径;

    • --force-rm :设置镜像过程中删除中间容器;

    • --isolation :使用容器隔离技术;

    • --label=[] :设置镜像使用的元数据;

    • -m, --memory string:设置内存最大值;

    • --memory-swap :设置Swap的最大值为内存+swap,"-1"表示不限swap;

    • --no-cache :创建镜像的过程不使用缓存;

    • --pull :尝试去更新镜像的新版本;

    • -q :安静模式,成功后只输出镜像ID;

    • --rm :设置镜像成功后删除中间容器;

    • --shm-size :设置/dev/shm的大小,默认值是64M;

    • -t, --tag value:名称和可选的“name:tag”格式的标签(默认[])

    • --ulimit :Ulimit配置。

    举例

    history

    格式

    docker history [OPTIONS] IMAGE
    

    子选项

    • -H :以可读的格式打印镜像大小和日期,默认为true;

    • --no-trunc :显示完整的提交记录;

    • -q :仅列出提交记录ID。

    举例
    查看本地镜像nginx:1.10.0的创建历史:

    # docker history nginx:1.10.0
    IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
    16666ff3a57f        7 months ago        /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon o   0 B                 
    <missing>           7 months ago        /bin/sh -c #(nop) EXPOSE 443/tcp 80/tcp         0 B                 
    <missing>           7 months ago        /bin/sh -c ln -sf /dev/stdout /var/log/nginx/   0 B                 
    <missing>           7 months ago        /bin/sh -c apt-key adv --keyserver hkp://pgp.   57.65 MB            
    <missing>           7 months ago        /bin/sh -c #(nop) ENV NGINX_VERSION=1.10.0-1~   0 B                 
    <missing>           7 months ago        /bin/sh -c #(nop) MAINTAINER NGINX Docker Mai   0 B                 
    <missing>           7 months ago        /bin/sh -c #(nop) CMD ["/bin/bash"]             0 B                 
    <missing>           7 months ago        /bin/sh -c #(nop) ADD file:5d8521419ad6cfb695   125.1 MB
    

    save

    将指定镜像保存成 tar 归档文件。
    格式

    docker save [OPTIONS] IMAGE [IMAGE...]
    

    选项

    • -o :写入到文件,而不是STDOUT

    使用举例
    将镜像nginx:1.10.0 生成nginx_1.10.0.tar文档

    # docker save -o nginx_1.10.0.tar nginx:1.10.0
    

    import

    从归档文件中创建镜像。
    格式

    docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
    

    子选项

    • -c :将Dockerfile指令应用于创建的映像(默认[])

    • -m :提交时的说明文字;

    举例
    从镜像归档文件nginx_1.10.0.tar创建镜像,命名为local/nginx:1.10.0

    # docker import -m "local import" nginx_1.10.0.tar local/nginx:1.10.0
    sha256:ff9738d2818bbb2690603b54256af69999a44c78b4f3aa4ccd598639227d83ff
    # docker history local/nginx:1.10.0
    IMAGE               CREATED             CREATED BY          SIZE                COMMENT
    ff9738d2818b        33 seconds ago                          190.7 MB            local import
    

    容器生命周期管理

    run

    格式

    Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
    

    docker run命令首先会从特定的image创之上create一层可写的container,然后通过start命令来启动它。停止的container可以重新启动并保留原来的修改。
    当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:

    • 检查本地是否存在指定的镜像,不存在就从公有仓库下载

    • 利用镜像创建并启动一个容器

    • 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层

    • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去

    • 从地址池配置一个 ip 地址给容器

    • 执行用户指定的应用程序

    • 执行完毕后容器被终止

    子选项

    • -a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;

    • -d: 后台运行容器,并返回容器ID;

    • -i: 以交互模式运行容器,通常与 -t 同时使用;

    • -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;

    • --name="nginx-lb": 为容器指定一个名称;

    • --dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;

    • --dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;

    • -h "mars": 指定容器的hostname;

    • -e username="ritchie": 设置环境变量;

    • --env-file=[]: 从指定文件读入环境变量;

    • --cpuset="0-2" or --cpuset="0,1,2": 绑定容器到指定CPU运行;

    • -m :设置容器使用内存最大值;

    • --net="bridge": 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;

    • --link=[]: 添加链接到另一个容器;

    • --expose=[]: 开放一个端口或一组端口;

    • -p, --publish value: 开启容器时将容器的端口与主机的端口进行绑定;

    • -P, --publish-all:将所有暴露的端口发布到随机端口;

    • -v, --volume value:绑定挂载的卷;

    • --volumes-from value:从指定的容器挂载卷;

    • -w, --workdir string:容器中的工作目录

    使用举例
    创建一个容器执行相关命令:

    # docker run centos:6.8 echo 'Hello World!'
    Hello World!
    

    上面的例子中是运行一个docker 容器,然后打印Hello World!,之后就退出容器。在上面的例子中虽然容器退出了但是该容器并没有删除,在测试时候我们可以在启动容器使用--rm 参数来在使用容器后删除容器。

    # docker run -it --rm --name test centos:6.8 /bin/bash
    [root@cf33a287ad44 /]#
    

    上面的例子是指定了容器的名字test,在日常使用中这么操作比较容易管理。

    运行出一个container放到后台运行:

    # docker run -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 2; done"
    ae60c4b642058fefcc61ada85a610914bed9f5df0e2aa147100eab85cea785dc
    

    映射host到container的端口和目录:
    映射主机到容器的端口是很有用的,比如在container中运行memcached,端口为11211,运行容器的host可以连接container的 internel_ip:11211 访问,如果有从其他主机访问memcached需求那就可以通过-p选项,形如-p <host_port:contain_port>,存在以下几种写法:

    -p 11211:11211 这个即是默认情况下,绑定主机所有网卡(0.0.0.0)的11211端口到容器的11211端口上
    -p 127.0.0.1:11211:11211 只绑定localhost这个接口的11211端口
    -p 127.0.0.1::5000
    -p 127.0.0.1:80:8080
    

    目录映射其实是“绑定挂载”host的路径到container的目录,这对于内外传送文件比较方便,在搭建私服那一节,为了避免私服container停止以后保存的images不被删除,就要把提交的images保存到挂载的主机目录下。使用比较简单,-v <host_path:container_path>,绑定多个目录时再加-v。

    -v /tmp/docker:/tmp/docker
    

    start

    格式

    docker start [OPTIONS] CONTAINER [CONTAINER...]
    

    子选项

    • -a, --attach:Attach STDOUT/STDERR and forward signals

    • --detach-keys string:覆盖用于分离容器的键序列

    • -i, --interactive:Attach container's STDIN

    stop

    格式

    docker stop [OPTIONS] CONTAINER [CONTAINER...]
    

    子选项

    • -t, --time int:容器停止之前等待多少时间kill掉。(默认10)

    restart

    格式

    docker restart [OPTIONS] CONTAINER [CONTAINER...]
    

    子选项

    • -t, --time int:容器停止之前等待多少时间kill掉。(默认10)

    kill

    格式

    docker kill [OPTIONS] CONTAINER [CONTAINER...]
    

    子选项

    • -s, --signal string:发送到容器的信号(默认为“KILL”)

    rm

    格式

    docker rm [OPTIONS] CONTAINER [CONTAINER...]
    

    子选项

    • -f, --force :通过SIGKILL信号强制删除一个运行中的容器

    • -l, --link:移除容器间的网络连接,而非容器本身

    • -v, --volumes:删除与容器关联的卷

    pause

    暂停一个或多个容器中所有的进程。
    格式

    docker pause CONTAINER [CONTAINER...]
    

    unpause

    取消暂停一个或多个容器中的所有进程。
    格式

     docker unpause CONTAINER [CONTAINER...]
    

    create

    创建一个新的容器但不启动它。
    格式

    docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
    

    子选项
    子选项和run 命令的子选项通用。

    exec

    在运行的容器中执行命令。
    格式

    docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
    

    子选项

    • -d :分离模式: 在后台运行

    • -i :即使没有附加也保持STDIN 打开

    • -t :分配一个伪终端

    • -u, --user:Username or UID (format: <name|uid>[:<group|gid>])

    容器操作

    ps

    列出容器。
    格式

    docker ps [OPTIONS]
    

    子选项

    • -a :显示所有的容器,包括未运行的。

    • -f :根据条件过滤显示的内容。

    • --format :指定返回值的模板文件。

    • -l, --latest :显示最近创建的容器。

    • -n :列出最近创建的n个容器。

    • --no-trunc :不截断输出。

    • -q, --quiet :静默模式,只显示容器编号。

    • -s, --size :显示总的文件大小。

    inspect

    获取容器/镜像的元数据。
    格式

    docker inspect [OPTIONS] CONTAINER|IMAGE|TASK [CONTAINER|IMAGE|TASK...]
    

    子选项

    • -f, --format :使用给定的go模板格式化输出。

    • -s, --size :如果类型为容器,则显示总文件大小。

    • --type :为指定类型返回JSON。

    举例
    获取正在运行的容器ubuntu_test的 IP。

    # docker inspect -f '{{ .NetworkSettings.IPAddress }}' ubuntu_test
    172.17.0.2
    

    top

    查看容器中运行的进程信息,支持 ps 命令参数。
    格式

    docker top CONTAINER [ps OPTIONS]
    

    容器运行时不一定有/bin/bash终端来交互执行top命令,而且容器还不一定有top命令,可以使用docker top来实现查看container中正在运行的进程。

    events

    从服务器获取实时事件。
    格式

    docker events [OPTIONS]
    

    子选项

    • -f, --filter value :根据条件过滤事件;

    • --since string :从指定的时间戳后显示所有事件;

    • --until string :流水时间显示到指定的时间为止;

    logs

    获取容器的日志。
    格式

    docker logs [OPTIONS] CONTAINER
    

    子选项

    • -f, --follow : 跟踪日志输出

    • --since string :显示某个开始时间的所有日志

    • -t, --timestamps : 显示时间戳

    • --tail string :仅列出最新N条容器日志

    • --details:显示提供给日志的额外详情

    wait

    阻塞运行直到容器停止,然后打印出它的退出代码。
    格式

    docker wait CONTAINER [CONTAINER...]
    

    export

    将容器的文件系统导出为tar存档。
    格式

    docker export [OPTIONS] CONTAINER
    
    • -o, --output string:将输入内容写到文件。

    将名称为ubuntu_test 的容器保存为ubuntu_test.tar 文件:

    # docker ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    d749ca04f897        ubuntu:14.04        "sh"                About an hour ago   Up About an hour                        ubuntu_test
    # docker export -o ubuntu_test.tar ubuntu_test
    

    port

    列出端口映射或容器的特定映射。
    格式

    docker port CONTAINER [PRIVATE_PORT[/PROTO]]
    

    容器rootfs命令

    commit

    从容器创建一个新的镜像。
    格式

    docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
    

    子选项

    • -a, --author string :提交的镜像作者;

    • -c, --change value :使用Dockerfile指令来创建镜像;

    • -m :提交时的说明文字;

    • -p :在commit时,将容器暂停。

    cp

    用于容器与主机之间的数据拷贝。
    格式

    docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
    docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
    

    子选项
    -L, --follow-link :保持源目标中的链接

    举例
    将当前目录中的Dockerfile拷贝到ubuntu_test容器的tmp目录下:

    # docker cp Dockerfile ubuntu_test:/tmp/
    

    diff

    检查容器里文件结构的更改。
    格式

    docker diff CONTAINER
    

    Dockerfile

    Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行。
    一般的,Dockerfile 分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。

    FROM

    格式为 FROM <image>FROM <image>:<tag>
    第一条指令必须为 FROM 指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个 FROM 指令( 每个镜像一次) 。

    MAINTAINER

    格式为 MAINTAINER <name> ,指定维护者信息。

    RUN

    格式为 RUN <command>RUN ["executable", "param1", "param2"]
    前者将在 shell 终端中运行命令,即 /bin/sh -c ;后者则使用 exec 执行。指定使用其它终端可以通过第二种方式实现,例如 RUN ["/bin/bash", "-c", "echo hello"]
    每条 RUN 指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 来换行。

    CMD

    CMD指令用于指定一个容器启动时要运行的命令。这有点类是于RUN指令,只是RUN指令是指定镜像被构建时要运行的命令,而CMD是指定容器被启动时要运行的命令。这和使用docker run 命令启动容器时指定要运行的命令非常类似。

    支持三种格式

    • CMD ["executable","param1","param2"] 使用 exec 执行,推荐方式;

    • CMD command param1 param2 在 /bin/sh 中执行,提供给需要交互的应用;

    • CMD ["param1","param2"] 提供给 ENTRYPOINT 的默认参数;

    注意

    • 指定启动容器时执行的命令,每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条命令,只有最后一条会被执行。

    • 如果用户启动容器时候指定了运行的命令,则会覆盖掉 CMD 指定的命令。

    EXPOSE

    格式为 EXPOSE <port> [<port>...]
    告诉 Docker 服务端容器暴露的端口号,供互联系统使用。在启动容器时需要通过 -P,Docker 主机会自动分配一个端口转发到指定的端口。

    ENV

    格式为 ENV <key> <value> 。 指定一个环境变量,会被后续 RUN指令使用,并在容器运行时保持。
    例如

    ENV PG_MAJOR 9.3
    ENV PG_VERSION 9.3.4
    RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
    ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
    

    ADD

    格式为 ADD <src> <dest>
    该命令将复制指定的 <src> 到容器中的 <dest> 。 其中 <src> 可以是Dockerfile所在目录的一个相对路径;也可以是一个 URL;还可以是一个 tar 文件( 自动解压为目录) 。

    COPY

    格式为 COPY <src> <dest>
    复制本地主机的 <src> (为 Dockerfile 所在目录的相对路径) 到容器中的 <dest>
    当使用本地目录为源目录时,推荐使用 COPY 。

    ENTRYPOINT

    两种格式:

    • ENTRYPOINT ["executable", "param1", "param2"]

    • ENTRYPOINT command param1 param2 ( shell中执行) 。

    配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。
    每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。

    VOLUME

    格式为 VOLUME ["/data"]
    创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据
    等。

    USER

    格式为 USER daemon
    指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。
    当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户,例如: RUN groupadd -r postgres && useradd -r -g postgres postgres 。要临时获取管理员权限可以使用 gosu ,而不推荐 sudo 。

    WORKDIR

    格式为 WORKDIR /path/to/workdir
    为后续的 RUN 、 CMD 、 ENTRYPOINT 指令配置工作目录。
    可以使用多个 WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如

    WORKDIR /a
    WORKDIR b
    WORKDIR c
    RUN pwd
    

    则最终路径为 /a/b/c 。

    ONBUILD

    格式为 ONBUILD [INSTRUCTION]
    配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。
    例如,Dockerfile 使用如下的内容创建了镜像 image-A 。

    [...]
    ONBUILD ADD . /app/src
    ONBUILD RUN /usr/local/bin/python-build --dir /app/src
    [...]
    

    如果基于 image-A 创建新的镜像时,新的Dockerfile中使用 FROM image-A 指定基础镜像时,会自动执行 ONBUILD 指令内容,等价于在后面添加了两条指令。

    FROM image-A
    #Automatically run the following
    ADD . /app/src
    RUN /usr/local/bin/python-build --dir /app/src
    

    使用 ONBUILD 指令的镜像,推荐在标签中注明,例如 ruby:1.9-onbuild 。

    LABEL

    LABEL指令用于为Docker镜像添加元数据。元数据以键值对的形式展现。

    STOPSIGNAL

    STOPSIGNAL 指令用来设置停止容器时发送什么系统调用信号给容器。这个信号必须是内核系统调用表中合法的数,如9,或者SIGNAME 格式的信号名称,如SIGKILL。

    ARG

    ARG 指令用来定义可以在docker build 命令运行时传递给构建运行时的变量,我们只需要在构建时使用--build-arg 标志即可。用户只能在构建时指定在Dockerfile 文件中定义过的参数。
    例如:

    ARG build
    ARG webapp_user=user
    

    上面例子中第二条 ARG 指令设置了一个默认值,如果构建时没有为该参数指定值,就会使用这个默认值。如果我们在 docker build 中使用这些参数:

    docker build --build-arg build=1234 -t example/web .
    

    这里构建example/web 镜像时,build变量将会设置为1234,而webapp_user变量则会继承设置的默认值user。

  • 相关阅读:
    OC基础--常用类的初步介绍与简单使用之NSDate
    mysql创建自定义函数与存储过程
    Hibernate Session 获取connection
    mysql中isnull,ifnull,nullif的用法
    mysql数据库中某项其中一个值在该项排第几,百分几
    linux下的ImageMagick安装方法
    Java 判断操作系统类型(适用于各种操作系统)
    tesseract 字体训练资料篇
    structDemo1
    C语言中.h和.c文件解析(很精彩)
  • 原文地址:https://www.cnblogs.com/cuchadanfan/p/6306973.html
Copyright © 2020-2023  润新知