2007年5月3日
#
曾几何时在linux编c语言的时候就会碰到数据库连接的难题,虽然用ODBC可以解决一些问题,但最新的数据库支持必须用JDBC或专用接口才行,而且如ORACLE这种数据库,要想实现远程连接的话,必须安装客户端,对软件的发行产生了一定难度。而JDBC就没有这问题,只要有相关的JDBC驱动就可以正常使用,对软件的成本控制起了一定的积极作用。它很像网络中的桥接器的功能,所以我管它叫JDBC桥接器。
ICE的出现使得这个问题得到了简化,至少不用去关心网络控制和客户端的程序实现语言,只要服务端与客户端用的都是ICE的协议,这个问题就很好解决。下面就这个问题的实现做进一步的讨论。
这个JDBC桥接器的作用是:接受各种数据请求,并通过相应的JDBC数据库驱动连接数据库,并把请求结果返回到客户端。不管这个客户端是在本地还是在网络中,数据库在本地还是在网络中,都可能实现数据的透明传输与应用。
首先我们要做的是,必须在JDBC桥接器所在的机器上开放一个端口,用来接受服务,客户端利用ICE协议向服务端发送请求,并取回操作结果。
有人说,你用的着这么麻烦嘛?用JAVA直接开发客户端不就行了吗?
这个想法应该在很多人心中存在,一个JAVA应用程序的安装也是很烦琐,除非你是BS结构的。这种只能用在JAVA语言身上,但如果我用c/c++开发了一个客户端,只是想用jdbc来操作数据库的话,上面的想法就没有可能实现。并且在跨平台和操作系统的的环境中开发客户端和服务端是一件头痛的事情。
有人说,你要是使用WebService不也可能达到这样的效果吗?请看<<网络服务平台的比较----ICE应用系列文章之一>>,在whhif.cublog.cn可以找到。
在以上环境中,ICE可以避免以上这种种问题。
首先要开发一个slice脚本来定义服务。
module jdbcAgent
{
["java:type:java.util.ArrayList"] sequence <string> row;
["java:type:java.util.ArrayList"] sequence <row> table;
interface Operator
{
int connectDB(string driver,string disp,string host,string port,string db,string name,string pass);
bool insertSQL(string sql);
bool updateSQL(string sql);
bool deleteSQL(string sql);
table querySQL(string sql);
bool closeDB();
};
};
在windows下利用slice2java.exe jdbcAgent.ice生成服务。Linux下利用slice2java jdbcAgent.ice来生成服务。
定义服务的具体内容:
下面的函数与jdbcAgent.ice中所描述的服务是一样的,只是这里给出的是具体实现。只是几个数据库连接的常用功能,编缉ICE所生成的JAVA代码,最好使用eclipse,很方便。并没有定义异常。如果要了解具体实现意义,最好参考ICE的中文白皮书和我写的上一篇入门文章《一个简单的聊天室的实现----ICE应用系列文章之四》,在http://whhif.cublog.cn可以找到。
package jdbcProxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import Ice.*;
import jdbcProxy.jdbcAgent.*;
public class jdbcAgentI extends _OperatorDisp {
public static ArrayList m_conn_list;
jdbcAgentI()
{
m_conn_list=new ArrayList();
}
public int connectDB(String driver,String disp,String host,String port,String db,String name,String pass,Current cur)
{
try {
Class.forName(driver);
} catch (ClassNotFoundException cnfe) {
return -1;
}
Connection c = null;
try {
String _disp="jdbc:"+disp+"://"+host+":"+port+"/"+db;
c = DriverManager.getConnection(_disp,name,pass);
} catch (SQLException se) {
return -1;
}
if(c==null)
return -1;
m_conn_list.add(c);
return m_conn_list.size()-1;
}
public boolean insertSQL(String sql,Current cur)
{
Statement s = null;
if(cur.ctx.containsKey("connection_index"))
{
int index = Integer.parseInt((String)cur.ctx.get("connection_index"));
Connection c=(Connection)m_conn_list.get(index);
try {
s = c.createStatement();
} catch (SQLException se) {
return false;
}
try {
s.executeUpdate(sql);
} catch (SQLException se) {
try {
s.close();
} catch (SQLException e) {
return false;
}
return false;
}
try {
s.close();
} catch (SQLException e) {
return false;
}
return true;
}
else
{
return false;
}
}
public boolean updateSQL(String sql,Current cur)
{
Statement s = null;
if(cur.ctx.containsKey("connection_index"))
{
int index = Integer.parseInt((String)cur.ctx.get("connection_index"));
Connection c=(Connection)m_conn_list.get(index);
try {
c.setAutoCommit(true);
s = c.createStatement();
} catch (SQLException se) {
return false;
}
try {
s.executeUpdate(sql);
} catch (SQLException se) {
try {
s.close();
} catch (SQLException e) {
return false;
}
return false;
}
try {
s.close();
} catch (SQLException e) {
return false;
}
return true;
}
else
{
return false;
}
}
public boolean deleteSQL(String sql,Current cur)
{
Statement s = null;
if(cur.ctx.containsKey("connection_index"))
{
int index = Integer.parseInt((String)cur.ctx.get("connection_index"));
Connection c=(Connection)m_conn_list.get(index);
try {
s = c.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
} catch (SQLException se) {
return false;
}
try {
s.executeUpdate(sql);
} catch (SQLException se) {
try {
s.close();
} catch (SQLException e) {
return false;
}
return false;
}
try {
s.close();
} catch (SQLException e) {
return false;
}
return true;
}
else
{
return false;
}
}
public ArrayList querySQL(String sql,Current cur)
{
Statement s = null;
ArrayList ret=new ArrayList();
if(cur.ctx.containsKey("connection_index"))
{
int index = Integer.parseInt((String)cur.ctx.get("connection_index"));
Connection c=(Connection)m_conn_list.get(index);
ResultSet rs = null;
try {
s = c.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
} catch (SQLException se) {
return null;
}
try {
rs = s.executeQuery(sql);
} catch (SQLException se) {
try {
s.close();
} catch (SQLException e) {
return null;
}
return null;
}
try {
while (rs.next()) {
ResultSetMetaData rsmd=rs.getMetaData();
int col=rsmd.getColumnCount();
ArrayList tmp=new ArrayList();
for(int i=1;i<=col;++i)
{
tmp.add(rs.getString(i));
}
ret.add(tmp);
}
} catch (SQLException se) {
se.printStackTrace();
try {
s.close();
} catch (SQLException e) {
return null;
}
return null;
}
try {
s.close();
} catch (SQLException e) {
return null;
}
return ret;
}
else
return null;
}
public boolean closeDB(Current cur)
{
int index;
if(cur.ctx.containsKey("connection_index"))
{
index = Integer.parseInt((String)cur.ctx.get("connection_index"));
Connection c=(Connection)m_conn_list.get(index);
try{
if(c!=null)
{
c.close();
}
m_conn_list.remove(index);
return true;
}
catch(SQLException se)
{
return false;
}
}
return true;
}
}
服务实现完成之后,开始写服务端的代码server.java
服务端的代码实现起来非常简单,主要是绑口和加入ICE服务。
package jdbcProxy;
import Ice.*;
public class server extends Application {
public int run(String[] args)
{
ObjectAdapter adapter=communicator().createObjectAdapter("jdbcAgent");
adapter.add(new jdbcAgentI(),Util.stringToIdentity("operator"));
adapter.activate();
communicator().waitForShutdown();
return 0;
}
public static void main(String[] args)
{
server app=new server();
System.exit(app.main("server",args,"config"));
}
}
这样服务器端的代码就完成了,可以运行并等待请求过来。
下面开发两种语言的客户端java和c++的:
有心人可能看出,这两种语言的实现是非常相似的,可以说写出一种,就可以写其它各种语言的客户端,用在不同的需求之中。而且另人振奋的是,不同语言的客户端是可以同时对一个服务端发起请求的,服务器看不到程序语言的差别。
Java语言客户端
package jdbcProxy;
import java.util.HashMap;
import Ice.*;
import java.util.*;
import jdbcProxy.jdbcAgent.OperatorPrx;
import jdbcProxy.jdbcAgent.OperatorPrxHelper;
public class client extends Application {
public int run(String[] args)
{
Ice.Properties properties = communicator().getProperties();
final String proxyProperty = "jdbcAgent.Proxy";
String proxy = properties.getProperty(proxyProperty);
if(proxy.length() == 0)
{
System.err.println("property `" + proxyProperty + "' not set");
return 1;
}
OperatorPrx jaix=OperatorPrxHelper.checkedCast(communicator().stringToProxy(proxy));
int i=jaix.connectDB("org.postgresql.Driver","postgresql","192.168.30.20","5432","test","root","123456");
HashMap ctx=new HashMap();
ctx.put("connection_index",String.valueOf(i));
ArrayList ret=jaix.querySQL("select * from mytable",ctx);
if(ret==null)
return 0;
for(int j=0;j<ret.size();++j)
{
ArrayList tmp=(ArrayList)(ret.get(j));
for(int k=0;k<tmp.size();++k)
System.out.print(tmp.get(k)+" ");
System.out.println();
}
jaix.closeDB(ctx);
return 0;
}
public static void main(String[] args)
{
client app=new client();
System.exit(app.main("client",args,"config"));
}
}
C++语言客户端
#include "globe.h"
class Client : public Application
{
public:
virtual int run(int argc,char * argv[]);
Client();
~Client();
int index;
};
Client::Client()
{
index=-1;
}
Client::~Client()
{
}
int Client::run(int argc,char * argv[])
{
PropertiesPtr properties = communicator()->getProperties();
const char * buf="jdbcAgent.Proxy";
string proxy=properties->getProperty(buf);
if(proxy.empty())
{
cerr << argv[0] << ": property `" << buf << "' not set" << endl;
return EXIT_FAILURE;
}
cout<<proxy<<endl;
OperatorPrx jaix=OperatorPrx::checkedCast(communicator()->stringToProxy(proxy));
if(jaix==0)
{
cout<<"cannot get proxy===================="<<endl;
return 0;
}
Context ctx;
int i=jaix->connectDB("org.postgresql.Driver","postgresql","127.0.0.1","5432","test","root","123456");
if(i==-1)
{
cout<<"Cannot connect the db"<<endl;
return -1;
}
char buf2[20];
sprintf(buf2,"%d",i);
ctx["connection_index"]=buf2;
jaix=OperatorPrx::checkedCast(jaix->ice_newContext(ctx));
for(int i=0;i<10000;++i)
jaix->insertSQL("insert into mytable values('好人啊',100)");
table t=jaix->querySQL("select * from mytable");
for(table::iterator p=t.begin();p!=t.end();++p)
{
CString buf=q->c_str();
ConvertUtf8ToGBK(buf);
string buf2=buf;
cout<<buf2<<" ";
}
jaix->closeDB();
return 0;
}
int main(int argc,char * argv[])
{
Client app;
return app.main(argc,argv,"config");
}
只需要开发这两种客户端的逻辑代码,而不用重新开发服务的接口实现。
以下是结果:
数据库中插入四条数据:
图中乱码是因为UTF8引起的。
java客户端在eclipse中的结果:
c++客户端的结果:
文件:
cpp_client.rar
大小:
9KB
下载:
下载
文件:
java_service_client.rar
大小:
2KB
下载:
下载
在linux平台下,这两个包都可能不加改动的使用,这就是ICE的强大之处。
转自:http://blog.chinaunix.net/u/20057/showart_124127.h...
对于网络应用来说,比较简单就是发送请求和等待回应模型,我把这种模式称之为单工模型,服务器没有办法主动通知客户端发生了什么,只有被动的等待客户端来请求并回应,最经典的就是HTTP服务,对于这种模型来说这已经够了,但对于服务器与客户之间的互动来说,这种就不行了,得需要双工模型,即服务器与客户之间的相互通知。对于这种模型,最能说明问题的就是一个聊天室了,一个房间有多人聊天,一个人所说的话得经过服务器而通知其它人,这种就需要服务器与客户端的一个简单互动了,但这也足以说明问题了。ICE的出现使这种模型变得简单,下面我就来介绍一下如何使用ICE来开发聊天室。
如上图所述,我们所要做的工作就是将一台客户端发出的信息,广播到其它的客户端上,就是这么一个简单的操作。为了达到这种目的,必须在服务器端和客户端都开一个监听端口,用来双方交互,同时服务器端还要接受客户端的请求,成为一个信息HUB。
因为ICE本身就是平台无关的,所以在什么平台上编缉并不影响其它平台。首先要写一个slice文件,定义服务。
module FloorSpace
{
interface CallBack
{
void GetInput(string content);
};
dictionary<string,CallBack *> CacheMap;
interface Floor
{
bool Register(string name);
void SetInput(string content);
void Unregister();
void SetupCallback(CallBack * cp);
};
};
CallBack是用来定义客户端的回调服务,Floor是用来定义服务器端的服务。
定义好slice文件后,比如叫做floor.ice,用slice2cpp floor.ice生成服务。它会生成floor.h 和floor.cpp两个文件,这两个文件定了服务接口和代理接口。
需要一个文件用来从floor.h中继承Floor接口中的各种服务,需要一个文件用来从floor.h中继承CallBack接口中的服务。
class FloorI:virtual public Floor
{
virtual bool Register(const string & name,const Current & context);
virtual void SetInput(const string & content,const Current & context);
virtual void Unregister(const Current & context);
virtual void SetupCallback(const CallBackPrx & prx,const Current & context);
CacheMap m_cache_map;
};
class CallBackI:virtual public CallBack
{
public:
virtual void GetInput(const string & content,const Current & context);
};
当然需要将FloorI中的虚函数实现,这就是你的服务真正所在了。
bool FloorI::Register(const string & name,const Current & context)
{
if(m_cache_map.find(name)!=m_cache_map.end())
return 0;
else
m_cache_map[name];
return 1;
}
void FloorI::Unregister(const Current & context)
{
Context::const_iterator q=context.ctx.find("user_name");
if(q!=context.ctx.end())
{
CacheMap::iterator p;
if((p=m_cache_map.find(q->second))!=m_cache_map.end())
m_cache_map.erase(p);
}
}
void FloorI::SetupCallback(const CallBackPrx & prx,const Current & context)
{
Context::const_iterator p=context.ctx.find("user_name");
if(p!=context.ctx.end())
{
m_cache_map[p->second]=prx;
}
}
void FloorI::SetInput(const string & content,const Current & context)
{
Context::const_iterator q=context.ctx.find("user_name");
if(q!=context.ctx.end())
{
CacheMap::iterator p;
for(p=m_cache_map.begin();p!=m_cache_map.end();++p)
{
if(p->first!=q->second)
{
Context ctx;
ctx["user_name"]=q->second;
try
{
p->second->GetInput(content,ctx);
}
catch(ConnectionRefusedException e)
{
m_cache_map.erase(p);
cout<<" 挂了"<<endl;
}
catch(NullHandleException e)
{
m_cache_map.erase(p);
cout<<" 没有诚意"<<endl;
}
}
}
}
}
CallBack服务具体定义:
void CallBackI::GetInput(const string & content,const Current & context)
{
Context::const_iterator q=context.ctx.find("user_name");
if(q!=context.ctx.end())
{
cout<<"["<<q->second<<" say]"<<content<<endl;
}
}
这样我们的聊天室服务器端和客户端的服务定义实现完毕。剩下就是写服务器和客户端了,服务器的实现很简单,因为这是ICE的框架:
int ServerApp::run(int argc,char * argv[])
{
shutdownOnInterrupt();
ObjectAdapterPtr adapter=communicator()->createObjectAdapter("Floor.Server");
adapter->add(new FloorI,stringToIdentity("floor"));
adapter->activate();
communicator()->waitForShutdown();
return EXIT_SUCCESS;
}
就这么几行代码,可以实现网络联结和服务创建。客户端的实现:
int ClientApp::run(int argc,char * argv[])
{
shutdownOnInterrupt();
Ice::PropertiesPtr properties = communicator()->getProperties();
const char * buf="Floor.Proxy";
string proxy=properties->getProperty(buf);
if(proxy.empty())
{
cerr << argv[0] << ": property `" << buf << "' not set" << endl;
return EXIT_FAILURE;
}
cout<<proxy<<endl;
FloorPrx floorprx=FloorPrx::checkedCast(communicator()->stringToProxy(proxy));
if(!floorprx)
{
cerr << argv[0] << ": invalid proxy" << endl;
return EXIT_FAILURE;
}
string user_name;
cout<<"name : ";
cin>>user_name;
cout<<endl;
if(floorprx->Register(user_name)==0)
{
cout<<user_name<<" has been registered"<<endl;
return EXIT_FAILURE;
}
Ice::ObjectAdapterPtr adapter = communicator()->createObjectAdapter("Floor.Client");
adapter->add(new CallBackI, Ice::stringToIdentity("callbackReceiver"));
adapter->activate();
Context ctx;
ctx["user_name"]=user_name;
floorprx=FloorPrx::uncheckedCast(floorprx->ice_newContext(ctx));
CallBackPrx cbp=CallBackPrx::uncheckedCast(adapter->createProxy(stringToIdentity("callbackReceiver")));
floorprx->SetupCallback(cbp);
string content;
cout<<"please input something"<<endl;
cout<<"["<<user_name<<" say]";
while(cin>>content)
{
cout<<endl;
floorprx->SetInput(content);
cout<<"["<<user_name<<" say]";
}
floorprx->Unregister();
}
实现的就是一个人说话,将他说的话传到服务器,服务器将其广播到其它用户,功能实现完毕。
总结:ICE使你不用关心网络如何联结,端口如何定义,你所要关心的就是服务如何实现,而这正是你想要的。当你知道想做什么,但一想到网络通讯的复杂程度,可能就没有信心了,ICE正好使它成为可能。学习ICE是一件很愉快的事。
文件:
ice_floor_callback.rar
大小:
10KB
下载:
下载
转自:http://blog.chinaunix.net/u/20057/showart_123629.h...
ICE作为一种无平台的中间件,提供了最灵活的编译方式,即自定义的平台无关语言slice,这种以语言方式来配置的做法,极大的统一了网络服务的标准,有点类似于java语言的实现与编译,正是因为java语言的定义与实现都是由SUN公司提供的,才极大的推动了java语言的发发展。
在linux平台下编译比windows平台简单的多,必须要用g++ 3.x来编译ICE的开发包,否则会报错。在http://www.zeroc.com/download.html 中下载Ice-3.0.1.tar.gz和ThirdParty-Sources-3.0.1.tar.gz,先编译ThirdParty-Sources-3.0.1.tar.gz:
1、mkdir ThirdParty
2、cp ThirdParty-Sources-3.0.1.tar.gz ThirdParty
3、tar –xzvf ThirdParty-Sources-3.0.1.tar.gz
4、tar –xzvf openssl-0.9.8a.tar.gz
5、cd openssl-0.9.8a
6、./ Configure;make;make install
7、cd ..
8、tar –xzvf expat-1.95.8.tar.gz
9、cd expat-1.95.8
10、./ configure;make;make install
11、cd ..
12、tar –xzvf db-4.3.29.NC.tar.gz
13、cd db-4.3.29.NC
14、cd build_unix
15、../dist/configure;make;make install
16、cd ../..
17、tar –xzvf Ice-3.0.1.tar.gz
18、cd Ice-3.0.1
19、将config文件夹下的Make.rules.Linux,将c++改为g++
20、将config文件夹下的Make.rules里面的变量修改为第三方库的路径,找?号的是系统已经安装的,在linux下STL就是STLport不用另行安装。
#STLPORT_HOME ?= /opt/STLport
#
# If libbzip2 is not installed in a standard location where the compiler
# can find it, set BZIP2_HOME to the bzip2 installation directory.
#
#BZIP2_HOME ?= /opt/bzip2
#
# If Berkeley DB is not installed in a standard location where the
# compiler can find it, set DB_HOME to the Berkeley DB installation
# directory.
#
#DB_HOME = /root2/opt/db
#
# If OpenSSL is not installed in a standard location where the
# compiler can find it, set OPENSSL_HOME to the OpenSSL installation
# directory.
#
OPENSSL_HOME = /root2/opt/openssl
#
# Define if your OpenSSL requires Kerberos, and if Kerberos is not
# installed in a standard location.
#
KERBEROS_HOME ?= /usr/kerberos
#
# If expat is not installed in a standard location where the
# compiler can find it, set EXPAT_HOME to the expat
# installation directory.
#
EXPAT_HOME = /root2/opt/expat
#
# If readline is not installed in a standard location where the
# compiler can find it, AND you want to use readline,
# set READLINE_HOME to the readline installation directory.
#
#
#READLINE_HOME ?= /opt/readline
21、make;make install
这样ICE就可以编译过去了,可以用make test来测试编译得是否正确。
在windows平台上安装ICE比较简单,就是VC设置麻烦些。因为我用的是VC6.0,但用VC7.0和8.0都有相对应的包,安装步骤是一样的。
首先从http://www.zeroc.com/download.html下载ThirdParty-3.0.1-VC60.msi和Ice-3.0.1-VC60.msi,直接安装。
打开VC6.0,在include和lib设置时,在include中加入Ice-3.0.1-ThirdParty-VC60\include\stl_port和Ice-3.0.1-VC60\include。同理在lib中加入Ice-3.0.1-ThirdParty-VC60\lib和Ice-3.0.1-VC60\lib
将Ice-3.0.1-ThirdParty-VC60\include和Ice-3.0.1-ThirdParty-VC60\lib放在第一行,否则编译STL的时候还是没有用STL_port,就会编译失败。
在编译console类型的程序时,要将Porject->setting->c/c++->code gereration中的Use run-time library中的Debug Multithreaded DLL选上,实现多线程,因为ICE本身天生就是多线程的。
在任何情况下编译ICE程序,都要将Porject->setting->C++ Language中的Enable Run-Time Type Information (RTTI)选中,否则STL_port会报Access violation - no RTTI data In Visual Studio (Visual C++)错误。
这样,两种平台上的ICE都安装完毕,可以用Demo来测试环境。
转自:http://blog.chinaunix.net/u/20057/showart_122073.h...
网络服务平台的比较----ICE应用系列文章之一
自从上世纪九十年代以来,计算工业一直在使用像DCOM 和CORBA 这样的面向对象中间件平台。在使分布式计算能为应用开发者所用的进程中,面向对象中间件是十分重要的一步。开发者第一次拥有了这样的可能:不必是一个网络古鲁(guru),就可以构建分布式应用——中间件平台会照管大部分网络杂务,比如整编(marshaling)和解编(unmarshaling)(对数据进行编码与解码,以进行传送)、把逻辑对象地址映射到物理传输端点、根据客户和服务器的原生机器架构改变数据的表示,以及应需自动启动服务器。然而,由于一些原因,无论是DCOM 还是CORBA,都未能成功占领大部分计算市场:
• DCOM 是Microsoft 的独家解决方案,在异种网络中,各种机器会运行多种操作系统,无法使用DCOM。
• DCOM 不能支持大量对象(数十万或数百万),这在很大程度上是它的分布式垃圾收集机制带来的开销造成的。
• 尽管有多家供应商提供CORBA 产品,几乎不可能找到一家供应商,能够为异种网络中的所有环境提供实现。尽管进行了大量标准化工作,不同的CORBA 实现之间仍缺乏互操作性,从而不断地造成各种问题;而且,由于供应商常常会自行定义扩展,而CORBA 又缺乏针对多线程环境的规范,对于像C 或C++ 这样的语言,源码兼容性从未完全实现过。• DCOM和 CORBA都过于复杂。要熟悉DCOM或CORBA,并进行相应的设计和编程,是一项需要许多个月来掌握的艰难任务(而要达到专家水平,需要好几年)
• 在其各自的历史中,性能问题一直在折磨这两种平台。DCOM 只有一种实现可用,所以不可能购买性能更好的实现。而尽管有多家供应商提供CORBA 产品,很难找到遵从标准、性能良好的实现——其主要原因是CORBA 规范自身所带来的复杂性(在许多情况下,其特性都丰富得超出了需要)
• 在异种环境中,让DCOM 和CORBA 共存从来都不是一件容易的事情:尽管有供应商提供互操作产品,这两种平台之间的互操作从来都不是无缝的,而且难以管理,会产生互不相连的技术孤岛。
2002 年, Microsoft .NET 平台[11] 取代了DCOM。但尽管.NET 提供了比DCOM 更强大的分布式计算支持,它仍然是Microsoft 的独家解决方案,因而不是异种环境下的选择。另一方面,CORBA 近年来已停滞不前,许多供应商离开了市场,给消费者留下了不再受到广泛支持的平台;剩下的少数供应商在进一步标准化方面的兴趣也已衰退,致使CORBA 规范中的许多缺陷未能得到解决,或是在它们被报告多年之后才得到解决。在DCOM 和CORBA 衰败的同时,分布式计算社群对SOAP[23] 和webservices[24] 产生了浓厚的兴趣。使用无处不在的WWW 基础设施和HTTP来开发中间件平台的想法十分迷人——至少在理论上。SOAP 和webservices 曾经允诺要成为Internet 上的分布式计算通用语言。 但尽管引发了很大的公众效应,发表了许多论文, web services 却没有能兑现其允诺:在本书撰写的同时,用web services 架构开发的商业系统非常少。其原因是:
• 无论是在网络带宽方面,还是在CPU 开销方面,SOAP 都会给应用造成严重的性能恶化,以致于该技术无法适用于许多有苛刻性能要求的系统。
• 尽管SOAP 提供了"on-the-wire" 规范,要开发现实的应用,那仍是不够的,因为该规范提供的抽象层次太低。应用可以把各种SOAP 消息拼凑在一起,但这样做极其繁琐而易错。
• 缺乏更高级的抽象促使供应商提供各种应用开发平台,使遵从SOAP 的应用开发自动化。但是,除了协议一级,这些开发平台完全没有标准化,不可避免是私有的,所以用一家供应商开发的应用无法与其他供应商的中间件产品一起使用。
• 关于SOAP 和web services 的架构安全性,有一些严重的担忧 。特别地,许多专家都表示,他们对该平台缺乏内在的安全性感到担忧。
• web services 是一项还处在幼年的技术。到目前为止,已进行的标准化很少,而且看起来还需要好几年,其标准化水平才能达到源码兼容性和跨供应商互操作性所要求的完备程度。结果,想要使用中间件平台的开发者面临着一些使人不快的选择:
• .NET Remoting
最严重的缺点是不支持非Microsoft 平台。[虽然出了Mono,但.....]
• CORBA
最严重的缺点是老化的平台、高度的复杂性,以及仍在发生的供应商磨擦。
• web services
最严重的缺点是严重低效,需要使用私有开发平台,并且还存在安全问题。
这些选择看起来很可能会让你失败:你可以选择只能在Microsoft 架构
上运行的平台,选择复杂的、正在被遗弃的平台,或选择低效的、由于缺
乏标准化而归属私有的平台。
引自:http://blog.chinaunix.net/u/20057/showart_121992.h...
转自:韩磊@CSDN
Marc Laukien:Object-Oriented Concepts, Inc的创办人和总裁。开放源码的ORBacus (原名OmniBroker,完全遵从CORBA的ORBA)的主要作者。在2001年IONA(著名的CORBA技术公司)收购OOC之后,他出任IONA负责CORBA开发的副总裁……
Michi Henning:IONA公司前首席CORBA科学家。CORBA编程的经典书籍Advanced CORBA Programming with C++的作者之一。他参与制订了若干OMG规范,并曾是OMG的C++ Revision Task Force的主席……
Bernard Normier:1995年加入IONA公司,并成为Orbix 2000的领头工程师之一。他是OMG的Persistent State Service规范的作者,并且直到2003年2月,他仍是C++和Transaction Service Revision Task Force委员会的主席……
……
看到这样一些CORBA“老兵”,倘若不加以说明,你一定会以为这是一篇关于CORBA的文章。但正如文章名和上面的简介中的一些措辞(“前”、“曾是”、“直到……仍是”……)所暗示的,本文将要讲述的,并非CORBA,而是对CORBA的“反叛”——这支“叛军”名为ZeroC公司,名不见经传;这家公司的旗舰产品叫Internet Communications Engine(Ice);而创办这家公司的,正是上述这些大名鼎鼎的前CORBA阵营中的领军人物。
一、 概览
按照ZeroC的说法,Ice是“一种现代的面向对象中间件,可用于替代像CORBA或COM/DCOM/COM+这样的中间件。在易于学习的同时,它为各种有着苛刻的技术要求的应用提供了强大的网络基础设施。在像SOAP或XML-RPC这样的技术太慢、或是没有提供足够的可伸缩性或安全性之处,正是Ice开始闪耀之地。”而如果把Ice看作是“Millennium CORBA,扔掉了在其生命期里累积的包袱,但却保留了它的全部好特性,增加了一些特性,并以一种明晰而整洁的方式设计它们”,或许更能够让你把握到Ice的本质;甚至于,如果你十分了解CORBA,了解它的长处和弱点,你又深入了解了Ice,你或许也会像给出上述评语的Frank Pilhofer(又一个CORBA专家!)那样叫道:“Way to go!”。
那么,与CORBA相比,Ice到底有何优点?在回答这个问题之前,先让我们看一看Ice拥有哪些值得夸耀的特性:
- 面向对象的规范语言。
- 易于使用的C++和Java映射。在未来的版本中还将支持更多的映射(比如C#)。
非常高效的协议,还可以进行协议压缩。 - 异步方法调用(asynchronous method invocation)和异步方法分派(asynchronous method dispatch)。
- 动态的传输插件。
- TCP/IP和UDP/IP支持,以及基于SSL的安全性。
- Ice防火墙解决方案,支持回调。
- 使用XML的自动持续(persistence),包括对版本管理的支持。
- 类型化的消息传递服务,支持联盟(federation)。
- 软件修补和更新服务。
- 完善的部署工具。
- 详尽的文档。
- GPL授权或商业授权(商业用途)。
- 支持Windows 2000/XP、Linux和Solaris操作系统。在未来的版本中还将支持更多的操作系统。
Ice由以下一些软件包组成:
IceUtil
一组实用函数,比如像Unicode处理和线程编程(只是C++版本)
Slice
Ice规范语言(Specification Language for Ice)。Slice在客户和服务器之间建立合约,另外也被用于描述持续数据。
Slice编译器
用于把Slice编译为目标语言(比如C++、Java、XML)或是根据Slice文件自动生成文档。
Ice
Ice核心库。它使用非常高效的协议(包含了协议压缩和对TCP和UDP的支持)管理所有的通信任务,为多线程服务器提供灵活的线程池,并且还有支持极端的可伸缩性的额外功能——可能达到数百万个Ice对象。除此而外,Ice核心库还有其他一些功能。
IceBox
专用于Ice应用的应用服务器。IceBox可以轻松地运行和管理Ice服务,这些服务可作为DLL、共享库或Java类动态加载。
IcePack
完善的服务器激活和部署工具。通过IcePack,在异种计算机网络中部署应用的复杂任务得到了极大的简化。你只需要提供行业标准XML格式的部署描述信息,IcePack就能替你处理余下的工作。
Freeze
Freeze为Ice servant提供自动持续。只需少许代码,应用就能与高效管理持续对象的“逐出者”(evictor)结合在一起。Freeze提供二进制数据格式,以获取最大限度的速度;同时还提供XML数据格式,以获取极度的灵活性。当持续数据的Slice描述变化时,你可以轻松地迁移使用XML数据格式的Freeze数据库——对于大型软件项目中的版本管理,这是必不可少的。
IceSSL
Ice核心的动态SSL传输插件。它使用行业标准SSL协议,提供了认证、加密和消息完整性检查。
Glacier
对对象中间件系统的一个极大挑战是安全性和防火墙。Ice的防火墙解决方案Glacier,极大地简化了安全应用的部署。Glacier认证并过滤客户请求,并允许以安全的方式对客户进行回调。与IceSSL结合,Glacier提供了既非侵入式、又易于配置的强大安全解决方案。
IceStorm
一种支持联盟的消息服务。与大多数其他的消息或事件服务相反,IceStorm提供类型化的事件,这意味着在联盟上广播消息就和调用某个接口上的方法一样容易。
IcePatch
用于软件发布的修补服务。让软件保持最新常常是一件单调乏味的任务。IcePatch使各个文件、以及完整目录层次的更新得以自动化。只有变更过的文件才被下载到客户机器中,而且会使用高效的压缩算法。
二、 与CORBA的对比
尽管ZeroC声称自己无意“贬低”CORBA,并称“CORBA相对于其时代而言是一项了不起的成就”,而且Ice还从CORBA那里借取了许多好思想,但如果这些专家们仍能在CORBA内部进行变革,仍认为CORBA还有前途,他们大概也无需成立新的公司,开发新的产品,“公然”进行“反叛”了。看完下面的译自ZeroC网站的“Ice vs. CORBA”的对比,你不仅能够明白,Ice相对于CORBA究竟有何优势,你或许也将明白,“叛军”之所以要成为“叛军”的原因。
完备性
当我们说完备性时,我们意指的是现实世界产品的完备性,而不是那些从未被实现的规范的完备性。我们相信Ice比市场上任何一种CORBA产品都要完备。你自己检查一下:哪一种CORBA产品真的提供了可与Ice相比的特性?
没有“Design by Committee”
Ice是由一小群热诚的、富有高度经验的人设计的。它并不试图成为适用于所有人的万用药。而另一方面,在CORBA规范中则充斥着各种“华而不实的东西”;这些东西由一些即得利益集团强行注入规范之中,它们并没有真的弄清楚这些规范是否能被实际实现。
在CORBA规范的提交过程中,达成一致的途径常常是把所有已经存在的私有实现的五花八门特性的集合全数接受下来。结果,规范的大小和复杂度远远超出了必需,而且平台也更大、更慢,并使得所得到的复杂API变得更难以使用。Ice提供的API要小得多、更为高效,比等价的CORBA API更易于学习,而且也没有牺牲功能。
Slice
Slice比CORBA IDL更小、更干净、更强大。它的语言成分更少,在整体上却更为灵活。例如,内建的字典(dictionary)类型提供了对快速访问(fast-access)数据结构的直接支持,异常继承提供了更为干净的到“具有内建的异常处理功能的语言”的映射。同时,Slice消除了CORBA IDL的许多不必要的复杂性,比如属性(attribute)、inout参数、context,以及Objects-by-Value(OBV)的复杂性。
持续
Slice不只是一种接口定义语言,它还可被用于描述持续的Ice对象的状态,从而使我们更易于编写在数据库中自动地存储对象状态的服务器。
元数据(Metadata)
Slice支持一种可扩展的元数据设施,允许我们为应用特定目的标记Slice成分。例如,元数据可被用于定义Java语言映射,满足特定应用的需求。
没有Any类型
Ice没有CORBA Any类型的等价物。CORBA用户也许会对此感到很意外,因为在CORBA规范中大量使用了Any类型。但是,Any类型是多余的:像Java和C++这样的程序设计语言不需要Any类型,设计良好的分布式系统也不需要。Any类型通常被用于两种情况下:或是系统需要一种不透明的类型,中介方可进行接收和传递,而无需了解该类型的细节(比如CORBA Event Service);或是被用作联合(union)的等价物。
Ice可以发送和接收如“blob”这样的请求来处理第一种情况,Slice类继承可以处理第二种情况。无论是哪种情况,所得到的应用都更为高效、更为安全,也更易于设计和实现,而且不会遭受与CORBA Any类型相关联的复杂性的折磨。
Ice核心
CORBA核心随着时间的过去已经变得极其复杂。一个最好的例证是Portable Object Adapter,尽管需要支持经常出现的实现技术很少,它仍要求开发者具有专门的知识才能对其进行正确的使用。而另一方面,Ice对象适配器,更简单,更直接,并且比POA更强大:使用POA,有些工作会变成长期的编程项目,而使用Ice对象适配器,使用一些设计良好的API可以很快完成这些工作。
Ice协议
IIOP是CORBA最为薄弱的地方之一,其设计缺陷太多,很难把它们一一列出。仅举几个例子:没有请求封装,这使得转发服务(比如Event Service)在不了解所涉及的所有类型的细节的情况下,无法进行工作;低效的对齐规则迫使系统进行不必要的数据复制;数据编码规则很复杂,却又没有带来性能上的提高;对象引用编码非常复杂,妨碍了高效的整编和内存共享实现;代码集磋商还未定义,并且遭受到竞争状态的折磨;所有这些复杂性意味着IIOP难以实现,并会带来互操作性和性能问题。Ice协议简单、更高效,并且提供了像数据压缩和批请求这样的特性(IIOP无法支持这些特性)。
安全性
安全性总是CORBA最大的问题之一。OMG反复以书面形式制定了一些规范,却仍未有广泛可用的实现支持这些规范,CORBA用户也仍然无法得到可用和安全的ORB。与此相反,在设计Ice时,我们始终把安全性放在首要位置。这也是Ice为何要创造性地提供SSL,并提供确实能工作的、灵活而没有侵入性的防火墙解决方案的原因。
C++映射
与CORBA和C++“共事”非常困难,即使对于有经验的C++开发者来说也是如此。有无数涉及内存管理和异常安全性的陷阱和缺陷。与此相反,Ice C++映射非常简单和直接。开发者实际上不可能由于犯错而造成内存泄漏。要记住的规则的数量无限地小于CORBA C++映射的规则数量,而且,Ice C++映射基于STL行业标准。
可伸缩性
CORBA技术的可伸缩性非常好,但前提是你是一个专家。而使用Ice,谁都可以编写可高度伸缩的应用。例如,Ice为你实现了一种持续的“逐出者”模式,让你能够很容易地处理数百万对象。你所需做的就是用Slice定义持续对象数据,并让Ice来完成余下工作:Ice run-time会使用高速数据库自动地加载和存储对象。
版本管理
CORBA没有任何用于支持对象状态的版本管理的机制。Ice可以将数据存储为XML格式,当持续数据的Slice描述变化时,可以很容易地将数据库移植到新的格式。
软件更新
IcePatch工具可以用来保持客户软件的及时更新,它使用了压缩来进行高效的数据传输,使用了校验和来保证一致性。CORBA没有提供在分布式系统中分发软件更新的机制。
类型化事件服务
在CORBA中有类型化事件服务规范,但其实现(如果有的话)却很少。它的类型化事件服务还存在着许多已知问题,使其在现实世界的部署中实际上是无用的。Ice的设计从最开始就支持类型化事件服务。IceStorm是高效的类型化事件服务实现,同时还支持联盟。
Facets(面)
CORBA支持继承、DCOM支持聚合。在过去,有许多关于何者更好的辩论。Ice两者都支持:接口继承加上聚合,以facets的形式。facets允许你使用动态聚合,而不是静态继承,来在运行时扩展类型。
异步消息
CORBA支持Asynchonous Message Invocation (AMI),但几乎没有CORBA产品实现AMI。以一种简单而高效的方式,Ice从最开始就支持AMI。Ice还支持Asynchronous Message Dispatch (AMD),在CORBA中没有对应的等价物。AMD是用于客户的AMI的服务器端等价物。通过AMI,你可以将分派线程返还给Ice,并在将结果递送给客户时进行回调。可将AMI和AMD串联在一起,从而创建非常高效的、资源消耗很少的路由器。
AMI和AMD对客户和服务器来说都是透明的。也就是说,服务器不知道请求是通过AMI到达的,还是同步发送的,而客户也不知道操作调用是通过AMD处理的,还是同步处理的。要支持AMI和AMD,无需改动Slice定义。
三、 应用实例
2003年3月17日,一家名为Mutable Realms的公司在E3游戏展上公布了一款名为“Wish”的新游戏。该公司宣称,通过这个游戏,他们定义了一种新的游戏范畴:Ultra Massive Multiplayer Online Role Playing Games。与传统的Massively Multiplayer Online Role Playing Games (MMORPG)不同的是,Wish不会将游戏者限制在某个只有数百游戏者的服务器上,而是允许数万游戏者出现在同一个3D幻想世界里。
Wish所用的通信平台正是Ice。正如Michi Henning所说,这样的游戏对可伸缩性、速度和可靠性的要求,只有大型的电信项目才能超出——难以想象,不是吗?实际上,ZeroC和Mutable Realms两家公司进行了紧密的合作,以确保Ice能够提供开发Wish这样的游戏所需的全部特性(这样的“定制”没有什么坏处,你大概不会嫌自己的应用跑得太快;如果你真这么觉得的话,有一个解决问题的好办法:::sleep(100))。
或许我们已没有必要再贬抑CORBA,但来自Mutable Realms的开发者Benoit,仍然“借用”了CORBA来表达对Ice的欣赏:“I have no doubt that our productivity wouldn't be as good if we were using CORBA as our middleware technology”。
四、 结语
“Basically, Ice is what we always wished CORBA would have been.”当Michi Henning这样说的时候,他想到了自己作为世界顶尖的CORBA专家,在每天使用CORBA、达8年之久之后,仍然要靠查对自己撰写的书来编写CORBA代码——因为他还是记不清那些细节;他也想到了OMG内部那些“令人恐惧”的磨擦和这一领域中创新的“令人恐惧”的衰减……遇到这样的局面,不生出“异心”,大概根本称不上是真正的技术专家;而当领军人物开始另起炉灶,CORBA的末日或许就真的不远了。
但另一方面,技术也许从来都不是IT行业真正的决定性因素。商业才是。至少就目前看来,Ice还未受到广泛的关注,而像OMG这样的“豪门俱乐部”,以及各大CORBA技术公司,也不会轻易就放弃自己的地盘。Ice的前途究竟如何,还有待时日来观察。如果在国内有更多的公司或个人采用Ice来开发软件,无疑将有助于Ice的发展和进步。
反叛,才刚刚开始。
ICE的C++编译需要使用STLport。
STLport-4.6 是完全兼容ANSI C++标准的类库。
This distribution contains STLport sources only, no binaries.
To use STLport iostreams, you have to build STLport library from sources in "src"
directory and link your programs with it.
这个发布包仅仅包括STLport源代码马,不含二进制发布软件包。必须重新编译src目录下的代码才可以使用STLport iostreams类库。
This is major change since pre-4.0 releases, please read the instructions carefully.
这是自4.0版本发布以来的重要变更版本,请仔细的阅读下面的操作指南。
==== Unpacking and installing STLport ==========
解包和安装STLport
1) Unpack STLport archive to a directory accessible during compilation.
NOTE : DO NOT overwrite header files coming with the compiler, even if you made
a backup - this won't work ! Most probably, you've already unpacked the archive before
reading this file though ;)
首先吧STLport安装包解压缩到一个目录。注意:不要覆盖了编译器自带的头文件,即使你已经做了备份,也不要这么做!
2) Make sure "stlport" directory of this distribution comes before compiler's one
in your search path when you compile the project;
确保stlport目录在编译器自带的头文件搜索路径之前
Note: for SunPro CC 5.0 and higher, there used to be special directory "stlport/SC5"
this is now obsolete, please make sure you do not use it anymore.
注意:对于SunPro CC 5.0或者更高版本,有一个特殊的目录stlport/SC5,这个目录已经背废弃了,请不要再使用这个目录。
3) Make sure you do not rename this "stlport" subdirectory -
that may result in compilation errors.
确保不要修改stlport的子目录名称,否则会导致编译错误
NOTE : Do NOT attempt to run "configure" ! It is deprecated, moved to safe standalone folder
and should be used as a helper to create initial config for a new compiler only.
Your compiler should be recognized by STLport source code with no configuring.
Please edit appropriate configuration header for your compiler
directly if you have to make compiler-specific configuration changes.
注意:不要尝试运行configure命令,该方法已经废弃不用了,已经移到一个安全单独的目录,只能用于作为为新编译器的创建初始配置的辅助手段。您使用的编译器应该能够被STLport的源代码识别,如果需要针对您使用的编译器进行特殊的配置,请直接修改适当的头文件。
4) Go to "src" subdirectory. It contains various makefiles for different
compilers. If you are not able to find makefile for your particular
compiler, please use one that looks most similar to your make engine to
create your own.
直接进入src目录,这个目录包含了各种不同编译器使用的make文件,请选择一个和你的编译器相似的make文件。
Verify you can do command line compiles. IDE users may have to do something
special, like add environment variables (for Microsoft) or install
additional compiler components (for Metrowerks), before they can use their
command line compilers.
必须在命令行方式编译,使用IDE编译需要设置一些环境变量(微软)或者安装特殊的编译组件(Metrowerks)。
IMPORTANT :
If you DO NOT plan to use STLport iostreams implementation, you do not have to build the library.
Please do this instead :
如果你不需要使用STLport iostream类库,你不必编译整个类库,请使用下面的方法
4-1) Using appropriate makefile, do "make -f <your compiler name>.mak prepare".
Please do not skip this! On some platforms, it creates necessary symbolic links.
If you do build STLport iostream, this step is performed automatically when you do "make all".
使用适当的make文件,执行“make -f <your compiler name>.mak prepare”命令,不要跳过这步!在一些平台上,它创建了一些符号链接。在需要编译STLport库时,这个步骤是由“make all”自动完成的
4-2) uncomment _STLP_NO_OWN_IOSTREAMS setting in "stlport/stl_user_config.h" to disable use
of STLport iostreams and to use wrappers around your existing iostreams.
After disabling STLport iostreams, you will use wrappers around your compiler's iostreams
libabry, as in previous STLport releases.
No binary library for STLport needs to be built in this case.
Note though :
- new-style ANSI iostreams may not be available on your system;
- compiler's iostreams are most likely slower than STLport version.
删除stlport/stl_user_config.h文件中_STLP_NO_OWN_IOSTREAMS编译常量的注释禁止使用STLport iostream类库,并且使用已经存在的iostream类库的封装类。在这种情况下不需要重建STLport二进制类库。
If you have decided to disable STLport iostreams, you may stop reading here.
如果你已经决定不使用STLport iostream类库,可以不用往下阅读了。
==== Building STLport iostreams library ==========
Below are step-by-step instructions to build STLport streams library:
下面是一步一步的教你编译STLport stream类库
5) Using appropriate makefile, do "make clean all" to build the STLport libraries
(makefiles are set up to build several different flavors - debug/nondebug,
static/dynamic versions).
Optionally, do "make install" to copy STLport headers and libraries to shared location.
选择适当的make文件,执行make clean all编译STLport库,make文件设置了集中不同的编译方式-debug/nondebug和static/dynamic版本。可选的,执行 make install拷贝STLport的头文件和库文件到共享的位置。
Note : your "make" program may have different name, like "nmake" for Visual C++.
注意:make文件可能有不同的名称,VC使用nmake
Examples :
1. If you are building STLport for just one compiler, you may do something like that
(DOS syntax for Visual C++ below):
copy vc6.mak makefile
nmake clean all
nmake install
例如:
1.如果你只是为一种编译器编译STLport,方法如下:
copy vc6.mak makefile
nmake clean all
nmake install
2. If you plan to build STLport with multiple compilers, use "make -f" :
make -f gcc.mak clean install
make -f sunpro.mak clean install
This will build and install STLport for gcc & SUN CC.
2.为多个编译器编译STLport,使用make –f
make -f gcc.mak clean install
make -f sunpro.mak clean install
这会编译和安装STLport gcc和SUN CC两个版本。
"install" target works on most platforms.
install编译依赖目标几乎在所有的平台上可以使用。
On Win32, it does the following :
- copies STLport headers in "stlport" subdirectory of your compiler's INCLUDE directory;
- copies STLport .lib files in your compiler's LIB directory;
- copies STLport DLLs to Windows system directory so they can be found at runtime.
在Win32平台上,install目标做了下面的工作:
-拷贝STLport的头文件到编译器的INCLUDE目录
-拷贝STLport.lib到编译器的LIB目录
-拷贝STLport DLL库到Windows的系统目录
On UNIX, it does the following :
- copies STLport headers in "stlport" subdirectory of system's local include directory (default is /usr/local/include);
- copies STLport .a and .so files to system local library directory (default is /usr/local/lib);
在UNIX平台上,它完成了下面的工作
-拷贝STLport头文件到系统local include目录(默认是/usr/local/include)
-拷贝STLport.a和.so文件到系统的local库文件目录(默认为/usr/local/lib)
6) If build fails, you may choose to :
- try fixing the build ;
- wait until somebody else will submit corresponding changes to be incorporated in next STLport
release/snapshot. To use STLport w/o its own iostreams, please do step 3a).
In case you do patch STLport, please submit your patches to support@stlport.com or (better)
to STLport Forum (http://www.stlport.com/cgi-bin/forum/dcboard.cgi)
如果编译失败,你可以:
-试着修改相关文件重新编译
-等待其他人发现同样的问题,这STLport的下个发布中修改
既然你已经为STLport打了补丁,请把你的补丁发送到support@stlport.com或者(最好使用这种方式)STLport Forum(http://www.stlport.com/cgi-bin/forum/dcboard.cgi)
7) Do "make install" to install resulting libraries into "./lib" subdirectory.
执行make install安装编译产生的库到/lib目录
==== Linking your application with STLport library ==========
链接应用程序到STLport库文件
8) Supply the "lib" subdirectory to the library search path and add desired
library to the list of libraries to link with.
把lib目录加入到库文件的搜索路径中并且指定要链接的库名称。
Examples (imagine you have mytest.cpp in the same directory as this file is):
With gcc : gcc -I./stlport mytest.cpp -L./lib/ -lstlport_gcc
With DEC CC : cxx -I./stlport mytest.cpp -L./lib/ -lstlport_deccxx
With SUN CC : CC -I./stlport mytest.cpp -L./lib/ -lstlport_sunpro
.....
例如:
-gcc,gcc -I./stlport mytest.cpp -L./lib/ -lstlport_gcc
-DEC CC,cxx -I./stlport mytest.cpp -L./lib/ -lstlport_deccxx
-SUN CC,CC -I./stlport mytest.cpp -L./lib/ -lstlport_sunpro
……
[ Visual C++ specific ] For VC++, you do not have to specify "stlport-msvc-XXX.lib" explicitly,
as it is being choosen and forced to link automatically by "#pragma"'s in stlport/config/stl_select_lib.h.
Appropriate version is being selected based on /MD[d] vs /MT[d] options and __STL_DEBUG setting.
All you have to do is to set library search path for the linker.
Example :
cl.exe /I.\stlport mytest.cpp /link /libpath:.\lib /MD
-VC比较特殊,不需要显式的指定stlport-msvc-XXX.lib库文件,而是在 stlport/config/stl_select_lib.h头文件中使用#pragma指令自动选择了链接的库文件。有些版本基于/MD[d] vs /MT[d]编译选项编译,以及设置了__STL_DEBUG编译常量。只需要按照下面的设置即可:
cl.exe /I.\stlport mytest.cpp /link /libpath:.\lib /MD
9) If you linked your application with shared STLport library (.so or .dll), please make your .so or
.dll's to be found in PATH at runtime. On Windows, the simplest way to do it
is to copy all .dll's to Windows system directory. Or, you might choose to add directory
containing STLport to the PATH environment string.
10) Have fun !
10/31/03, Boris Fomitchev.
引自:http://blog.sina.com.cn/u/5551e55e010003el