zoukankan      html  css  js  c++  java
  • docker-网络

    一、利用iproute,简单模拟容器之间的通信

    1、添加两个网络名称空间(network namespace)

    [root@node2 ~]# ip netns add r1
    [root@node2 ~]# ip netns add r2
    [root@node2 ~]# ip netns list
    r2
    r1

    2、创建虚拟网卡对。创建完毕后,会成对出现在宿主机上,默认是没有被激活。

    [root@node2 ~]# ip link add name veth1.1 type veth peer name veth1.2
    [root@node2 ~]# ip link show
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT qlen 1
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
        link/ether 00:0c:29:6e:cc:05 brd ff:ff:ff:ff:ff:ff
    3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
        link/ether 00:0c:29:6e:cc:0f brd ff:ff:ff:ff:ff:ff
    4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT 
        link/ether 02:42:9c:a8:8b:e0 brd ff:ff:ff:ff:ff:ff
    5: veth1.2@veth1.1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
        link/ether 22:d8:37:b4:40:9f brd ff:ff:ff:ff:ff:ff
    6: veth1.1@veth1.2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
        link/ether b2:a3:a7:ba:54:ca brd ff:ff:ff:ff:ff:ff

    3、将其中一个虚拟网卡设备veth1.2移动到其中一个网络名称空间r1,并将名字修改为eth0

    [root@node2 ~]# ip link set dev veth1.2 netns r1
    [root@node2 ~]# ip netns exec r1 ip link set dev veth1.2 name eth0

    4、激活网络空间r1名为eth0的网卡,以及留在宿主机上的veth1.1,并进行简单通信

    [root@node2 ~]# ifconfig veth1.1 10.1.0.1/24 up
    [root@node2 ~]# ifconfig
    veth1.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 10.1.0.1  netmask 255.255.255.0  broadcast 10.1.0.255
            inet6 fe80::b0a3:a7ff:feba:54ca  prefixlen 64  scopeid 0x20<link>
            ether b2:a3:a7:ba:54:ca  txqueuelen 1000  (Ethernet)
            RX packets 8  bytes 648 (648.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 8  bytes 648 (648.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    [root@node2 ~]# ip netns exec r1 ifconfig eth0 10.1.0.2/24 up
    [root@node2 ~]# ip netns exec r1 ifconfig
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 10.1.0.2  netmask 255.255.255.0  broadcast 10.1.0.255
            inet6 fe80::20d8:37ff:feb4:409f  prefixlen 64  scopeid 0x20<link>
            ether 22:d8:37:b4:40:9f  txqueuelen 1000  (Ethernet)
            RX packets 8  bytes 648 (648.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 8  bytes 648 (648.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    [root@node2 ~]# ping 10.1.0.2
    PING 10.1.0.2 (10.1.0.2) 56(84) bytes of data.
    64 bytes from 10.1.0.2: icmp_seq=1 ttl=64 time=0.266 ms
    64 bytes from 10.1.0.2: icmp_seq=2 ttl=64 time=0.069 ms
    64 bytes from 10.1.0.2: icmp_seq=3 ttl=64 time=0.062 ms
    64 bytes from 10.1.0.2: icmp_seq=4 ttl=64 time=0.061 ms
    64 bytes from 10.1.0.2: icmp_seq=5 ttl=64 time=0.060 ms
    64 bytes from 10.1.0.2: icmp_seq=6 ttl=64 time=0.069 ms
    64 bytes from 10.1.0.2: icmp_seq=7 ttl=64 time=0.067 ms
    64 bytes from 10.1.0.2: icmp_seq=8 ttl=64 time=0.068 ms
    ^C
    --- 10.1.0.2 ping statistics ---
    8 packets transmitted, 8 received, 0% packet loss, time 7001ms
    rtt min/avg/max/mdev = 0.060/0.090/0.266/0.066 ms

    5、将宿主机上的虚拟网络设备veth1.1移动到另外一个网络名称空间r2中,进行简单通信

    [root@node2 ~]# ip link set dev veth1.1 netns r2
    [root@node2 ~]# ip netns exec r2 ifconfig veth1.1 10.1.0.3/24 up
    [root@node2 ~]# ip netns exec r2 ping 10.1.0.2
    PING 10.1.0.2 (10.1.0.2) 56(84) bytes of data.
    64 bytes from 10.1.0.2: icmp_seq=1 ttl=64 time=0.084 ms
    64 bytes from 10.1.0.2: icmp_seq=2 ttl=64 time=0.060 ms
    64 bytes from 10.1.0.2: icmp_seq=3 ttl=64 time=0.058 ms
    64 bytes from 10.1.0.2: icmp_seq=4 ttl=64 time=0.062 ms
    64 bytes from 10.1.0.2: icmp_seq=5 ttl=64 time=0.056 ms
    ^C
    --- 10.1.0.2 ping statistics ---
    5 packets transmitted, 5 received, 0% packet loss, time 3999ms
    rtt min/avg/max/mdev = 0.056/0.064/0.084/0.010 ms

    以上就简单演示了两个容器的通信。

    二、docker网络模式

    显示docker的网络

    [root@node2 ~]# docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    e5703a4221ca        bridge              bridge              local
    f2db12f815d3        host                host                local
    2d0ce462eb59        none                null                local

    2.1、none模式

    定义:

    网络模式为 none,即不为 Docker 容器构造任何网络环境。一旦Docker 容器采用了none 网络模式,那么容器内部就只能使用loopback网络设备,不会再有其他的网络资源。Docker Container的none网络模式意味着不给该容器创建任何网络环境,容器只能使用127.0.0.1的本机网络。

    [root@node2 ~]# docker run --name t1 -it --rm --network none busybox:latest /bin/sh
    / # ifconfig
    lo        Link encap:Local Loopback  
              inet addr:127.0.0.1  Mask:255.0.0.0
              UP LOOPBACK RUNNING  MTU:65536  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1 
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
    
    / # 

    2.2 bridge模式

    Docker 容器默认使用bridge模式的网络。

    • 使用一个 linux bridge,默认为 docker0
    • 使用 veth 对,一头在容器的网络 namespace 中,一头在 docker0 上
    • 该模式下Docker Container不具有一个公有IP,因为宿主机的IP地址与veth pair的 IP地址不在同一个网段内
    • Docker采用 NAT 方式,将容器内部的服务监听的端口与宿主机的某一个端口port 进行“绑定”,使得宿主机以外的世界可以主动将网络报文发送至容器内部
    • 外界访问容器内的服务时,需要访问宿主机的 IP 以及宿主机的端口 port
    • NAT 模式由于是在三层网络上的实现手段,故肯定会影响网络的传输效率。
    • 容器拥有独立、隔离的网络栈;让容器和宿主机以外的世界通过NAT建立通信

    默认不指定hostname,则为container ID;使用-h 指定hostname

    [root@node2 ~]# docker run --name t1 -it --rm --network bridge busybox:latest 
    / # hostname
    b1bc9ce212d6
    / # 
    
    [root@node2 ~]# docker run --name t1 -it --rm --network bridge -h t1.mustark.com busybox:latest 
    / # hostname
    t1.mustark.com
    / # 

    指定DNS服务器地址与搜索域

    [root@node2 ~]# docker run --name t1 -it --rm --network bridge -h t1.mustark.com --dns 114.114.114.114 --dns-search ilinux.io busybox:latest 
    / # cat /etc/resolv.conf 
    search ilinux.io
    nameserver 114.114.114.114
    / # 

    增加域名解析记录

    [root@node2 ~]# docker run --name t1 -it --rm --network bridge -h t1.mustark.com --dns 114.114.114.114 --dns-search ilinux.io --add-host www.mageedu.com:1.1.1.1 busybox:latest 
    / # cat /etc/hosts
    127.0.0.1    localhost
    ::1    localhost ip6-localhost ip6-loopback
    fe00::0    ip6-localnet
    ff00::0    ip6-mcastprefix
    ff02::1    ip6-allnodes
    ff02::2    ip6-allrouters
    1.1.1.1    www.mageedu.com
    172.17.0.2    t1.mustark.com t1
    / # 

    将容器内部的服务监听的端口与宿主机的某一个端口port 进行“绑定”,使得宿主机以外的世界可以主动将网络报文发送至容器内部,将服务“暴露”

    第一种,将指定容器端口映射至主机所有地址的一个动态端口

    [root@node2 ~]# docker run --name myweb --rm -p 80 mustark/httpd:v0.2

    利用iptables和docker port myweb查看对应的端口

    [root@node2 ~]# docker port myweb
    80/tcp -> 0.0.0.0:32768
    
    
    [root@node2 ~]# iptables -t nat -vnL
    Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
     pkts bytes target     prot opt in     out     source               destination         
        1    52 DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
    
    Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
     pkts bytes target     prot opt in     out     source               destination         
    
    Chain OUTPUT (policy ACCEPT 1 packets, 60 bytes)
     pkts bytes target     prot opt in     out     source               destination         
        0     0 DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL
    
    Chain POSTROUTING (policy ACCEPT 1 packets, 60 bytes)
     pkts bytes target     prot opt in     out     source               destination         
        0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0           
        0     0 MASQUERADE  tcp  --  *      *       172.17.0.2           172.17.0.2           tcp dpt:80
    
    Chain DOCKER (2 references)
     pkts bytes target     prot opt in     out     source               destination         
        0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
        0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:32768 to:172.17.0.2:80

    在浏览器访问

    容器停止后,规则会自动删除。

    第二种情况,将指定的容器端口映射到主机指定的IP地址的动态端口

    [root@node2 ~]# docker run --name myweb --rm -p 10.0.0.62::80 mustark/httpd:v0.2
    
    
    [root@node2 ~]# docker port myweb
    80/tcp -> 10.0.0.62:32768

    第三种情况,将容器的端口映射到主机的端口

    [root@node2 ~]# docker run --name myweb --rm -p 80:80 mustark/httpd:v0.2
    
    
    [root@node2 ~]# docker port myweb
    80/tcp -> 0.0.0.0:80

    第四种情况,将指定的容器端口映射到主机指定的IP地址的端口

    [root@node2 ~]# docker run --name myweb --rm -p 10.0.0.62:8080:80 mustark/httpd:v0.2
    
    
    [root@node2 ~]# docker port myweb
    80/tcp -> 10.0.0.62:8080

    联盟式容器

    指使用某个已存在容器的网络接口的容器,接口被联盟内的各容器使用;彼此之间共享一个网络名称空间,但其他名称空间如User、mount等还是隔离的

    基于busybox创建一个容器

    [root@node2 ~]# docker run --name b1 -it --rm  busybox
    / # ifconfig
    eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
              inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:8 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:648 (648.0 B)  TX bytes:0 (0.0 B)
    
    lo        Link encap:Local Loopback  
              inet addr:127.0.0.1  Mask:255.0.0.0
              UP LOOPBACK RUNNING  MTU:65536  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1 
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
    
    / # 

    基于b1这个容器创建一个容器,可以看到地址是用的b1容器的地址

    [root@node2 ~]# docker run --name b2 --network container:b1 -it --rm busybox
    / # ifconfig
    eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
              inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:8 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:648 (648.0 B)  TX bytes:0 (0.0 B)
    
    lo        Link encap:Local Loopback  
              inet addr:127.0.0.1  Mask:255.0.0.0
              UP LOOPBACK RUNNING  MTU:65536  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1 
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
    
    / # 

    两者彼此的共用网络IO接口,但是文件系统却是隔离的。

    在b1上创建一个目录,b2上是没有的;在b1上启动一个http服务,b2是可以访问的

    b1
    / # mkdir /tmp/testdir -p / # echo "hello world" >/tmp/index.html / # httpd -h /tmp/ / # netstat -tnl Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 :::80 :::* LISTEN
    b2
    / # ls /tmp / # / # wget -O - -q 127.0.0.1 hello world / #

    host模式

    Host 模式并没有为容器创建一个隔离的网络环境。而之所以称之为host模式,是因为该模式下的 Docker 容器会和 host 宿主机共享同一个网络 namespace,故 Docker Container可以和宿主机一样,使用宿主机的eth0,实现和外界的通信。换言之,Docker Container的 IP 地址即为宿主机 eth0 的 IP 地址。其特点包括:

      • 这种模式下的容器没有隔离的 network namespace
      • 容器的 IP 地址同 Docker host 的 IP 地址
      • 需要注意容器中服务的端口号不能与 Docker host 上已经使用的端口号相冲突
      • host 模式能够和其它模式共存
    [root@node2 ~]# docker run --name b1 --network host -it --rm  busybox
    / # echo "hello container" > /tmp/index.html
    / # httpd -h /tmp/
    / # netstat -tnl
    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       
    tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      
    tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      
    tcp        0      0 :::80                   :::*                    LISTEN      
    tcp        0      0 :::22                   :::*                    LISTEN      
    tcp        0      0 ::1:25                  :::*                    LISTEN      
    / # ifconfig
    docker0   Link encap:Ethernet  HWaddr 02:42:9C:A8:8B:E0  
              inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
              inet6 addr: fe80::42:9cff:fea8:8be0/64 Scope:Link
              UP BROADCAST MULTICAST  MTU:1500  Metric:1
              RX packets:42 errors:0 dropped:0 overruns:0 frame:0
              TX packets:50 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:3329 (3.2 KiB)  TX bytes:5224 (5.1 KiB)
    
    eth0      Link encap:Ethernet  HWaddr 00:0C:29:6E:CC:05  
              inet addr:10.0.0.62  Bcast:10.0.0.255  Mask:255.255.255.0
              inet6 addr: fe80::20c:29ff:fe6e:cc05/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:6597 errors:0 dropped:0 overruns:0 frame:0
              TX packets:4024 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000 
              RX bytes:1368597 (1.3 MiB)  TX bytes:460351 (449.5 KiB)
    
    eth1      Link encap:Ethernet  HWaddr 00:0C:29:6E:CC:0F  
              inet addr:172.16.1.62  Bcast:172.16.1.255  Mask:255.255.255.0
              inet6 addr: fe80::20c:29ff:fe6e:cc0f/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:6 errors:0 dropped:0 overruns:0 frame:0
              TX packets:27 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000 
              RX bytes:360 (360.0 B)  TX bytes:1956 (1.9 KiB)
    
    lo        Link encap:Local Loopback  
              inet addr:127.0.0.1  Mask:255.0.0.0
              inet6 addr: ::1/128 Scope:Host
              UP LOOPBACK RUNNING  MTU:65536  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1 
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
    
    / # 

    自定义docker0网络桥

    自定义docker0桥的网络属性信息:/etc/docker/daemon.json文件
    {
      "bip": "192.168.1.5/24",
      "fixed-cidr": "10.20.0.0/16",
      "fixed-cidr-v6": "2001:db8::/64",
      "mtu": 1500,
      "default-gateway": "10.20.1.1",
      "default-gateway-v6": "2001:db8:abcd::89",
      "dns": ["10.20.1.2","10.20.1.3"]
    }
    核心选项为bip,即bridge ip之意,用于指定docker0桥自身的IP地址;其它选项可通过此地址计算得出。

    [root@node2 ~]# systemctl stop docker.service 
    [root@node2 ~]# cat /etc/docker/daemon.json 
    {
        "registry-mirrors": ["https://registry.docker-cn.com"],
        "bip": "172.20.0.1/16"
    }
    [root@node2 ~]# ifconfig
    docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
            inet 172.20.0.1  netmask 255.255.0.0  broadcast 172.20.255.255
            inet6 fe80::42:9cff:fea8:8be0  prefixlen 64  scopeid 0x20<link>
            ether 02:42:9c:a8:8b:e0  txqueuelen 0  (Ethernet)
            RX packets 42  bytes 3329 (3.2 KiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 50  bytes 5224 (5.1 KiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    [root@node2 ~]# systemctl start docker.service 

    此时,docker0桥由默认的172.17.0.1变成了我们定义的172.20.0.1。

    dockerd守护进程的C/S,其默认仅监听Unix SOcket格式的地址,/var/run/docker.sock;如果使用TCP套接字, 

    Centos7下

    /etc/docker/daemon.json会被docker.service的配置文件覆盖,直接添加daemon.json不起作用。可以有如下几种设置:

    直接编辑配置文件:Centos中docker daemon配置文件在/lib/systemd/system/docker.service,找到以下字段,在后面添加如下,注意,此处不能用"fd://",否则报错

    [Service]
    ······
    ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375

    自定义网络桥

    创建一个自定义网络桥

    [root@node2 ~]# docker network create -d bridge --subnet "172.26.0.0/16" --gateway "172.26.0.1" mybr0
    33ac621209dc27967f6918a29cb1a786c616c1be57228b2b5d82e33a6f651d9b
    [root@node2 ~]# docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    42344bf27e25        bridge              bridge              local
    f2db12f815d3        host                host                local
    33ac621209dc        mybr0               bridge              local
    2d0ce462eb59        none                null                local
    [root@node2 ~]# ifconfig
    br-33ac621209dc: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
            inet 172.26.0.1  netmask 255.255.0.0  broadcast 172.26.255.255
            ether 02:42:7f:07:36:f9  txqueuelen 0  (Ethernet)
            RX packets 0  bytes 0 (0.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 0  bytes 0 (0.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
            inet 172.20.0.1  netmask 255.255.0.0  broadcast 172.20.255.255
            ether 02:42:c2:e9:1e:38  txqueuelen 0  (Ethernet)
            RX packets 0  bytes 0 (0.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 0  bytes 0 (0.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

    利用自定义的网络桥创建容器

    [root@node2 ~]# docker run --name b1 -it --network mybr0 --rm  busybox
    / # ifconfig
    eth0      Link encap:Ethernet  HWaddr 02:42:AC:1A:00:02  
              inet addr:172.26.0.2  Bcast:172.26.255.255  Mask:255.255.0.0
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:12 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:1016 (1016.0 B)  TX bytes:0 (0.0 B)
    
    lo        Link encap:Local Loopback  
              inet addr:127.0.0.1  Mask:255.0.0.0
              UP LOOPBACK RUNNING  MTU:65536  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1 
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
    
    / # 
  • 相关阅读:
    ClickOnce發布經驗
    reporting Server組件不全引起的致命錯誤
    異步調用
    Usercontrol Hosted in IE
    MATLAB命令大全(转载)
    一种保护眼睛的好方法
    关于oracle自动编号
    An Algorithm Summary of Programming Collective Intelligence (1)
    An Algorithm Summary of Programming Collective Intelligence (3)
    An Algorithm Summary of Programming Collective Intelligence (4)
  • 原文地址:https://www.cnblogs.com/mustark/p/10333476.html
Copyright © 2011-2022 走看看