Archive for文档及资源

gSOAP学习笔记

gSOAP学习笔记

潘孙友 2010-12-27 于遵义

目录
一、基本概念
  1.1 关于SOAP
  1.2 关于gSOAP
  1.3 gSOAP编译器(命令行工具)
    1.3.1 wsdl2h
    1.3.2 socapcpp2
二、gSOAP开发:Web Service服务端
三、gSOAP开发:Web Service客户端
四、参考资料

一、基本概念

1.1 关于SOAP

SOAP(Simple Object Access Protocol),即简单对象访问协议,是在分布式的环境中交换数据的简单协议,以XML作为数据传送语言。
SOAP有两种工作模式,一种是RPC(Remote Procedure Call),另一种是Message-Oriented。MO可以利用XML来交换结构更复杂的数据。RPC模式的SOAP可以理解为这样一个开发协议:SOAP=RPC+HTTP+XML,具有以下特点:

  • 采用HTTP作为通信协议,采用客户/服务模式;
  • RPC作为统一的远程方法调用途径;
  • 传送的数据使用XML格式。

看一个简单的请求及回复SOAP数据(真实数据):

POST /wpsoap/ HTTP/1.1
Host: 127.0.0.1:10240
User-Agent: gSOAP/2.7
Content-Type: text/xml; charset=utf-8; action=""
Content-Length: 480
Connection: close
SOAPAction: ""

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://www.example.org/wpsoap/" xmlns:ns2="urn:nszfpt"><SOAP-ENV:Body><ns2:login><req><username>admin</username><password>3.14159</password></req></ns2:login></SOAP-ENV:Body></SOAP-ENV:Envelope>
HTTP/1.1 200 OK
Server: gSOAP/2.7
Content-Type: text/xml; charset=utf-8; action=""
Content-Length: 555
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wpsoap="urn:nszfpt"><SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><wpsoap:tagRspLogin><rsp><retCode>0</retCode><retMessage>login ok!</retMessage></rsp><session>01234567890</session></wpsoap:tagRspLogin></SOAP-ENV:Body></SOAP-ENV:Envelope>

这东西非常的复杂,我仅仅记录一下使用到的部分。

1.2 关于gSOAP

引用:http://blog.csdn.net/darkone/archive/2006/12/14/1442525.aspx
gSOAP编译工具提供了一个SOAP/XML 关于C/C++ 语言的实现,
从而让C/C++语言开发web服务或客户端程序的工作变得轻松
了很多。绝大多数的C++web服务工具包提供一组API函数类库
来处理特定的SOAP数据结构,这样就使得用户必须改变程序
结构来适应相关的类库。与之相反,gSOAP利用编译器技术提
供了一组透明化的SOAP API,并将与开发无关的SOAP实现细节
相关的内容对用户隐藏起来。gSOAP的编译器能够自动的将用
户定义的本地化的C或C++数据类型转变为符合XML语法的数据
结构,反之亦然。这样,只用一组简单的API就将用户从SOAP
细节实现工作中解脱了出来,可以专注与应用程序逻辑的实
现工作了。gSOAP编译器可以集成C/C++和Fortran代码(通过
一个Fortran到C的接口),嵌入式系统,其他SOAP程序提供
的实时软件的资源和信息;可以跨越多个操作系统,语言环
境以及在防火墙后的不同组织。
	gSOAP使编写web服务的工作最小化了。gSOAP编译器生成
SOAP的代码来序列化或反序列化C/C++的数据结构。gSOAP包
含一个WSDL生成器,用它来为你的web服务生成web服务的解
释。gSOAP的解释器及导入器可以使用户不需要分析web服务
的细节就可以实现一个客户端或服务端程序。

照我理解,gSOAP可以为我们生成soap服务器端+客户端代码的框架,我们只需实现具体的接口函数即可。而生成代码的工具就是上面文中提到的“gSOAP编译器”。

1.3 gSOAP编译器(命令行工具)

1.3.1 wsdl2h

此工具用来从WSDL文件生成c/c++头文件。

wsdl2h -o 头文件名 WSDL文件名或URL
常用的其它参数:
-o 文件名,指定输出头文件
-n 名空间前缀 代替默认的ns
-c 产生纯C代码,否则是C++代码
-s 不要使用STL代码
-t 文件名,指定type map文件,默认为typemap.dat
-e 禁止为enum成员加上名空间前缀

1.3.2 socapcpp2

此工具用来从头文件,生成SOAP服务器及客户端代码,还包括WSDL、测试用XML数据。

soapcpp2 头文件
常用选项
-C 仅生成客户端代码
-S 仅生成服务器端代码
-L 不要产生soapClientLib.c和soapServerLib.c文件
-c 产生纯C代码,否则是C++代码(与头文件有关)
-I 指定import路径(见上文)
-x 不要产生XML示例文件
-i 生成C++包装,客户端为xxxxProxy.h(.cpp),服务器端为xxxxService.h(.cpp)。

二、gSOAP开发:Web Service服务端

开发服务器程序,需使用gSOAP生成服务器端代码框架。我们有两种做法:

  1. 编写WSDL,使用wsdl2h生成头文件,再soapcpp2生成框架代码;
  2. 编写头文件,使用soapcpp2生成框架代码;

这两种方式,结果是一样的,最终都有产生头文件,并生成代码。不同在于,在项目的开发中需要维护的文件不同,前者是需要维护WSDL文件,后者维护头文件。

我个人觉得第二种方式更好用,不仅仅是少了个步骤,而是WSDL的语法太难写了,有点XSD的味道。而头文件的编写,更接近于程序员的思考方式,比如定义消息结构,定义接口名称等。

gSOAP是非常智能的,它利用C/C++的注释来获取信息,所以在手工编写的头文件中,注释是用用处的,常以// gsoap 名字空间 …开头。做为学习,我准备为php blog程序wordpress写一个web service接口,名字叫wpsoap。

我开始写头文件(wpSoap.h)了,出于学习目的,我仅实现了两个接口:一是用户登陆;一是日志发布。

/**
 * @file wpsoap.h
 * @brief 为wordpress2.7提供web service接口
 *
 *  "//gsoap"开头行,请勿删除.
 *
 *  1. 通过此文件生成WSDL 及 服务端代码
 *
 *    >mkdir -p srvSrcFromH
 *    >cd srvSrcFromH
 *    >soapcpp2 -L -S "wpsoap.h" -I /path/to/gsoap-2.8/gsoap/import/
 *
 *  2. 通过WSDL生成客户端代码
 *
 *    >mkdir -p clientSrcFromWSDL
 *    >cd clientSrcFromWSDL
 *    >wsdl2h.exe  -o wpsoap.h ../srvSrcFromH/wpsoap.wsdl -I /path/to/gsoap-2.8/gsoap/import/
 *    >soapcpp2 -L -C wpsoap.h -I /path/to/gsoap-2.8/gsoap/import/
 *
 * @author pansunyou@gmail.com
 * @version 1.0
 * @date 2010-12-27
*/

//gsoap wpsoap service name: wpsoap
//gsoap wpsoap service namespace: http://www.example.org/wpsoap/
//gsoap wpsoap service location: http://192.168.0.187:10240/wpsoap/
//gsoap wpsoap service encoding: encoded
//gsoap wpsoap schema namespace: urn:nszfpt

#import "stlvector.h"

//通用回复
class wpsoap__tagCommResponse
{
       int                  retCode                 ;      //回复码
       std::string retMessage           ;      //回复消息
};

//[请求]用户登陆
class wpsoap__tagReqLogin
{
    std::string username              ;      //用户名
    std::string password        ;      //密码名文
};

//[答复]用户登陆
class wpsoap__tagRspLogin
{
    wpsoap__tagCommResponse rsp    ;      //通用回复
       std::string session                 ;      //会话标识
};

//[接口]登陆接口
int wpsoap__login(wpsoap__tagReqLogin req, wpsoap__tagRspLogin& rsp);

//[请求]发布日志
class wpsoap__tagReqPost
{
    std::string title         ;      //标题
    std::string body              ;      //正文
};

//[答复]发布日志
class wpsoap__tagRspPost
{
    wpsoap__tagCommResponse rsp    ;      //通用回复
};

//[接口]发布日志接口
int wpsoap__post(wpsoap__tagReqPost req, wpsoap__tagRspPost& rsp);

在接口中,我使用到了自定义的消息结构wp_soap_tag*,这里的wpsoap__前缀是必须的,这样soapcpp2才能为我们生成正确的代码。

之后,我使用soapcpp2生成服务端代码框架:

@echo off
@set path=%cd%\..\..\contrib\gsoap-2.8\gsoap\bin\win32\;%path%

mkdir srvSrcFromH 2>nul
cd srvSrcFromH
soapcpp2.exe -L -S ..\res\wpSoap.h -I ..\..\..\contrib\gsoap-2.8\gsoap\import\
pause

要编译出服务程序,有这些代码还不够,还需要自己写两个文件,一个用来写main函数,一个用来写wpsoap的接口函数(当然可以放在一个文件里)。最终我的服务器程序有以下文件:(另外,还需要gsoap目录下的stdsoap2.cpp,因为我把它编译为静态库了,所以这里没列出来。)

D:\wpSoapServer
|   makeSrc.bat
|   wpsoapimpl.cpp                //这里实现了soapStub.h给出的接口
|   wpsoapsrv.cpp                  //这里是main函数开始的地方
+---res
|       wpSoap.h
\---srvSrcFromH
        soapC.cpp
        soapH.h
        soapServer.cpp
        soapStub.h
        soapwpsoapObject.h
        wpsoap.login.req.xml
        wpsoap.login.res.xml
        wpsoap.nsmap
        wpsoap.post.req.xml
        wpsoap.post.res.xml
        wpsoap.wsdl
        wpsoap.xsd

每次我修改了res/wpSoap.h后,我就运行一下makeSrc.bat,自动重新生成srvSrcFromH目录里的所有东西,并且这个目录里的所有代码是不需要手工维护的(除非有特殊需要)。

在服务器代码中,我仅实现了以下两个函数(wpsoapimpl.cpp):

int wpsoap__login(struct soap*, wpsoap__tagReqLogin req, wpsoap__tagRspLogin &rsp);
int wpsoap__post(struct soap*, wpsoap__tagReqPost req, wpsoap__tagRspPost &rsp);

wpsoapsrv.cpp里的代码仅仅是调用gSOAP产生的代码来建立socket服务器,基本不需维护。gSOAP是线程安全的,可以将请求分配到线程池内实现高效服务,但我仅为了走通gSOAP的使用流程,没有这样使用。

具体做法可以参考:http://www.cs.fsu.edu/~engelen/soapdoc2.html

三、gSOAP开发:Web Service客户端

客户端代码本来也是可以通过为服务端编写的头文件生成的,但是为了真实一点,假设我无法获取服务器开发时使用的头文件,仅仅有个公开的WSDL文件,就是上面产生的srvSrcFromH /wpsoap.wsdl。

我用这个脚本来生成客户端框架代码:

@echo off
@set path=%cd%\..\..\contrib\gsoap-2.8\gsoap\bin\win32\;%path%

mkdir clientSrcFromWSDL 2>nul
cd clientSrcFromWSDL
wsdl2h.exe -o wpsoap.h ..\..\wpSoapServer\srvSrcFromH\wpsoap.wsdl
soapcpp2.exe -L -C wpsoap.h -I ..\..\..\contrib\gsoap-2.8\gsoap\import\
pause

加上我测试用的代码wpsoapclient.cpp,以及gosap目录里的stdsoap2.cpp,我有了如下文件:

D:\wpSoapClient
|   makeSrc.bat
|   wpsoapclient.cpp
\---clientSrcFromWSDL
        soapC.cpp
        soapClient.cpp
        soapH.h
        soapStub.h
        soapwpsoapProxy.h
        wpsoap.h
        wpsoap.login.req.xml
        wpsoap.login.res.xml
        wpsoap.nsmap
        wpsoap.post.req.xml
        wpsoap.post.res.xml

客户端代码非常少(仅仅是实现,容错之类的都未考虑):

/**
 * @file wpsoapclient.cpp
 * @brief 访问wpsoap服务
 *
 * 调用wpsoap的客户端示例代码
 *
 * @author pansunyou@gmail.com
 * @version 1.0
 * @date 2010-12-27
*/

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstdlib>
#include <string>
#include "clientSrcFromWSDL/soapStub.h"
#include "clientSrcFromWSDL/soapwpsoapProxy.h"
#include "clientSrcFromWSDL/wpsoap.nsmap"

using namespace std;

int main(int argc, char*argv[])
{
  wpsoap wpsoapClient;
  if (argc==2)
    wpsoapClient.endpoint = argv[1];

  //1. 登陆
  string username = "admin";
  string password = "3.14159";
  int r = 0;

  ns2__tagReqLogin req;
  req.username = username;
  req.password = password;
  _ns2__login ns2__login;
  ns2__login.req = &req;
  _ns2__tagRspLogin rsp;
  r = wpsoapClient.__ns1__login(&ns2__login, &rsp);
  if (r!=0)
  {
    fprintf(stderr, "调用soap接口失败!\n");
    return -1;
  }

  if (0!=rsp.rsp->retCode)
  {
    printf("登陆失败 retCode=%d, retMessage=%s\n",
		rsp.rsp->retCode,
		rsp.rsp->retMessage.c_str());
    return -1;
  }
  printf("登陆成功! [session=%s]\n",
	rsp.session.c_str());

  ns2__tagReqPost reqPost;
  reqPost.body = "post article by wpsoap!";
  reqPost.title = "hello, wpsoap!";

  _ns2__post ns2__post;
  ns2__post.req = &reqPost;
  _ns2__tagRspPost ns2__tagRspPost;
  r = wpsoapClient.__ns1__post(&ns2__post,
	&ns2__tagRspPost);
  if (r!=0)
  {
    fprintf(stderr, "调用soap接口失败!\n");
    return -1;
  }

  if (0!=rsp.rsp->retCode)
  {
    printf("发布日志失败 retCode=%d,
		retMessage=%s\n",
		rsp.rsp->retCode,
		rsp.rsp->retMessage.c_str());
    return -1;
  }
  printf("日志发布成功! [retMessage=%s]\n",
  rsp.rsp->retMessage.c_str());

  return 0;
}

四、参考资料

http://gsoap2.sourceforge.net/
http://www.cppprog.com/2009/0723/138.html

http://hi.baidu.com/winnyang/blog/item/d5fd4f3df38f35cd9e3d625b.html

http://www.cs.fsu.edu/~engelen/soap.html
http://tangentsoft.net/mysql++/

Comments (3)

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长什么样?

1.1 文件组成

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互相访问文件系统。

2.1. cofs

在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启动自动加载,实在想不出还有什么比这更方便了。

2.2. sftp/winscp/ftp/samba

既然colinux里安装的是个linux,又能联网,那安装一些文件传输服务器是自然而然的事情,这里就不多说废话了。

三、colinux 网络模式

如果linux不能联网,那有啥意思。通过colinux运行的linux系统,可以有以下几种连网方式。

先提前说一下,在tuntap和pcap-birdge模式的配置中,网卡的名称很重要,需要和在“控制面板”“网络连接”中看到的一致。

3.1 slirp

这是最简单的一种,它的原理是在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

3.3 pcap-bridge/ndis-bridge

这属于桥接模式,需要第三方的软件包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服务

4.1 安装

我们可以把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,则可能没注册过这些没用的服务,不如把依赖清理掉。

4.2 卸载服务

相应的卸载脚本为:

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, 暂时记录这么多。

Comments (1)

spserver代码阅读笔记

从这里可以下载doc/pdf版:spserver代码阅读.pdf

http://code.google.com/p/spserver/

引用:http://iunknown.javaeye.com/blog/59804
spserver 是一个实现了半同步/半异步(Half-Sync/Half-Async)和领导者/追随者(Leader/Follower) 模式的服务器框架,能够简化 TCP server 的开发工作。
spserver 使用 c++ 实现,目前实现了以下功能:

  • 封装了 TCP server 中接受连接的功能
  • 使用非阻塞型I/O和事件驱动模型,由主线程负责处理所有 TCP 连接上的数据读取和发送,因此连接数不受线程数的限制
  • 主线程读取到的数据放入队列,由一个线程池处理实际的业务
  • 一个 http 服务器框架,即嵌入式 web 服务器(请参考: SPWebServer:一个基于 SPServer 的 web 服务器框架)

目录

  1. Leader/Follower 模型
  2. Dispatcher模型
  3. Hahs半同步半异步模型
  4. 代码编写

一、Leader/Follower 模型

一切从类SP_LFServer的构造函数开始。如果SP_LFServer是在主线程中实例化的,那就从主线程讲起。

以[M]代表主线程[MainThread],
[M]建立的线程池中的线程[ChildThread][C]

  1. [M]SP_IOUtils::tcpListen初始化监听socket
    • [M]创建socket listenFD
    • [M]bind listenFD到本地某端口
    • [M]listen在listenFD上
  2. [M]初始化libevent事件基
  3. [M]把listenFD的读事件绑在事件基上,回调函数是SP_EventCallback::onAccept
  4. [M]建立线程池,每个线程都跑去执行SP_LFServer ::lfHandler [C]阻塞在这里
    • [C]一旦有线连接进来,某个[C]在SP_LFServer ::handleOneEvent抢到全局锁,跑去执行一次event_base_loop,也就是执行了SP_EventCallback::onAccept把新连接接进门来。
      • [C]SP_EventCallback::onAccept中,主要是把当前连接放入会话管理器,并为新连接创建SP_Session对象,然后setHandler及setIOChannel,注册连接的读写到SP_LFServer的事件基,并宣告”此连接已经可以读写,某个[C]来处理读写事件吧”。
      • 再就是调用事务的初始化函数(由具体的Handler实现):doStart
    • [C]或者是有数据要收发,那些阻塞在SP_LFServer :: lfHandler -> SP_LFServer :: handleOneEvent中event_base_loop的[C],会被激活并调用相应的读写回调,接收数据或者向连接写数据。
    • [C]或者是有任务要处理,那些阻塞在SP_LFServer :: lfHandler -> SP_LFServer :: handleOneEvent中InputResultQueue->pop的[C],会被激活并取得这个任务。
  5. [M]做完这些事情,主线程自己就睡觉去了(以后再也不干事了) [M]阻塞在这里

此种模式中,实际的数据收发,是由某个最早抢到全局锁mMutex的[C]来做的,它不仅把新连接通过SP_EventCallback::onAccept接进来,也同时在event_base_loop中把其它事件(如果有)也一同处理了,直到某个事件向任务队列InputResultQueue塞了任务(这任务通常是接收了足够多的数据或者其它事件导致的)。

一旦这个[C]接到任务,它就跑去干正经活去,数据收发的事情交由下一个苦力接手,这就要看线程池中哪个线程抢到了,应该是不确定的。干完正经活的线程回到线程池里,跟其它人抢mMutex。

反正几乎每个[C]都会经历:抢mMutext,处理libevent事件(收发数据当然在这里)或者接到任务。

二、Dispatcher模型

以[M]代表主线程[MainThread],以[D]代表[M]创建的[DispatcherThread]线程

  1. [M]SP_IOUtils::tcpListen初始化监听socket
    • [M]创建socket listenFD
    • [M]bind listenFD到本地某端口
    • [M]listen在listenFD上
  2. [M]SP_Dispatcher:: SP_Dispatcher 初始化
    • [M]创建libevent事件基
    • [M]创建阻塞队列,存放连接
    • [M]创建新线程[DispatcherThread]
    • [D]创建两个线程池
      • [D]workerExecutor池中有较多线程,用于执行实际事务
      • [D]actExecutor池中线程较小,用于处理收尾事件
    • [D]进入event_base_loop (DispatcherThread阻塞在这里)
      • [D]有新事件发生,workerExecutor执行,actExecutor收尾
  3. [M]在循环中accept ([M]阻塞在这里)
    • 有新连接进来,激活了[M],空闲,推入阻塞连接队列
      • SP_IOUtils::setNonblock设置连接为非阻塞型
      • 触发onPush事件,激活了[D]
      • [D]为连接设置事务处理对象setHandler
      • [D]为连接初始化数据渠道(ssl/raw/ encrypted)setIOChannel
      • [D]将连接之读写事件加入Dispatcher的事件基中进行监听
        • SP_EventCallback::onRead处理读数据
        • SP_EventCallback::onWrite处理写数据
      • [D]开始调用事务处理的doStart或仅激发可读写可写消息
    • 系统忙,超过连接数,往连接里写” System busy, try again later”,断开连接

所有进来的连接,都是先经[M]Accept的,因为Accept后直接抛入连接队列,所以Accept可以很快进行,不管当前有多少连接都会非常及时响应。

待[D]开始监听新连接的读写事件后,数据的收发都是由[D]自已负责,这是在2.e步骤行的。

一旦读写完(或者处理完其它信号或者事件),就去看看任务队列InputResultQueue中有无需要处理的事件(比如在读写阶段,读完一段数据如果符合条件,就会被组成一个任务扔到任务任务队列中)。当然,[D]不会事必躬亲,而是把任务取出来扔给workerExecutor线程池。

然后,[D]会去看任务执行结果队列OutputResultQueue,这里的元素是由workerExecutor中的某线程在执行事务的时候产生的,即执行完一个任务就把任务打包放到结果队列。[D]从结果队列取出来,扔给actExecutor线程池,由它去收尾。其实一般情况下只是做些释放内存之类的工作,或者统计一下成功执行了多少任务(请求)。

三、Hahs半同步半异步模型

以[M]代表主线程[MainThread]

一切从类SP_Server::start讲起

  1. [M]SP_IOUtils::tcpListen初始化监听socket
    • [M]创建socket listenFD
    • [M]bind listenFD到本地某端口
    • [M]listen在listenFD上
  2. [M]通过SP_EventArg建立libevent事件基
  3. [M]把listenFD的读事件绑在事件基上,回调函数是SP_EventCallback::onAccept
  4. [M]建立大线程池workerExecutor和小线程池actExecutor,这些池中的线程都是阻塞在判断队列中是否有元素的函数上
  5. [M]进入libevent事件处理循环:event_base_loop [M]阻塞在这里
    • 直到有事件发生,比如新连接进来,[M]调用onAccept去迎接新连接,并将其读写事件注册到事件基上
    • 处理完事件后,去任务队列中看看有无要处理的任务(InputResultQueue),有的话提出来扔给大线程池workerExecutor,由池中的线程去干实际的活
    • 然后看看有无处理完的任务(OutputResultQueue),有的话提出来扔给小线程池actExecutor

这个模型里,所有数据读写及其它libevent事件处理都由实例化SP_Serverr 的线程来做的,如果是文件传送这样的应用,此线程会很忙。

我猜想,名字中的同步是否是指实际的事务处理是同步的,比如流程一直都是接收数据,处理数据(比如处理的时候可以很长时间),返回数据这么个固定的顺序;而实际数据的收发,在事务处理时不需要关心,只要认为数据已经发出去就好了,至于真正是在什么时候发给客户端的,事务处理函数管不着,这种不等待数据真正地外发做法是否就是异步呢?

四、代码编写

每个连接开始都是可读又可写的,根据要实现的功能的不同,可以由Client/Server任一方先出招。所有的交流总是会有某方主动的,像http服务,总是会由客户端先行发个请求,然后服务器回应。

在代码编写的时候,一般只需要实现这么几个地方:

  1. SP_MsgDecoder子类的decode
  2. SP_Handler子类的handle/start/error/timeout

SP_MsgDecoder::decode在每次接收完数据的时候被调用,返回值代表了是不是已经收到一个完整的数据包了,如果是则必须返回eOK让接受数据的函数组个任务放到任务队列,让线程池中的某位[C]来调用SP_Handler::
handle。如果还只是不完整的数据包,那就返回eMoreData,告诉接收函数我还没吃够,继续喂我吧。

这其实会有个小问题,如果我们的逻辑数据包太大,内存会占用较多,效率不高。并且这样的处理方式在需要连接接收大量数据的地方不太实用,比如像接收客户端传送的大文件。有人会说,像传文件的时候,可以设置让decode一直返回eOK嘛,这确实是可行的,但是decode函数还是会被调用N次,这个调用还是挺耗资源的。每接收一小片数据,都会去调用一下decode+handle,还有个深层次的问题是这里的decode+handle都是父类虚函数的实现,效率就更低了。

每个东西都会有它适合的应用场合,像以上的模式更适应像http或者telnet这种交互性较多,但每次传递数据较少的应用。如果是做ftp文件传送之类,还是考虑其它模型吧。

不过我倒还真是用它来实现过一个文件服务器,文件内容传送是被分片打包进自定义的数据包的,和其它命令混合着传送到服务器,服务端一片片地将文件内容写入目标文件。由于文件碎片数据包中包含了足够的信息,所以这样断断续续地写也是可以传文件的。传输速度由于只是测试过单个客户端连接的情况,所以也就没什么参考意义。

评论

Toad for IBM DB2 FREEWARE

最近要接触Oracle/DB2数据库,试了几个图形界面客户端,这个算是最好用的。

下载地址: 免费版也超级强大

评论

linux下找出usb网卡的驱动

ubuntu 10.10对TP-LINK TL-WN721N的支持很好,一插上就找到网络了。同事说想看看对应的驱动源码,问我知不知道怎么找出是加载了哪个驱动。

lsmod 可以列出以模块方式加载的内核模块,如果编译内核的时候选择了Y(内嵌方式)则看不到的。
lsusb 可以列出当前计算机上已连接的USB设备的信息,像产家编号,型号编号什么的。
/lib/modules/2.6.***/modules.alias 文件包含了硬件编号与模块名的对应关系,即系统根据编号(我们在lsusb中看到的)来确定加载正确的模块。

比如TP-LINK TL-WN721N相应的编码是CF03 9721,在modules.alias中可以找到相似的字符串,其后即是驱动名ath9k_htc。
如果不相信这就是驱动,可以通过rmmod ath9k_htc卸载看看网卡还能不能用。

评论