5844
原文地址:http://cloud.51cto.com/art/201501/464053_all.htm引言如果你刚接触Apache CloudStack,想了解和熟悉相关概念,可是苦于没有搭建测试环境所需的种种设备,何不使用你现有的PC和VirtualBox?VirtualBox是一种跨平台的虚拟化应用程序,可以在OS X、Windows、Linux和Solaris等操作系统上运行,这意味着不管你运行什么操作系统,应该都能够运行VirtualBox。本文的目的是,尽管一切都在笔记本电脑上运行,因而受到明显的制约,还是要搭建一个近可能接近生产部署环境的Apache CloudStack 环境。部署的这个系统将支持Apache CloudStack的下列几大功能:生产级虚拟机管理程序:思杰XenServer 6.2,完全支持虚拟局域网(VLAN);CentOS 6.5上的Apache CloudStack;主存储和辅助存储都使用NFS――各自都在专用的VLAN上;控制台代理和辅助存储虚拟机;所有的高级网络功能特性,比如防火墙、网络地址转换(NAT)、端口转发、负载均衡和虚拟私有云(VPC)。想实现所有这些功能,我们就要在VirtualBox上部署两个虚拟机、为Apache Cloudstack部署一个CentOS虚拟机,以及为虚拟机管理程序部署一个思杰XenServer虚拟机。CloudStack虚拟机还将充当我们的MySQL服务器和NFS服务器。这种测试环境的一大要求就是,让该环境保持完全独立,那样它可以用于培训(插入Bootcamp链接)和演示等用途。为了实现这个目标,并且保持这一功能:部署新的区域(Zone),下载系统中所要使用的示例CentOS模板,我们模拟CloudStack公共网络,使用NGINX在CloudStack管理服务器上托管运行默认的CentOS模板。VirtualBox配置从https://www.virtualbox.org/wiki/Downloads,下载并安装合适的版本。一旦VirtualBox安装完毕,我们就需要对它进行配置,以便准备用于该环境。尽可能使用默认值,但如果你之前已经一直在使用VirtualBox,可能需要调整不同的设置。我们将使用三个“Host Only”(仅主机)网络、一个“NAT”网络和一个“Internal”(内部)网络。默认情况下,VirtualBox只有一个“仅主机”网络,于是我们需要另外构建两个仅主机网络。1. 从“文件”菜单(Windows)或VirtualBox菜单(OS X),选择“Preferences”(偏好设置),然后依次选择“Network”(网络)和“Host-only Networks”(仅主机网络)。2. 另外构建两个网络,那样至少有三个网络可供我们使用。3. 为头两个网络设置IP模式(IP Schema),如下所示:仅主机网络的命名约定不一样,这取决于主机的操作系统,我只是将这些称之为“仅主机网络1”、“仅主机网络2”和“仅主机网络3”,依次类推,所以不妨参阅下列比较矩阵,即可识别正确的网络。This Guide Windows OS X仅主机网络1 VirtualBox仅主机以太网适配器 vboxnet0仅主机网络2 VirtualBox仅主机以太网适配器#2 vboxnet1仅主机网络3 VirtualBox仅主机以太网适配器#3 vboxnet2仅主机网络1:IPv4地址:192.168.56.1IPv4网络掩码:255.255.255.0DHCP服务器是可选的,因为我们并不使用它,但要确保地址范围与我们将要使用的静态IP:192.168.56.11和192.168.56.101没有冲突。仅主机网络2:IPv4地址:172.30.0.1IPv4网络掩码:255.255.255.0通过设置这些IP地址范围,我们就能确保充当主机的笔记本电脑在这些网络上有一个IP,那样我们就能访问与它们连接的虚拟机。我们不需要“仅主机网络3”上的IP,因为这个将用于存储,而且还要运行VLAN。我们使用NAT网络,那样我们就能将CloudStack管理虚拟机连接到互联网,从而能够安装我们所要使用的各种程序包。配置VirtualBox“NatNetwork”,以便使用下列设置:网络名称:NatNetwork网络CIDR:10.0.2.0/24由于我们无法控制范围,于是禁用了DHCP,将虚拟机上静态分配的IP排除在外。虽然本文主要介绍构建单一的CloudStack管理服务器,但是你很容易添加第二台CloudStack管理服务器;我发现,来自NAT网络的DHCP分配IP地址会随机变化,所以设置NAT规则可能问题重重,因此我总是使用静态分配的IP地址。“内部”网络根本不需要配置。CloudStack虚拟机使用下列设置,为CloudStack管理器创建一个虚拟机:名称:CSMAN 4.4.1类型:Linux版本:Red Hat(64位)内存:2048(初始安装不能低于这个值)硬盘:VDI―动态―64 GB(我们分配了这么多的容量,是因为它将充当NFS存储区)。注意:如果你同时增添所有网络,VirtualBox似乎会将这些网络混同起来,于是我们先添加第1个网络,并安装CentOS,然后一旦完全安装完毕,我们就添加额外的网络,可是在这当中会重启,这似乎是最新版本VirtualBox(截至本文截稿时是4.3.18)的一个bug。改动设置,为第1个网络适配器分配正确的网络,如下所示:安装CentOS 6.5 64位minimal版,将主机名称设为CSMAN,将IP地址设为192.168.56.11/24,网关为192.168.56.1,并确保网络已设置成引导时启动。将DNS设成公共服务器,比如8.8.8.8 & 8.8.4.4。一旦安装完毕,重启虚拟机,核实eth0处于活动状态,然后关闭虚拟机,添加第2个网络适配器。引导虚拟机,那样它能检测到网卡,然后关闭,添加第3个适配器。引导虚拟机,那样它能检测到网卡,然后关闭,添加第4个适配器。最后,引导虚拟机,那样它能检测到最后一个适配器,然后我们就能为各个网卡配置正确的IP模式。ifcfg-eth0 DEVICE=eth0 TYPE=Ethernet IPADDR=192.168.56.11 PREFIX=24 ONBOOT=yes NM_CONTROLLED=no BOOTPROTO=none IPV4_FAILURE_FATAL=yes IPV6INIT=no NAME=MGMT ifcfg-eth1 DEVICE=eth1 TYPE=Ethernet IPADDR=10.0.2.11 GATEWAY=10.0.2.1 PREFIX=24 ONBOOT=yes NM_CONTROLLED=no BOOTPROTO=none DEFROUTE=yes PEERROUTES=yes IPV4_FAILURE_FATAL=yes IPV6INIT=no NAME=NAT ifcfg-eth2 DEVICE=eth2 TYPE=Ethernet IPADDR=172.30.0.11 PREFIX=24 ONBOOT=yes NM_CONTROLLED=no BOOTPROTO=none IPV4_FAILURE_FATAL=yes IPV6INIT=no NAME=PUBLIC ifcfg-eth3 DEVICE=eth3 TYPE=Ethernet BOOTPROTO=none ONBOOT=yes MTU=9000 VLAN=yes USERCTL=no MTU=9000 ifcfg-eth3.100 DEVICE=eth3.100 TYPE=Ethernet IPADDR=10.10.100.11 PREFIX=24 ONBOOT=yes BOOTPROTO=none NAME=PRI-STOR VLAN=yes USERCTL=no MTU=9000 ifcfg-eth3.101 DEVICE=eth3.101 TYPE=Ethernet IPADDR=10.10.101.11 PREFIX=24 ONBOOT=yes BOOTPROTO=none NAME=SEC-STOR VLAN=yes USERCTL=no MTU=9000 重启网络让新设置生效,然后打上所有最新的更新版。service networking restart yum update -y 安装和配置基本的虚拟机构建好后,我们现在需要安装Apache CloudStack及该虚拟机将托管运行的其他所有服务。首先我们要确保虚拟机配置正确。SelinuxSelinux需要设置成“permissive”(宽容模式),为此我们可以通过运行下面两个命令来实现:setenforce permissive sed -i “/SELINUX=enforcing/ c\SELINUX=permissive” /etc/selinux/config 主机名称你在运行hostname –fqdn后,CloudStack管理服务器应该会返回FQDN(完全符合标准的域名),但由于我们没有安装一个正常运行的DNS,可能会返回“未知主机”。为了解决这个问题,我们只要在Hosts文件里面添加一项;我们在Hosts文件里面时,最好也为xenserver添加一项。用下面命令更新/etc/hosts,然后重启让其生效。127.0.0.1 localhost localhost.cstack.local 192.168.56.11 csman.cstack.local csman 192.168.56.101 xenserver.cstack.local xenserver 为SSH连接提速由于你想使用SSH连接到CloudStack虚拟机,有必要关闭DNS检查,以便为连接提速。运行下列命令:sed -i “/#UseDNS yes/ c\UseDNS no” /etc/ssh/sshd_config service sshd restart NTPsed -i “/#UseDNS yes/ c\UseDNS no” /etc/ssh/sshd_config service sshd restart 安装NTP总是个好主意,所以不妨现在添加NTP,并将它设成引导时启动(你总是可以配置该虚拟机,为XenServer充当NTP服务器,但这不在本文探讨范围之内)。yum install -y ntp# chkconfig ntpd on# service ntpd start CloudStack软件库运行下面这个命令,安装CloudStack软件库:echo “[cloudstack] name=cloudstack baseurl=http://packages.shapeblue.com/cloudstack/main/centos/4.4 enabled=1 gpgcheck=1″ > /etc/yum.repos.d/cloudstack.repo 导入ShapeBlue gpg版本密钥:(密钥ID 584DF93F,密钥指纹= 7203 0CA1 18C1 A275 68B1 37C4 BDF0 E176 584D F93F)yum install wget -y wget http://packages.shapeblue.com/release.asc sudo rpm –import release.asc 安装CloudStack和MySQL现在我们可以安装CloudStack和MySQL Server了:yum install -y cloudstack-management mysql-server 安装NFS服务器由于CSMAN虚拟机还将充当NFS服务器,我们需要设置NFS环境。运行下列命令,即可为主存储和辅助存储创建文件夹,然后将它们导出到合适的IP地址范围。mkdir /exports mkdir -p /exports/primary mkdir -p /exports/secondary chmod 777 -R /exports echo “/exports/primary 10.10.100.0/24(rw,async,no_root_squash)” > /etc/exports echo “/exports/secondary 10.10.101.0/24(rw,async,no_root_squash)” >> /etc/exports exportfs -a 我们现在需要用设置来更新/etc/sysconfig/nfs,以便激活NFS服务器。运行下面这个命令,更新所需的设置sed -i -e ‘/#MOUNTD_NFS_V3=”no”/ c\MOUNTD_NFS_V3=”yes”‘ -e ‘/#RQUOTAD_PORT=875/ c\RQUOTAD_PORT=875′ -e ‘/#LOCKD_TCPPORT=32803/ c\LOCKD_TCPPORT=32803′ -e ‘/#LOCKD_UDPPORT=32769/ c\LOCKD_UDPPORT=32769′ -e ‘/#MOUNTD_PORT=892/ c\MOUNTD_PORT=892′ -e ‘/#STATD_PORT=662/ c\STATD_PORT=662′ -e ‘/#STATD_OUTGOING_PORT=2020/ c\STATD_OUTGOING_PORT=2020′ /etc/sysconfig/nfs 我们还需要更新防火墙设置,让XenServer可以访问导出的NFS,所以运行下列命令,配置所需的设置:sed -i -e “/:OUTPUT/ a\-A INPUT -p tcp -m tcp –dport 111 -j ACCEPT” /etc/sysconfig/iptables sed -i -e “/:OUTPUT/ a\-A INPUT -p udp -m udp –dport 111 -j ACCEPT” /etc/sysconfig/iptables sed -i -e “/:OUTPUT/ a\-A INPUT -p tcp -m tcp –dport 2049 -j ACCEPT” /etc/sysconfig/iptables sed -i -e “/:OUTPUT/ a\-A INPUT -p udp -m udp –dport 2049 -j ACCEPT” /etc/sysconfig/iptables sed -i -e “/:OUTPUT/ a\-A INPUT -p tcp -m tcp –dport 2020 -j ACCEPT” /etc/sysconfig/iptables sed -i -e “/:OUTPUT/ a\-A INPUT -p tcp -m tcp –dport 32803 -j ACCEPT” /etc/sysconfig/iptables sed -i -e “/:OUTPUT/ a\-A INPUT -p udp -m udp –dport 32769 -j ACCEPT” /etc/sysconfig/iptables sed -i -e “/:OUTPUT/ a\-A INPUT -p tcp -m tcp –dport 892 -j ACCEPT” /etc/sysconfig/iptables sed -i -e “/:OUTPUT/ a\-A INPUT -p udp -m udp –dport 892 -j ACCEPT” /etc/sysconfig/iptables sed -i -e “/:OUTPUT/ a\-A INPUT -p tcp -m tcp –dport 875 -j ACCEPT” /etc/sysconfig/iptables sed -i -e “/:OUTPUT/ a\-A INPUT -p udp -m udp –dport 875 -j ACCEPT” /etc/sysconfig/iptables sed -i -e “/:OUTPUT/ a\-A INPUT -p tcp -m tcp –dport 662 -j ACCEPT” /etc/sysconfig/iptables sed -i -e “/:OUTPUT/ a\-A INPUT -p udp -m udp –dport 662 -j ACCEPT” /etc/sysconfig/iptables service iptables restart 然后,我们将nfs服务设成引导时自动启动,还可以立即启动它chkconfig nfs on service nfs start 安装MySQL Serversed -i -e ‘/datadir/ a\innodb_rollback_on_timeout=1′ -e ‘/datadir/ a\innodb_lock_wait_timeout=600′ -e ‘/datadir/ a\max_connections=350′ -e ‘/datadir/ a\log-bin=mysql-bin’ -e “/datadir/ a\binlog-format = ‘ROW’” -e “/datadir/ a\bind-address = 0.0.0.0″ /etc/my.cnf 然后,我们将mysqld服务设成引导时自动启动,还可以立即启动它chkconfig mysqld on service mysqld start 确保默认安装的MySQL安全,这始终是个好主意;有一款使用方便的实用工具可以为你确保其安全。运行下面这个命令,看到提示时设置一个新的密码(当前密码将是空的),接受删除匿名用户、测试数据库和禁用远程访问等的所有默认值。mysql_secure_installation 现在我们将登录进入到MySQL,为根帐户赋予所有权限,这么做是为了可以在下一步中创建“cloud”帐户。mysql -u root -p (enter password when prompted) mysql> GRANT ALL PRIVILEGES ON *.* TO ‘root’@'%’ WITH GRANT OPTION; mysql> quit 安装数据库MySQL配置完毕后,我们现在可以安装CloudStack数据库了,只要运行下面两个命令,代替你之前设置的根密码。cloudstack-setup-databases cloud:cloud@127.0.0.1 –deploy-as=root:<password> cloudstack-setup-management Nginx有一个默认的示例模板从cloud.com网站服务器下载;但由于这个测试系统无法实际访问公共互联网,我们需要为辅助存储虚拟机下载该模板提供一个办法。为此,我们将NGINX安装在CSMAN虚拟机上,并使用它托管运行我们模拟的“公共”网络上的模板。首先创建NGINX软件库,为此运行下面这个命令:echo “[nginx] name=nginx repo baseurl=http://nginx.org/packages/centos/\$releasever/\$basearch/ gpgcheck=0 enabled=1″ > /etc/yum.repos.d/nginx.repo 然后安装NGINX,为此运行下面这个命令:yum install nginx -y 现在,我们运行下面两个命令,下载XenServer的示例CentOS模板:cd /usr/share/nginx/html wget -nc http://download.cloud.com/templates/builtin/centos56-x86_64.vhd.bz2 我们需要添加防火墙规则,允许通过端口80来访问,所以运行下面两个命令:sed -i -e “/:OUTPUT/ a\-A INPUT -p tcp -m tcp –dport 80 -j ACCEPT” /etc/sysconfig/iptables service iptables restart 最后,我们启动nginx服务,通过从Host笔记本电脑访问http://192.168.56.11/,对它进行测试service nginx start XenServer vhd-util由于我们要使用思杰XenServer作为虚拟机管理程序,我们需要下载一个特殊的实用工具,每个XenServer添加到系统上后,该实用工具将拷贝到每个XenServer。运行下面几行,即可下载文件、更新许可权限。cd /usr/share/cloudstack-common/scripts/vm/hypervisor/xenserver/ wget http://download.cloud.com.s3.amazonaws.com/tools/vhd-util chmod 755 /usr/share/cloudstack-common/scripts/vm/hypervisor/xenserver/vhd-util 创建CloudStack默认系统虚拟机模板由于现在我们需要为辅助存储创建XenServer系统虚拟机模板,于是运行下面这个命令:/usr/share/cloudstack-common/scripts/storage/secondary/cloud-install-sys-tmplt -m /exports/secondary -u http://packages.shapeblue.com/systemvmtemplate/4.4/4.4.1/systemvm64template-4.4.1-7-xen.vhd.bz2 -h xenserver -F CloudStack Usage Server一个可选的步骤是安装CloudStack Usage Service,为此运行下面这个命令:yum install cloudstack-usage -y service cloudstack-usage start 定制配置为了让这个测试系统能够在4GB内存的笔记本电脑上有限的可用资源里面工作,我们需要对配置做多处改动。首先,我们需要启用使用支持非HVM(完全虚拟化)的XenServer。你将XenServer安装到VirtualBox上时,它会提醒它只支持PV(半虚拟化),而不支持HVM。为了解决这个问题,我们运行下列SQL更新命令,为云数据库中的配置表添加新的一行(记得你在安装CloudStack数据库时,代替你所使用的自己的MySQL Cloud密码)。mysql -p<password> cloud -e \ “INSERT INTO cloud.configuration (category, instance, component, name, value, description) VALUES (‘Advanced’, ‘DEFAULT’, ‘management-server’, ‘xen.check.hvm’, ‘false’, ‘Shoud we allow only the XenServers support HVM’);” 下列MySQL命令更新各种全局设置,并更改分配给系统虚拟机的资源,那样它们可以在有限的可用资源里面工作。mysql -u cloud -p<password> UPDATE cloud.configuration SET value=’8096′ WHERE name=’integration.api.port’; UPDATE cloud.configuration SET value=’60′ WHERE name=’expunge.delay’; UPDATE cloud.configuration SET value=’60′ WHERE name=’expunge.interval’; UPDATE cloud.configuration SET value=’60′ WHERE name=’account.cleanup.interval’; UPDATE cloud.configuration SET value=’60′ WHERE name=’capacity.skipcounting.hours’; UPDATE cloud.configuration SET value=’0.99′ WHERE name=’cluster.cpu.allocated.capacity.disablethreshold’; UPDATE cloud.configuration SET value=’0.99′ WHERE name=’cluster.memory.allocated.capacity.disablethreshold’; UPDATE cloud.configuration SET value=’0.99′ WHERE name=’pool.storage.capacity.disablethreshold’; UPDATE cloud.configuration SET value=’0.99′ WHERE name=’pool.storage.allocated.capacity.disablethreshold’; UPDATE cloud.configuration SET value=’60000′ WHERE name=’capacity.check.period’; UPDATE cloud.configuration SET value=’1′ WHERE name=’event.purge.delay’; UPDATE cloud.configuration SET value=’60′ WHERE name=’network.gc.interval’; UPDATE cloud.configuration SET value=’60′ WHERE name=’network.gc.wait’; UPDATE cloud.configuration SET value=’600′ WHERE name=’vm.op.cleanup.interval’; UPDATE cloud.configuration SET value=’60′ WHERE name=’vm.op.cleanup.wait’; UPDATE cloud.configuration SET value=’600′ WHERE name=’vm.tranisition.wait.interval’; UPDATE cloud.configuration SET value=’60′ WHERE name=’vpc.cleanup.interval’; UPDATE cloud.configuration SET value=’4′ WHERE name=’cpu.overprovisioning.factor’; UPDATE cloud.configuration SET value=’8′ WHERE name=’storage.overprovisioning.factor’; UPDATE cloud.configuration SET value=’192.168.56.11/32′ WHERE name=’secstorage.allowed.internal.sites’; UPDATE cloud.configuration SET value=’192.168.56.0/24′ WHERE name=’management.network.cidr’; UPDATE cloud.configuration SET value=’192.168.56.11′ WHERE name=’host’; UPDATE cloud.configuration SET value=’false’ WHERE name=’check.pod.cidrs’; UPDATE cloud.configuration SET value=’0′ WHERE name=’network.throttling.rate’; UPDATE cloud.configuration SET value=’0′ WHERE name=’vm.network.throttling.rate’; UPDATE cloud.configuration SET value=’GMT’ WHERE name=’usage.execution.timezone’; UPDATE cloud.configuration SET value=’16:00′ WHERE name=’usage.stats.job.exec.time’; UPDATE cloud.configuration SET value=’true’ WHERE name=’enable.dynamic.scale.vm’; UPDATE cloud.configuration SET value=’9000′ WHERE name=’secstorage.vm.mtu.size’; UPDATE cloud.configuration SET value=’60′ WHERE name=’alert.wait’; UPDATE cloud.service_offering SET ram_size=’128′, speed=’128′ WHERE vm_type=’domainrouter’; UPDATE cloud.service_offering SET ram_size=’128′, speed=’128′ WHERE vm_type=’elasticloadbalancervm’; UPDATE cloud.service_offering SET ram_size=’128′, speed=’128′ WHERE vm_type=’secondarystoragevm’; UPDATE cloud.service_offering SET ram_size=’128′, speed=’128′ WHERE vm_type=’internalloadbalancervm’; UPDATE cloud.service_offering SET ram_size=’128′, speed=’128′ WHERE vm_type=’consoleproxy’; UPDATE cloud.vm_template SET removed=now() WHERE id=’2′; UPDATE cloud.vm_template SET url=’http://192.168.56.11/centos56-x86_64.vhd.bz2′ WHERE unique_name=’centos56-x86_64-xen’; quit service cloudstack-management restart为了能够通过默认端口8096访问我们启用的Un-Authenticated API,我们需要添加一条防火墙规则。运行下列命令,允许通过防火墙访问端口8096:sed -i -e “/:OUTPUT/ a\-A INPUT -p tcp -m tcp –dport 8096 -j ACCEPT” /etc/sysconfig/iptables service iptables restart 测试用户界面给一两分钟的时间,好让cloudstack-management服务完全重启,然后登录到用户界面(UI),应该可以通过http://192.168.56.11:8080/client/,从Host笔记本电脑来访问该UI:默认的登录信息如下:用户名:admin密码:password域:<空>创建计算方案默认的Compute Offering(计算方案)并不适合这个有限的环境,于是我们需要使用下列设置,创建一个新的计算方案:名称:超小(Ultra Tiny)描述:超小– 1vCPU和128MB内存存储类型:共享式自定义:无处理器核心数量:1处理器(MHz):500内存(MB):128网络速率(Mb/s):无服务质量类型:无提供高可用性:有存储标记:无主机标记:无处理器上限:无公共:是易失性:无部署规划器:无GPU:无减少内存数量成功登录到UI后,数据库会完全部署,所以现在我们可以将内存减少到1GB,为我们的XenServer释放内存。关闭虚拟机,将设置改成1024 MB内存。XenServer虚拟机想配置XenServer,如果你在运行Windows,就需要XenCenter在本地主机上运行;但如果你的主机在运行OS X或Linux,那么你就要添加一个能运行XenCenter的Windows虚拟机。你可以从http://downloadns.citrix.com.edgesuite.net/akdlm/8160/XenServer-6.2.0-XenCenter.msi下载XenCenter。使用下列设置,为XenServer创建一个虚拟机:名称:XenServer类型:Linux版本:Red Hat(64位)虚拟处理器:2内存:1536(如果你的主机有8GB内存,可以考虑分配3072MB)硬盘:VDI – 动态– 24 GB注意:如果你同时添加所有网络,VirtualBox似乎会将它们混同起来,于是我们添加第1个网络,并安装XenServer,然后一旦完全安装完毕,我们添加额外的网络,但在这当中会出现重启。这似乎是最新版本VirtualBox(截至本文截稿时为4.3.18)的一个bug。改动设置,为第1个网络适配器分配正确的网络,如下所示:请注意:我们已将“Promiscuous Mode”(混杂模式)设成“Allow All”(允许所有)。现在安装XenServer 6.2,为此从http://downloadns.citrix.com.edgesuite.net/akdlm/8159/XenServer-6.2.0-install-cd.iso下载ISO文件,引导虚拟机。XenServer安装向导简单直观,不过你会看到警告信息,表明缺少硬件虚拟化的支持,这在意料之中,因为VirtualBox不支持该功能。接受警告,继续下一步。选择合适的区域设置,看到提示时输入下列详细信息(我们为DNS和NTP输入CSMAN虚拟机的IP;虽然本文并不探讨在CSMAN虚拟机上构建这些服务,但这为你提供了之后可以这么做的选项):启用自动精简配置:是安装源:本地介质补充包:无验证:略过密码:<password>静态IP:192.168.56.101/24(无需网关)主机名称:xenserverDNS:192.168.56.11NTP:192.168.56.11一旦XenServer安装完毕,卸载ISO,重启虚拟机。我们现在需要将分配给Dom0的内存数量改成最少推荐数量(400MB),为此只要在XenServer控制台上运行下面这个命令:/opt/xensource/libexec/xen-cmdline –set-xen dom0_mem=400M,max:400M XenServer补丁安装XenServer补丁很重要,虽然XenCenter会告知你需要什么补丁,但由于我们使用OpenSource版本的XenServer,所以我们必须通过命令行来安装补丁。幸好,有好多办法可以让这个过程实现自动化。我个人总是使用PXE来部署XenServer,而补丁的安装环节内置在我的部署过程中。不过,这不在本文探讨范围之内,但是Tim Mackey已写了一篇出色的博文,介绍如何做到这一点,详见http://xenserver.org/discuss-virtualization/virtualization-blog/entry/patching-xenserver-at-scale.html。虽然Tim的方法:每个补丁安装后重启是最佳实践,但安装所有补丁要花很长的时间,所以我在这些非生产测试环境中使用的另一种方法在https://github.com/amesserl/xs_patcher作了详细介绍。这个方法可安装所有补丁,只需要重启一次。配置文件“clearwater”现在有点过时了,应该含有下列内容(而缓存文件夹应该含有相关的补丁文件):XS62E014|78251ea4-e4e7-4d72-85bd-b22bc137e20b|downloadns.citrix.com.edgesuite.net/8736/XS62E014.zip|support.citrix.com/article/CTX140052XS62ESP1|0850b186-4d47-11e3-a720-001b2151a503|downloadns.citrix.com.edgesuite.net/8707/XS62ESP1.zip|support.citrix.com/article/CTX139788XS62ESP1003|c208dc56-36c2-4e91-b8d7-0246575b1828|downloadns.citrix.com.edgesuite.net/9031/XS62ESP1003.zip|support.citrix.com/article/CTX140416XS62ESP1005|1c952800-c030-481c-a0c1-d1b45aa19fcc|downloadns.citrix.com.edgesuite.net/9058/XS62ESP1005.zip|support.citrix.com/article/CTX140553XS62ESP1009|a24d94e1-326b-4eaa-8611-548a1b5f8bd5|downloadns.citrix.com.edgesuite.net/9617/XS62ESP1009.zip|support.citrix.com/article/CTX141191XS62ESP1013|b22d6335-823d-43a6-ba26-28793717125b|downloadns.citrix.com.edgesuite.net/9703/XS62ESP1013.zip|support.citrix.com/article/CTX141480XS62ESP1014|4fc82e62-b938-407d-a2c6-68c8922f3ec2|downloadns.citrix.com.edgesuite.net/9708/XS62ESP1014.zip|support.citrix.com/article/CTX141486一旦你给XenServer全面打上了补丁,关闭它,然后添加第2个适配器,再次要注意我们如何将“混杂模式”设成“允许所有”。启动虚拟机,然后使用XenCenter,对网卡执行“重新扫描”,以检测到这个新网卡,然后关闭,添加第3个适配器,再次要注意我们如何将“混杂模式”设成“允许所有”。启动虚拟机,然后使用XenCenter,对网卡执行“重新扫描”,以检测到这个新网卡,然后关闭,添加第4个适配器,再次要注意我们如何将“混杂模式”设成“允许所有”。启动虚拟机,然后使用XenCenter,对网卡执行“重新扫描”,以检测到最后这个网卡,然后最后一次重启,确保它们都已被激活和连接。配置XenServer网络现在我们准备配置XenServer网络。我们应该已有下列四个网络,有必要确保MAC与VirtualBox中的适配器相对应。我们需要使用一种更合乎逻辑的命名约定,为网络改名,还要创建两个存储网络,并分配VLAN,等等。首先改名,将存储网络的最大传输单元(MTU)设成9000(其余的仍然是默认的1500)。Network 0 – MGMTNetwork 1 – GUESTNetwork 2 – PUBLICNetwork 3 – STORAGE (MTU为9000)下一步,我们使用下列设置,添加主存储网络:类型:外部网络名称:PRI-STORAGE网卡:NIC 3VLAN:100MTU:9000然后,添加辅助存储网络:类型:外部网络名称:SEC-STORAGE网卡:NIC 3VLAN:101MTU:9000最后,我们为主存储网络和辅助存储网络添加IP地址,那样XenServer就能访问它们:名称:PRI-STOR网络:PRI-STORAGEIP地址:10.10.100.101子网掩码:255.255.255.0网关:<空>名称:SEC-STOR网络:SEC-STORAGEIP地址:10.10.101.101子网掩码:55.255.255.0网关:<空>这是XenServer需要的所有配置,所以现在我们可以接着部署我们的第一个区域了。不过在我们着手之前,有必要创建两个虚拟机的快照,那样万一需要,你可以恢复原状,再次启动。部署区域我们现在添加一个高级区域,为此进入到“Infrastructure/Zones/Add Zone”(基础设施/区域/添加区域),创建一个类型为“高级”的新区域,没有安全组。区域名称– TestIPv4 DNS1 – 8.8.8.8内部DNS 1 – 192.168.56.11虚拟机管理程序– XenServer访客CIDR – 10.1.1.0/24下一步,我们需要设置XenServer流量标签,以便与我们分配给XenServer上的每个网络的名称相一致,我们还要添加可选的存储网络,为此将它拖拉到物理网络上。编辑每一个流量类型,并设置下列标签:管理网络– MGMT公共网络– PUBLIC访客网络– GUEST存储网络– SEC-STORAGE然后使用下列设置,继续按区域添加向导的提示来操作公共流量网关– 172.30.0.1网络掩码– 255.255.255.0VLAN – <空>起始IP – 172.30.0.21终止IP -172.30.0.30POD设置POD名称– POD1预留系统网关– 192.168.56.1预留系统网络掩码– 255.255.255.0起始预留系统IP – 192.168.56.21终止预留系统IP – 192.168.56.30访客流量VLAN范围– 600 – 699存储流量网关– 10.10.101.1网络掩码– 255.255.255.0VLAN – <空>起始IP – 10.10.101.21终止IP – 10.10.101.30集群设置虚拟机管理程序– XenServer集群名称– CLU1主机设置主机名称– 192.168.56.101用户名– root密码– <password>主存储设置名称– PRI1范围– Cluster服务器– 10.10.100.11路径– /exports/primary辅助存储设置提供者– NFS名称– SEC1服务器– 10.10.101.11路径– /exports/secondary最后,激活区域,然后给大约5分钟的时间,好让系统虚拟机部署、默认的CentOS模板“下载”到系统中。现在你可以准备部署第一个访客虚拟机了。
8
0 2728天前
4900
今天在CSDN看到一个php输出空白隐形字符65279的问题,在网上找了下,发下这个65279字符是php用来标记文件是utf-8编码的,输出的时候会一起输出到客户端,导致客户端如果使用ajax得到返回值时,无法匹配字符串。php隐形字符65279解释如下:UTF-8 编码的文件可以分为无 BOM 和 BOM 两种格式。何谓BOM? "EF BB BF" 这三个字节就叫BOM,全称是"Byte Order Mard"。在utf8文件中常用BOM来表明这个文件是UTF-8文件,而BOM的本意是在utf16中用。 utf-8文件在php中输出的时候bom是会被输出的,所以要在php中使用utf-8,必须要是使用不带bom头的utf-8文件。 常用的文本编辑软件对utf-8文件保存的支持方式并不一样,使用的时候要特别留意。例如:1、使用ultraedit时,另存时会有“UTF-8”和“UTF-8 - 无BOM”两种选择。2、 window的记事本保存的是带bom的。3、EditPlus软件不同版本对utf-8的保存支持不一样,例如:2.31版本保存的是不带bom的,2.11版本保存的是带bom的。把utf-8文件头去掉的办法:1、使用ultraedit另存,选择“UTF-8 - 无BOM”2、一个很有用的php程序,放在站点根目录下运行,会把目录下全部utf-8文件的bom头去掉//remove the utf-8 boms
//by magicbug at gmail dot com
if (isset($_GET['dir'])){ //config the basedir
$basedir=$_GET['dir'];
}else{
$basedir = '.';
}
$auto = 1;
checkdir($basedir);
function checkdir($basedir){
if ($dh = opendir($basedir)) {
while (($file = readdir($dh)) !== false) {
if ($file != '.' && $file != '..'){
if (!is_dir($basedir."/".$file)) {
echo "filename
$basedir/$file ".checkBOM("$basedir/$file")." <br>";
}else{
$dirname = $basedir."/".$file;
checkdir($dirname);
}
}
}
closedir($dh);
}
}
function checkBOM ($filename) {
global $auto;
$contents = file_get_contents($filename);
$charset[1] = substr($contents, 0, 1);
$charset[2] = substr($contents, 1, 1);
$charset[3] = substr($contents, 2, 1);
if (ord($charset[1]) == 239 && ord($charset[2]) == 187 && ord($charset[3]) == 191) {
if ($auto == 1) {
$rest = substr($contents, 3);
rewrite ($filename, $rest);
return ("<font color=red>BOM found, automatically removed.</font>");
} else {
return ("<font color=red>BOM found.</font>");
}
}
else return ("BOM Not Found.");
}
function rewrite ($filename, $data) {
$filenum = fopen($filename, "w");
flock($filenum, LOCK_EX);
fwrite($filenum, $data);
fclose($filenum);
} 如果觉得麻烦的,也可以直接使用我们已经做好的文件:BOM清理脚本 For PHP
7
0 2735天前
8661
代码为自己根据自己的想法制作而成,目前基本上自己的软件都使用这些代码来进行证书的写入 证书生成以后自动导入到系统的受信任的列表中 当然。。。证书仅用于测试环境,正式用途还请到相关CA中心进行申请正规证书! 证书预览:界面截图: 源码:点击下载程序下载:点击下载
2
0 2780天前
9038
可以使用EMBED标签,不过,特别指明的是,为了让Mozilla/Firefox和IE都能够比较好地工作,需要在type属性上多注意些.本意上是,如果type为audio/x-pn-realaudio-plugin的话,则让浏览器调用REAL播放器来播放,如果type为 video/x-ms-wmv的话,则让浏览器调用Windows Media Player来播放.但实际情况是,在Mozilla/Firefox下,能够按上述所想的调用播放器.但在IE下面,只有RM文件调用REAL,MP3 无论指定哪一种类型,都会调用WMP,这就是说MP3文件,WMP和REAL都能播放,但,WMP的效果要好些.于是,可以这样组合:RM文件,用 REAL播放,WMA文件用WMP播放,MP3文件用WMP播放.代码如下(注:因为只显示控制栏,而不显示图象栏,所以要对高度做限制): RM:<embed type="audio/x-pn-realaudio-plugin" align="middle" autostart="0"
height="45" width="600" loop="false" src="1.rm"/>下面是都使用WMP的 MP3:<embed type="video/x-ms-wmv" align="middle" autostart="0" height="45" width="600"
loop="false" src="mp3.mp3"/> WMA:<embed type="video/x-ms-wmv" align="middle" autostart="0" height="45" width="600"
loop="false" src="butterfly.wma"/>
0
0 2794天前
5937
root默认是不支持远程登录的,用外网连接你必须给权限呢? 解决方法如下: 3.如果你有数据库管理软件,如Navicat,则会简单很多,只需要按照下图操作即可解决(其他数据库软件类似)更改后:
0
0 2796天前
5528
////// XVE For Vista/Win7 Update 5 Beta 1 //////
////// Visual Studio 2008 + VB.NET + .NET Framework 2.0 //////
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim fb(&H200010), peek(4) As Byte
Dim mn, type, l, rl, c, fail As Integer
Dim ts As String
Dim fin, fout As System.IO.FileStream
If MsgBox("请注意,本程序仅供学习之用,请将生成文件立刻删除。" + vbCrLf + "对于使用本程序造成的任何后果,由使用者自行承担法律责任!谢绝跨省。" + vbCrLf + "点击[是],表示您同意自行承担所有责任!", MsgBoxStyle.YesNo) <> MsgBoxResult.Yes Then Exit Sub
Button2.Enabled = False
For i = 0 To ListView1.Items.Count - 1
c = 0
ListView1.Items(i).SubItems(0).Text = "开始转换"
Application.DoEvents()
fin = New System.IO.FileStream(ListView1.Items(i).SubItems(1).Text, IO.FileMode.OpenOrCreate)
l = fin.Length
fin.Read(fb, 0, &H200000)
fin.Read(peek, 0, 4)
mn = (Asc("R") - peek(1) + &H100) And &HFF
If (((peek(2) + mn) And &HFF) = Asc("M") And ((peek(3) + mn) And &HFF) = Asc("F")) Then
type = 1
GoTo ok
End If
mn = (&H26 - peek(1) + &H100) And &HFF
If (((peek(2) + mn) And &HFF) = &HB2 And ((peek(3) + mn) And &HFF) = &H75) Then
type = 2
GoTo ok
End If
mn = (Asc("L") - peek(1) + &H100) And &HFF
If (((peek(2) + mn) And &HFF) = Asc("V")) Then
type = 3
GoTo ok
End If
mn = (Asc("I") - peek(1) + &H100) And &HFF
If (((peek(2) + mn) And &HFF) = Asc("F") And ((peek(3) + mn) And &HFF) = Asc("F")) Then
type = 4
GoTo ok
End If
mn = (-peek(1) + &H100) And &HFF
If (((peek(2) + mn) And &HFF) = 0) Then
type = 5
GoTo ok
End If
mn = (-peek(1) + &H100) And &HFF
If (((peek(2) + mn) And &HFF) = 1 And ((peek(3) + mn) And &HFF) = &HBA) Then
type = 6
GoTo ok
End If
mn = (&H45 - peek(1) + &H100) And &HFF
If (((peek(2) + mn) And &HFF) = &HDF And ((peek(3) + mn) And &HFF) = &HA3) Then
type = 7
GoTo ok
End If
fout = New System.IO.FileStream(ListView1.Items(i).SubItems(1).Text + "1", IO.FileMode.OpenOrCreate)
fout.Write(fb, 0, &H200000)
fout.Write(fb, 0, 4)
fin.Read(fb, 0, &H100000)
fout.Write(fb, 0, &H100000)
ListView1.Items(i).SubItems(0).Text = "失败"
Application.DoEvents()
fail += 1
GoTo nxt
ok:
ts = Split("rmvb wmv flv avi mp4 mpg mkv")(type - 1)
fout = New System.IO.FileStream(ListView1.Items(i).SubItems(1).Text + "." + ts, IO.FileMode.OpenOrCreate)
peek(0) = CByte(Val(Split("46 48 70 82 0 0 26")(type - 1)))
For j = 1 To 3
peek(j) = CByte((CInt(peek(j)) + mn) And &HFF)
Next
fout.Write(peek, 0, 4)
fin.Read(fb, 0, &H3FC)
For j = 1 To &H3FC
fb(j - 1) = CByte((CInt(fb(j - 1)) + mn) And &HFF)
Next
fout.Write(fb, 0, &H3FC)
While fin.Position <= l
rl = fin.Read(fb, 0, &H40000)
If rl = 0 Then Exit While
fout.Write(fb, 0, rl)
c = c + 1
If c = 10 Then
ListView1.Items(i).SubItems(0).Text = "转换" + Trim(Str(Format(fout.Position / (l - &H200000) * 100, "0"))) + "%"
Application.DoEvents()
ProgressBar1.Value = Int(Math.Round(fout.Position / (l - &H200000) * 100))
c = 0
End If
End While
ListView1.Items(i).SubItems(0).Text = "完成转换"
Application.DoEvents()
nxt:
fin.Close()
fout.Close()
Next
MsgBox("转换结束" + vbCrLf + Trim(Str(ListView1.Items.Count - fail)) + "成功," + Trim(Str(fail)) + "失败" + IIf(fail <> 0, "请将目标文件下生成的错误信息文件%s发给作者,以便及时解决问题。" + vbCrLf + "注:该文件为xv文件的前3MB内容,不含有任何涉及您的隐私的信息。" + vbCrLf + "作者的电子邮件:692827763@qq.com", ""))
ProgressBar1.Value = 0
Button2.Enabled = True
End Sub
程序文件:xv转换器
0
0 2796天前
7004
介绍 wma文件的基本组织单元叫做对象,wma文件宏观上由三个顶级对象组成:头对象(Header Object)、 数据对象(Data Object)、其它顶级对象(Other top-level objects),其中前两个对象是必须的。头对象里又包含很多其他的子对象。头对象包含的对象主要有: Wma头(顶级的,实际上是头对象的前30个字节)、文件属性对象(全局文件属性)、流属性对象(定义一个媒体流及其属性)、内容描述对象(包含所有目录信息)、部件下载对象(提供播放部件信息)、流组织对象(逻辑上把多个媒体流组织在一起),等等。这些对象主要描述了非音频压缩数据的一些信息。例如作者,曲目信息,用户加入的命令信息,码流的码率等信息。每个对象相当于一个信息描述符。 数据对象以数据包的形式存储压缩的音频数据,以便于实现网络传输。所有的对象都由一个16字节的GUID(对象标识符,又称“对象ID”)、一个8字节的对象大小和一个可变长的对象数据组成。你只需识别对象后,按对象格式读结构,就能找到所需要的信息。与非音频压缩数据的信息有关的对象主要有:编码译码器列表对象;内容描述符对象(又称“标准标签对象”);扩展内容描述符对象(又称“扩展标签对象”)。而我们自编的程序一般就只要获取或修改后两个对象的信息就行了。 一、一些比较重要的头对象表1 Wma头的数据结构 域名称 数据类型 大小(字节)
--------------------------------
对象ID GUID 16
对象大小 QWORD 8
头对象总数 DWORD 4
保留 BYTE 2
-------------------------------- 说明: 1.对象ID固定为 30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C。此ID是全局性的WmaID。 2.保留字节的编码固定为01 02。 3.头对象总数是指其它所有的子对象,这些子对象也被称为头对象,但我们要弄清之间的关系。 4.本表以及下面各表中的数据类型是按C语言而定的,与VB是有差异的,这一点请注意。 5.对象大小是包括对象ID、对象大小项本身、以及对象数据在内的总长度。而本表的对象大小也可 以看作是数据对象的起始偏移量。 6.本表以及下面各表中的对象大小或长度单位的字节,均为低位在前高位在后。 7.保留字节后面紧接着就是各个头对象了。 表2 文件属性对象的数据结构(共104字节) 域名 数据类型 大小(字节)
---------------------------------------
对象ID GUID 16
对象大小 QWORD 8
文件ID GUID 16
文件大小 QWORD 8
创建日期 QWORD 8
数据包总数 QWORD 8
播放持续时间 QWORD 8
发送持续时间表 QWORD 8
预巻 QWORD 8
Flags DWORD 4
播放标志 1(位)
查找标志 1(位)
保留 30(位)
最小数据包大小 DWORD 4
最大数据包大小 DWORD 4
最大比特率 DWORD 4
--------------------------------------- 说明: 1.对象ID固定为 A1 DC AB 8C 47 A9 CF 11 8E E4 00 C0 0C 20 53 65。 2.每个wma文件的文件ID不相同,但它与本文件数据对象中的文件ID是相同的(见表16),当wma文 件被修改后,这个值也会改变。 3.数据包总数必须与数据对象中的数据包总数相等(见表16)。 4.求总的播放时间时要减去预巻的值。 5.最小数据包大小和最大数据包大小是固定相等的。 表3 流组织对象的数据结构域名 数据类型 大小(字节)
--------------------------------------------
对象ID GUID 16
对象大小 QWORD 8
流类型ID GUID 16
纠错类型 DWORD 4
时间补偿 WORD 2
编码器版本字符数 WORD 2
编码器版本 WCHAR 不定(一般=48)
位速 WCHAR 不定(一般=18)
采样频率 WCHAR 不定(一般=16)
是否立体声 WCHAR 不定(一般=28)
是否固定位率 WCHAR 不定(一般=8)
译码器特定数据大小 WORD 2
译码器特定数据 BYTE 不定(一般=2)
-------------------------------------------- 说明: 1.对象ID固定为 40 52 D1 86 1D 31 D0 11 A3 A4 00 A0 C9 03 48 F6。 2.流类型ID固定为 41 52 D1 86 1D 31 D0 11 A3 A4 00 A0 C9 03 48 F6。 3.WCHAR类型的字符均为Unicode字符。 4.编码器版本字符数×2=实际的编码器版本项所占用的字节数。 5.从编码器版本的字串到是否固定位率的字串,各字串中间并没有特定的分隔符,只是在所有字串 的最后用两个00 00结束。 6.这个结构是笔者根据多个实际的wma文件研究出来的,但不知“流组织对象”这个名称及其包含 的域名称是否正确。 表4 流属性对象的数据结构 域名 数据类型 大小(字节)
--------------------------------------------
对象ID GUID 16
对象大小 QWORD 8
流类型 GUID 16
纠错类型 GUID 16
时间补偿 QWORD 8
特定类型数据长度 DWORD 4
纠错数据长度 DWORD 4
Flags WORD 2
流编号 7(位)
保留 8(位)
加密标志 1(位)
保留 DWORD 4
****以下星号内是特定类型数据****
译码器ID/格式标签 WORD 2
声道数 WORD 2
采样率 DWORD 4
平均每秒字节数 DWORD 4
块对齐 WORD 2
位速 WORD 2
译码器特定数据大小 WORD 2
译码器特定数据 BYTE 不定
********************************
纠错数据 BYTE 不定
-------------------------------------------- 说明: 1.对象ID固定为 91 07 DC B7 B7 A9 CF 11 8E E6 00 C0 0C 20 53 65 2.流类型固定为 40 9E 69 F8 4D 5B CF 11 A8 FD 00 80 5F 5C 44 2B 3.纠错类型固定为 50 CD C3 BF 8F 61 CF 11 8B B2 00 AA 00 B4 E2 20 表5 头扩展对象 域名称 数据类型 大小(字节)
----------------------------------
对象ID GUID 16
对象大小 QWORD 8
保留域1 GUID 16
保留域2 WORD 2
头扩展数据大小 DWORD 4
头扩展数据 BYTE 不定
---------------------------------- 说明: 1.对象ID固定为 B5 03 BF 5F 2E A9 CF 11 8E E3 00 C0 0C 20 53 65 2.保留域1固定为 11 D2 D3 AB BA A9 CF 11 8E E6 00 C0 0C 20 53 65 3.头扩展对象也可以包含子对象。 表6 标准标签对象 顺号 域名称 数据类型 大小(字节)
--------------------------------------
⑴ 对象ID GUID 16
⑵ 对象大小 QWORD 8
⑶ 标题项长度 WORD 2
⑷ 艺术家项长度 WORD 2
⑸ 版权项长度 WORD 2
⑹ 注释项长度 WORD 2
⑺ 比率项长度 WORD 2
⑻ 标题 WCHAR 由⑶确定
⑼ 艺术家 WCHAR 由⑷确定
⑽ 版权 WCHAR 由⑸确定
⑾ 注释 WCHAR 由⑹确定
⑿ 比率 WCHAR 由⑺确定
-------------------------------------- 说明: 1.对象ID固定为 33 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C。 2.WCHAR类型的文本均用Unicode字符表示,每个字符串后面都用00 00结束。 3.标准标签又称“内容描述符”。 表7 扩展标签对象结构 域名称 数据类型 大小(字节)
-------------------------------
对象ID GUID 16
对象大小 QWORD 8
帧总数 WORD 2
帧1 不定
……
帧N 不定
------------------------------- 说明: 1.对象ID固定为:40 A4 D0 D2 07 E3 D2 11 97 F0 00 A0 C9 5E A8 50。 2.帧的结构见表8。 3.扩展标签又称“扩展内容描述符”。
0
4 2796天前
6794
原文链接:http://www.cnblogs.com/zhucl1006/archive/2007/12/19/1006332.html实现方法 :这个程序的实现的方法主要使用WMI的方式,动态的获取WMI中的资料。并计算得出结果显示到界面中。主要使用的WMI的类是:Win32_PerfRawData_Tcpip_NetworkInterface,Win32_NetworkAdapter先通过Win32_NetworkAdapter 获取到计算机中的所有的网络适配器的名称。然后选择不同的名称后,动态的获取底层的资料。这个程序中使用到一个EasyWMI的dll,这个dll中包括了所有WMI的定义。这个可以到codeProject 搜索一下 下载。WMI的功能很强大,几乎所有的计算机上的信息都可以通过这个查到。很方便开发一些性能监控等程式。以后有时间准备写一个使用WMI实现计算机监控管理的程序来。不过最近一直忙着用vc写的一个带UI的exe 的Com的程序。最近一段时间应该是没有什么时间了。对应的控件 :http://www.codeproject.com/Articles/17564/Simple-Performance-Chart
5
0 2821天前