-
Colinux,不是虚拟机,胜似虚拟机
Colinux,不是虚拟机,胜似虚拟机
一些使用记录潘孙友 2010.12.25 于遵义
目录 一、Colinux长什么样? 1.1 文件组成 1.2 运行着的colinux 二、Colinux内外文件访问 三、colinux 网络模式 3.1 slirp 3.2 tuntap 3.3 pcap-bridge/ndis-bridge 四、安装为NT服务 4.1 安装 4.2 卸载服务 五、给colinux中的linux加硬盘 六、图形界面 七、我的ubuntu配置文件 八、在colinux中安装喜欢的发行版
引用自:http://hi.baidu.com/usen68/blog/item/e9a84995569b1043d0135e18.html Colinux (Cooperative Linux)可使在Windows2000/XP上同时运行Linux成为可能并不借助第三方的 虚拟机软件(VMware,VitualPC).它不是一种虚拟机,而是Linux内核的移植,使得Linux 可以 natively 运行在Windows上。Colinux的格言是:如果Linux 可以运行在任何一种体系架构(i386, PowerPC,...)。Linux也应该可以运行在另外一种操作系统上(Windows, Linux,...)
好吧,这篇文章写得非常好,使用方法我就不总结了。请一定要好好读安装目录下的文档,比如colinux-daemon.txt,已经写得灰常灰常详细了,根本不需要上网找使用教程。
以前我也喜欢在自己电脑上装个真实的linux,虚拟不太慢,而且给人一种不真实的感觉。colinux的运行效果非常美,我使用已经有好几个月时间了。
colinux基本上是”绿色”软件(就把它当作是另外一个虚拟机吧)。我是通过7-zip解压colinux的安装程序来获取colinux的文件的,这样可以看清colinux的文件组成,也就是相当于”绿色”版本,一切都自己决定。
最小的colinux自身及可以在内部的运行的linux由三个文件组成即可。
- 1. linux.sys
- colinux通过此驱动与windows交互,以实现在windows上运行linux内核的功能。(有没理解错?)
- 2. colinux-daemon.exe
- colinux主要程序,通过它可以安装linux.sys,通过它来运行linux内核vmlinuz。
- 3. ubuntu.disk
- 最后需要的就是镜像文件了,相当于我们把整个linux系统安装在这一个文件里。这个文件就是我们的linux的“硬盘”,它的大小是多大,linux里看到的磁盘(其实是分区)就是多大。我安装了一个ubuntu,所以取名叫ubuntu.disk,另外我还有zenwalk.disk,slackware.disk和opt_4g.disk,从名字就可以看出是干什么的。
通过coLinux-0.7.8.exe安装的colinux,它主要由以下文件组成:
colinux-console-fltk.exe colinux终端 colinux-console-nt.exe colinux终端 colinux-daemon.exe colinux主程序 colinux-debug-daemon.exe 类似于上面 linux.sys netdriver 此目录主要用来在windows中安装虚拟网卡,也是“绿色”的 1. OemWin2k.inf 2. removeAllNIC.bat 3. tap.cat 4. tap0801co.sys 5. tapcontrol.exe colinux-net-daemon.exe 当以tuntap方式使用网络时需要 colinux-serial-daemon.exe 不知道什么用 colinux-slirp-net-daemon.exe 当使用slirp网络时需要 colinux-ndis-net-daemon.exe ndis-bridge模式需要 colinux-bridged-net-daemon.exe pcap-bridge需要 initrd.gz 安装colinux内linux时需要 vmlinux 这个是colinux提供的linux内核,凡是安装在colinux内的linux都只能统一 使用此内核 vmlinux-modules.tar.gz 与vmlinux相对应的内核模块,在安装好linux后,第一次使用initrd.gz时会 被自动复制到镜像系统中去,和initrd.gz一样只使用一次就可以了。
1.2 运行着的colinux
Colinux实例
像Oracle/DB2/Sybase之类的数据库总喜欢讲“实例”这个词,其实就是存在于系统中一个有完整功能的对象。对colinux来说,就是一台完整的虚拟主机(有CPU,内存,网卡,硬盘,和VMware一样,不过没VMware那样具体)。
我在镜像文件unbunt.disk中安装了个ubuntu,内部ubuntu网络使用slirp方式上网,并且把这个colinux实例安装NT服务,开机自动运行ubuntu。开机后,有两个进程:colinux-daemon.exe和colinux-slirp-net-daemon.exe,通过windows任务管理器查看,内存占用9MB,CPU使用率为0(因为ubuntu跑起来后没多少程序在运行)。
如此之低的资源占用,却可以让我随时可以进入一个完整的真实的纯粹的linux环境,难道colinux还不完美么?
二、Colinux内外文件访问
安装在镜像文件(就是那个好几G大小的文件)里的linux,可以通过如下几种方式与外面的windows互相访问文件系统。
在colinux提供的linux内核中已经默认编译了cofs文件系统的支持。Cofs似乎是一种虚拟文件系统,它可以让colinux的linux把在各colinux实例的配置中配置的windows目录当做磁盘设备,可以通过mount加载上来。
比如我有三个盘符,C/D/E,我在实例ubuntu的配置文件中写了cofs0=c:\ cofs1=d:\ cofs2=e:\,然后我在ubuntu中通过 mount –t cofs 0 /mnt/winc来加载cofs0到目录/mnt/winc (其它两个盘符类似操作),这样就可以自由地在linux读写windows下的文件了。
还可以把mount写入/etc/fstab让linux启动自动加载,实在想不出还有什么比这更方便了。既然colinux里安装的是个linux,又能联网,那安装一些文件传输服务器是自然而然的事情,这里就不多说废话了。
三、colinux 网络模式
如果linux不能联网,那有啥意思。通过colinux运行的linux系统,可以有以下几种连网方式。
先提前说一下,在tuntap和pcap-birdge模式的配置中,网卡的名称很重要,需要和在“控制面板”“网络连接”中看到的一致。
这是最简单的一种,它的原理是在linux内核中提供slirp(好吧,我不知道这是什么东西)驱动,给linux提供一个虚拟出来的仅在linux内部可见的网络接口,网络配置是固化的(见后面的配置文件)。在colinux-daemon.exe运行的同时运行colinux-slirp-net-daemon.exe协同工作,以实现让colinux中访问windows所能访问的网络。
它能让colinux内的linux访问外部网络,从其它主机访问内部linux是受限的,但好在slirp提供了类似于”端口重定向”这样的功能,仅需要在colinux的配置中标识出来就可以用了。
这种方式几乎不需要做什么事情就能让linux与外部主机交互。
以我的ubuntu.conf配置为例:
eth0=slirp,00:ff:78:1b:42:00,tcp:5901:5901/tcp:22:22/tcp:80:80
之后,在linux中配置eth0的网络(如果使用slirp模式,必须这样配置):
iface eth0 inet static address 10.0.2.15 netmask 255.255.255.0 gateway 10.0.2.2 broadcast 10.0.2.255这样就可以在linux中上网了,并且把当前windows的5901/22/80端口都重定向到内部linux上,使得局域网里其它主机也可以访问我的虚拟ubuntu。
这种方式唯一的缺憾就是需要通过端口重定向到当前windows才能访问内部虚拟ubuntu。
3.2 tuntap
这种方式利用微软的网络连接功能(ICS),就是平时我们使用双网卡共享上网的做法,只不过这里的第二张(或者第N张)网卡是虚拟出来的。这种方式也非常简单,在能上网的网卡上选择共享网络连接,然后设置虚拟网卡IP和虚拟机内部linux同网段即可。
比如虚拟网卡(我改名为TAP-Colinux)的IP为192.168.11.1,而内部linux的ip为192.168.11.150,内部ubuntu linux的网关及dns都设置为192.168.11.1,内部就可以上网了。这种模式下,我的windows是可以直接访问内部虚拟主机的,因为它们都在192.168.11网段。但是可惜的是,我局域网中的其它主机是无法连接我们内部ubuntu系统的。
这种方式本也挺好,但我有段时间windows网络共享坏掉了,无法修复,所以也就无法使用不再用它。
eth0=tuntap,"TAP-Colinux",00:ff:78:1b:40:00
这属于桥接模式,需要第三方的软件包wincap的支持。
照理说这是最好的模式,因为它把colinux里的linux置于和当前windows同等的网络地位,像一台真实存在于网络里的主机一样,设置固定IP或者通过DHCP获取IP,直接可以上网。但是,我发现网络里的其它主机(包括我当前的windows)能ping通colinux内的ip,但是却无法连接任何端口。
举例来说,我在ubuntu (10.22.65.138)中开了ssh服务,在外部主机(10.22.65.123)可以ping它,并且telnet 10.22.65.138 22也有反应,但是就是无法收发数据,telnet连接被挂起(照理说应该输出SSH-2.0-OpenSSH_5.5p1 Debian-4ubuntu4字符的),ssh也无法连接。
也许是我忽略了什么,反正这种模式也被我抛弃了。
eth0=pcap-bridge,"本地连接","00:ff:78:1b:41:00"
四、安装为NT服务
我们可以把colinux实例(比如我的ubuntu)安装为windows服务。我写了个批处理:
installUbuntuService.bat
@ set path=%cd%\..\..\bin\;%path% colinux-daemon.exe --install-service ubuntu @%cd%\ubuntu10.10.conf sc config ubuntu depend= "" sc config ubuntu start= auto net start ubuntu pause
说明一下,这里的sc config ubuntu depend是因为默认通过 –install-service安装的服务会有两个依赖项:colinuxDriver和另外一什么东西,但实际上是不需要的。如果是使用“绿色”版colinux,则可能没注册过这些没用的服务,不如把依赖清理掉。
相应的卸载脚本为:
uninstallUbuntuService.bat
@ set path=%cd%\..\..\bin\;%path% net stop ubuntu colinux-daemon.exe --remove-service ubuntu pause
平时我们可以通过net start 服务名和net stop 服务名来启动及关闭我们的“虚拟机”。服务是可以安装多个,可以同时启动(就像VMware里可以同时运行好几台虚拟机),比如我的机器上,还安装了zenwalk、slackware。
五、给colinux中的linux加硬盘
Colinux使用的“硬盘”其实就是普通二进制文件,是无格式的裸文件,在windows xp中,可以通过下面的命令生成文件。
fsutil file createnew c:\disk\ext4_4G.disk 4294967296
比如上面的命令就在c:盘下生成了一个大小为4G的文件。 这里的fsutil命令是xp自带的,与colinux无关。
我们只要在colinux的实例配置中加上
cobd2=C:\disk\ext4_4g.disk
就可以使用cobd2了。当然,在linux中要往这个“分区”中写数据,还得先格式化,并且把它加载上来。
mkfs.ex4 /dev/cobd2 mount –t ext4 /dev/cobd2 /mnt/newDisk
六、图形界面
这本不属于colinux的主题。
既然colinux内跑着一个完全真实的linux系统,那么我们就可以通过ssh连接上去,并且可以把X11数据转发到本地。于是,只要在windows中安装XMing之类的X-Server软件,我们就可以在putty打开的终端中直接启动linux下的图形界面程序了。
详细的配置见这篇文章,非常详细:
http://hi.baidu.com/mooncold/blog/item/8e0dfddc4f29a3a4cd11663a.html/cmtid/0f278f82283e2c9ef603a61a七、我的ubuntu配置文件
#屏幕 cocon=120x40 #内核 kernel=D:\opt\coLinux\dist\ubuntu\boot\vmlinux #initrd=D:\opt\coLinux\dist\ubuntu\boot\initrd.gz root=/dev/cobd0 ro #内存 mem=512 #磁盘 cobd0=D:\opt\coLinux\dist\ubuntu\disk\ubuntu_4G.disk cobd1=D:\opt\coLinux\dist\ubuntu\disk\swap.disk cobd2=C:\disk\opt_4g.disk #网络 eth0=slirp,00:ff:78:1b:42:00,tcp:5901:5901/tcp:22:22/tcp:80:80 #eth1=tuntap,"TAP-Colinux",00:ff:78:1b:40:00 #eth1=pcap-bridge,"本地连接","00:ff:78:1b:41:00" #共享目录 cofs0=c:\ cofs1=d:\ cofs2=e:\
八、在colinux中安装喜欢的发行版
各发行版安装方式相似,简单记录一下(详细的可以另外写篇记录)。这里不限发行版,可以是ubuntu/slackware/zenwalk/fc/debian/suse …
1. 取安装光盘中的initrd文件,名字可能因发行版不同而稍有变化。
2. 在配置文件中加载此initrd,即配置中的initrd=一项
3. 通过cofs,加载windows目录,通过mount –o loop 加载光盘镜像
这之后,就看各发行版的安装步骤了,可以肯定的是都能安装,只是过程会有些痛苦,再说吧。我已经搞定了unbuntu 10.10、slackware 13.0、zenwalk 6.4
over, 暂时记录这么多。
一条评论 -
遵义下雪了 2010/12/24
-
让服务器程序优雅地退出
假设我们的服务器程序提供服务是在主线程外的其它线程(或者子进程)中,主线程仅做些非常简单的事情,它创建服务后就进入休眠状态,不想通过循环sleep忙等,不想被用户打扰(比如被Ctrl+C草率地干掉),又觉得可以让用户友好地不慌不尽快地关闭(还是通过Ctrl+C或者其它信号,但关闭前要做些资源收回、状态保存之类的收尾工作)。
Ctrl+C或者其它信号强制杀掉进程,服务器程序肯定来不及收尾。
当然,这些需求是可以通过让程序成为daemon来实现,但是那样主线程(实际是主进程)就不存在了。
linux下可以这样做:
pthread_mutex_t condition_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t condition_cond = PTHREAD_COND_INITIALIZER; void sigHandle(int sig) { signal(SIGINT, SIG_IGN); printf("要退出咯!\n"); //比如在这里让服务器不慌不忙地停止工作 //可以让main函数继续了 pthread_mutex_lock( &condition_mutex ); pthread_cond_signal( &condition_cond ); pthread_mutex_unlock( &condition_mutex ); } int main(int argc, char**argv) { //拦截信号,当然不止SIGINT一程 //可通过kill -l查看 signal(SIGINT, sigHandle); //其它代码, 比如在其它线程中创建服务器... //停在这里了 pthread_mutex_lock( &condition_mutex ); pthread_cond_wait( &condition_cond, &condition_mutex ); pthread_mutex_unlock( &condition_mutex ); return 0; }windows下可以这样做:
HANDLE hEvent; void sigHandle(int sig) { signal(SIGINT, SIG_IGN); SetEvent(hEvent); } int main(int argc, char*argv[]) { signal(SIGINT, sigHandle); hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); ResetEvent(hEvent); int r = WaitForSingleObject(hEvent, INFINITE); } -
[zz]从”吵架”贴中加深对C++的理解
无意中看到这篇文章:http://www.cppblog.com/converse/archive/2010/07/06/119427.html
以下文字,出自上文评论中名maxime的牛人,此处仅做为学习之用,未经牛人允许,勿怪。C++是一门在工业实践中成长起来的语言,工业界发明这些东西是因为需要,学院派却总跟不上进度,教材几十年一变。要用C++,就要做好准备,否则,你干嘛不用Java或者C#。
1. 关于所谓“频繁的构造/析构开销大”
你首先要清楚“构造”和“析构”中编译器到底为你做了什么。
1.)分配对象空间:如果是在堆中分配对象,那么会有一个代价很大的堆分配(new,在2.7G的CPU上单线程new性能是5M次/秒);如果在堆栈上分配,内存分配代价几乎为零。
2)调用构造函数和析构函数.这有两个开销,一个是调用本身的开销,一个是函数体内部代码的开销,很明显,前者才C++带来的额外开销。我可以告诉你的是,如果是内联,这个开销为0,如果不是内联,这个开销在2.7G的CPU上单线程性能是1200M次/秒,作为类比,2.7G的CPU上单线程可以做400M次32位整型变量写入操作,也就是这个开销比写一个整型变量还小。
现在,看看你说的情况,局部对象的构造和析构,每次的代价比写一个32位整型的变量还小得多,相比每次日志输出至少十几个字节的内存拷贝,这点开销完全可以忽略不计,除非打算每秒中打算做1M次的日志,它带来的代价不占用1%的CPU而已,不过事实是,每秒钟写不了1M次的文件IO。
最后从设计的角度考虑这个问题,你的系统打算每秒中写多少次日志,应该心理有数吧,从这个意义上,从设计的角度,上面我写的那些分析毫无必要,只是为了加深对C++的理解,事实是,即便“频繁的构造/析构开销大”很大,它们仍然不是系统的真正瓶颈,没必要过早优化。如果它们真成了瓶颈,你应该做的事情是,调整成合理的日志策略。2.所谓“比如log << "hello " << "world",是无法判断到底在输出"hello"还是"world"的时候上面的参数输入已经结束了”
其实,这个问题,流的设计者早已考虑到了,std::endl就是用来干这件事情的。事实上,自定义的流操控符,还可以干很多事情比如:std::cout << v1 << mylock(v2) << v2 << myunlock(v2);
上面的mylock,myunlock就是自定义的操作符,用来给v2加锁解锁,而不输出任何字符。它到底能做什么,取决于你的想象力。我总爱把C++比作机械行业的钳工,他们比不上机器的速度,但没他们不行,很多事情机器做不了。使用正确的工具做正确的事情,如果你感觉不对,先想想选对工具没,而不是抱怨工具很烂。
额外,说明一点,有人告诉你sprintf存在写错的可能性,所以,你可以说,如果别人忘了写上他的endl怎么办?
我来告诉你吧,写错了其实没什么大不了的,问题关键是,写错了会带来什么危害。sprintf写错了,可能带来的是内存溢出覆盖,这才是我们恐惧他的原因,一个内存溢出带来的危害我就不说了。 反之,少写了一个endl,最多就是两行日志重叠,或者一个日志输出时间晚了一会儿。如果你真看到这个情况,把endl加上去就行了。
不知道现在是否能理解了,不要害怕bug,不要害怕写错,要怕会让你掉进深渊的bug。我得承认,这是C/C++的弱点,java/C#相对好很多。
C++最害怕的,就是指针操作,内存覆盖可以毁掉整个程序的运行基础,却不容易找到错误的代码。但这也是C++的优点,C++为什么要用流替换C的sprintf,就是要减少内存覆盖错误的机会。当然,C++中仍然有这种错误的机会,因为抛弃了指针,C++和Java就没区别了。如果说C是做操作系统的,java是做应用的,C++就是做系统和应用结合部的,只有理解了这点,你才能用好C++,而不是抱怨,它既没C简单,也没java安全。
事实是,C++就是这么个怪胎,比Java更快,比C更安全更有开发效率。3. 关于“要使用这门语言写出正确的程序来,需要了解底下多少的细节呢?!”
首先答案是,不需要知道细节,只需要知道“规范”。C++真正的问题不是太复杂,而是在实践中缺乏规范,尤其在中国的软件作坊里面。就像你会开汽车一样的,你没比要知道汽车发动机原理,同样能把汽车开好。因为你遵守了开汽车的规范,比如启动的时候,慢加油门。
很多人的问题在于,在思想上,忽视了规范,到头来却怪东西太复杂。
其次是了解细节,可以工作更深入。再说了,就算复杂,C++能有多复杂,一个C++语言里面能有多少东西呢?相比一个Java库,这点东西真算不了什么。很多人掌握不好,是因为没有正正经经的机会去学,去练。这点像数学,学的时候比较枯燥,不管怎么说,这点东西就叫复杂,那只能说,做的应用系统太简单。4. 关于“假如需要考虑多线程的话,那么一次输入有多个函数函数中被调用”
要在多线程进行IO操作,肯定是要用锁的,就算你不直接用,系统API的流API,比如Win32的WriteFile,也是要用的。
所以,答案很简单,用锁。问题不在于有几次函数调用,而在于能否让这几次函数调用位于同一个锁当中。
传统上,一个sprinf,你可以加一次锁,就够了。 而现在呢,分成了好几次调用,那么就在这几次调用之间和之后加锁就行了,在本例中,也就是那个被认为过于调用繁琐的临时对象了,在它的构造函数加锁,在它的析构函数中解锁,就能保证输出的原子性。如果这样还不满意,还可以考虑流操控符加锁,不过有点危险。
不过呢,说道最后,如果你明白,那个看似效率低下的临时对象其实对整行的输出做了缓存,所以在glog中,临时对象中是没必要用锁的,因为临时对象中保存的字串是不会被多线程打断的,它能够保证所有的“<<”调用在输出上的原子性。最后析构函数中,真正进行输出时,在下层的实际输出位置,实际上是有锁。5. 最后谈一下,C++流的真正缺点?
从安全性的角度讲,C++流相对sprintf是一次飞跃。从实际项目来看,C++程序员的代码产出和维护量,通常会数倍甚至几十倍于C程序员,这表面了在某些问题域上,C++比更有开发效率。
但由此带来的问题是,在代码量少的时候,C程序员可以花时间慢慢检查代码,保证sprintf没问题。而C++程序员再这样做效率就太低了。所以才会有了C++流的方案,C++流设计者正是从实践中品尝到了sprintf的苦果。
事实是,C++语法形式,从实用性角度,的确很蹩脚。而且性能只有sprintf的1/3.不过实际环境下,性能通常不是问题,流输出很少会是一个应用系统真正的瓶颈。
蹩脚的语法,是个问题,尤其当你需要做格式控制的时候,代码可能非常长。这个问题,我的看法是,写的时候可能多花点时间,不过以后维护起来就轻松了。毕竟,我宁愿选择安全性,花三天时间去找一个缓冲区溢出是不会宁人愉悦的。当你认为语法问题很重要时,通常暗示代码管理上有问题。我通常认为代码的书写只占20%的时间,80%时间是在维护代码。维护效率远比书写效率重要。
在C++领域,新发明似乎是没有止境的,有一个新的,利用重载“()”操作符的格式化库出现了,具体我本人没有用过,看起来还不错,据说在性能上优于sprintf,在安全性上不输于C++流,在格式上类似sprintf。由于缺乏大规模应用,实际情况如何,还不好说。
就我本人而言,我认为C++流的效率和格式问题,并非致命问题,所以也就不急着使用更先进的东西了,短期内我C++流仍是最好的格式化输出工具。除非,项目主要业务逻辑就是格式化字符串,那也许我会选择sprintf或者其他的东西。
最后,我感觉楼主,似乎想在一个输出语句中,输出很长很长的,可能跨越多次物理输出的内容。
这样做,首先代码不易理解,不易修改维护。 根据本人的实际经验来看,日志输出最好还是按实际物理行为单位比较好,所以glog没有支持所谓endl特性。
楼主可能真正担心的是另一个问题,在多线程程环境下,想要连续输出的几行文本,会被其他线程打断,以致阅读性变差。对此,我建议,如果不希望被打断,使用glog那就需要八几行输出写在一个glog句子,作为一次原子输出就行了。但是,如果楼主对这样的原子输出,还要求再被分成多次物理输出,那这是为什么呢?有这个必要吗?既然打算连续输出几行,且在一个语句之中,整个语句时间是非常快的,对观察者而言,一次原子输出是由一次物理输出还是多次物理输出构成,没有任何实际意义。 -
好吧,我的脚开始痛了
