• 客户端和服务端的故事
  • 发布于 2个月前
  • 167 热度
    0 评论
  • 洪峰
  • 0 粉丝 17 篇博客
  •   

周末的咖啡馆有点奇怪,  一群人围着几个老头儿在聊天。

 “快说说,你们那个时候没有HTTP, 没有JavaScript,到底是怎么让这些机器上的程序进行'交谈'的?”

ftp老头儿满脸沧桑,喝了一口咖啡,说道:“简单得很,机器A通过我,就是ftp, 上传一个文件到机器B的指定路径,然后再让rexec 去调用机器B上的程序,这程序是程序员写的,可以读取FTP目录下的文件,执行业务逻辑就行了。”

“什么是rexec ? ” 

“就是从一台机器上远程执行另外一个机器的命令嘛!” rexec老头儿略带怒气地说道,自己虽然没有ftp出名,但是不至于没人知道吧!

rexec [remote_host] [command]

“切!骗谁呢,根本不可能,怎么会用这么笨的方式!”人群中传来了表示不屑的声音。 

ftp和rexec相视苦笑,这些程序员不会想到,早些年真有这么做的系统,是真实的故事。   

ftp招呼telnet一起喝咖啡,不再出声。

RPC

门口传来一阵喧嚣,CORBA和Java RMI风风火火地走了进来。

人群呼啦一下子就围了上去,抛弃了那三个老头儿。

只听见Java RMI说道:“所有的程序本质上都是函数调用,函数调用在一个进程内是无比自然的事情。 如果是跨越机器、跨越进程呢? 如果一个机器上的函数,能调用另外一个机器上的函数,就像调用本地方法一样,会是什么样子? ” 

CORBA笑着说:“哈哈, 画面太美不敢想象。 ”

人群中有人问道:“调用远程方法就像调用本地方法一样?怎么可能?”

Java RMI说道:“在概念上其实极其简单,无非就是自动生成客户端代理和服务器端代理,这两个代理完成了大量的脏活和累活,比如:网络通信,参数序列化...... ”

CORBA接着说道:“魔法都在这两个代理当中,我们称之为Stub(客户端代理)和Skeleton(服务器端代理)。这个Stub代理提供了和服务器一模一样的接口,客户端程序只要调用它,它就会把请求发到服务器端的Skeleton代理进行处理。 所以对于客户端程序来说,网络不可见,就像是调用本地的方法一样。”

Java RMI说道:“对,我们把这种方式称为RPC。”

人群中发出一片惊叹声:“这RPC可真好啊,Stub和Skeleton代码能自动生成,我们拿到以后,马上就可以动手编程了,底层什么都不用关心。 ”

Java RMI说道:“底层可以采用二进制的协议,性能不要太好哦!” 

人群中又是一阵欢呼:“太好了!”

那边的ftp老头儿警告到:“大家要小心,要注意平台绑定,你想用Java RMI吗? 对不起,客户端和服务器都得用Java,都得安装Java虚拟机,  什么Python, C#, 没门儿, 连想都不要想。 ” 

telnet接着说:“更重要的是客户端和服务器紧密绑定,服务器端的变化,都必须得重新生成Stub和Skeleton 。 ”
没想到这些老家伙们目光如炬。

 “什么? 这也太无理了吧!” 人群呼啦一声又涌到了三个老头那里。

只见ftp老头儿在纸上写到: 比如说有这么一个接口, 可以根据用户ID查找用户信息。

public interface UserService extends Remote{
    public User findUser(int  id) throws RemoteException;
}

利用Java RMI的工具,可以生成Stub和Skeleton, 客户端拿到Stub以后,可以开心地去编程了。

至于UserService的具体实现代码,客户端不用操心。 

过了两天,某个客户端要求要给这个接口增加一个新的方法:按照名称来查找用户。

public User findUser(String name) throws RemoteException;

那对不起了,需要重新生成新的Stub和Skeleton, 所有的客户端都会受到影响,即使你根本不需要新的方法。

大家纷纷唉声叹气,这RPC实在是太烦人了!

有没有一种办法,让服务器端独立变化,而不影响客户端,或者说尽量不影响客户端呢?


XML-RPC

后面有个小伙字若有所思,他刚学会了XML, 他觉得既然XML的描述能力这么强,能不能用XML来描述一个方法调用和参数呢?

比如服务器端有个接口是getUser,需要提供的参数是用户ID, 可以这么描述:

然后通过HTTP Post把这个XML发送到服务器端,服务器端进行解析,获取方法名称和参数的值,调用真正的方法,把结果也以XML形式返回, 客户端收到以后再解析就可以得到结果了。 

想到此处,他大声叫道:“别生成什么Stub和Skeleton代理了,直接用HTTP和XML该多好啊。”

人群被他的奇异想法所吸引,呼啦一下又围了过来。

小伙子画了一张图, 展示了这个处理的过程:

有人问道:“返回的数据格式可能很复杂, 怎么表示啊。”

小伙子说:“这正是XML的强项啊,图中展示的是int型,还可以有double ,boolean ,string 等各种类型,甚至可以定义结构体。”

对XML来说,这样的结构体就是小菜一碟。

“这样客户端和服务器端就变成松耦合的了,如果服务器端想添加一个新的接口,客户端就不用做变化了。我打算把他叫做XML-RPC”  小伙子说道。 

“这种办法真好!” 人群中开始躁动起来,“我们都用XML-RPC吧!”


SOAP

“小伙子,你叫什么名字?” 狂热的人群中有个人冷静地问道。

“Dave Winer, 怎么了? ” 

“Winner? 嗯,你的名字真不错,天生赢家啊, 有没有兴趣和我们微软一起制定一个新的RPC标准?”

“新标准? 我的XML-RPC已经很完善了,又简单又好用。”

“No,No, 还欠缺不少东西,最要命的就是客户端和服务器端没有正式的协议约定,都是口头约定,或者文档约定,对吧?”

Dave Winer点点头。

“你想想,如果我们把一个服务器对外提供的接口也用XML精确地描述下来,任何程序,只要读取这个XML文件,就知道接口的方法名,参数名,该有多好?”

Dave Winer又点点头。

“还有啊,你的XML-RPC只支持HTTP, 我们的新标准可以支持任意协议啊, HTTP, SMTP,TCP,UDP......都可以。”

“我还是觉得HTTP最好!” 

“想想看,如果我们的新协议搞成了,所有的B2B的电子商务系统都可以用这一套协议来自动通信,多么完美的世界! 你仔细想想,你是想在这个破咖啡馆喝一辈子咖啡,还是想和我们微软一起改变世界?”

一年以后,Dave Winer 新的协议问世了,不,这其实是一套协议: 

WSDL :用于描述一个服务的接口,参数......

UDDI : 实现服务的注册和发现

SOAP : 和XML-RPC很像,但是更加规范,更加正式,更加复杂......

他们之间的关系如图所示:

微软的.NET战略适时启动,Web Service的宣传铺天盖地:你只要用WSDL定义了接口,就可以选择任何语言来实现! Java , Python, 甚至C语言都可以,当然,我们的Visual Studo, C#和它结合得更好,欢迎使用。

人们趋之若鹜。


几年以后

Dave Winer又一次来到了咖啡馆,这一次他选择了一个角落坐下,要了一杯咖啡,静静地听大家聊天。
“你们知道吗,微软太坑爹了,那个SOAP实在是太难用了!”

“没错没错,罗嗦,罗嗦,太罗嗦了。你看看,我每次发个SOAP请求得多麻烦:”

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="http://www.example.org">
  <soap:Header>
  </soap:Header>
  <soap:Body>
    <m:GetUser>
      <m:UserID>1001</m:UserID>
    </m:GetUser>
  </soap:Body>
</soap:Envelope>

“这算什么,返回值也是同样罗嗦的XML,解析起来实在是累死了。”

“是啊,如果没有可视化工具的辅助,简直是无法使用。”

Dave Winer一边喝咖啡一边想,没办法,这XML就是这样,不过我们的SOAP搞得是不是有点过分了?

“我觉得这就是那些大厂商们为了赚钱而搞出的东西,都是为了卖他们的软件,一点都不实用!”

“我们还是回归最简单的HTTP调用吧!”  有人提议。

比如想获取一个用户的信息,可以调用这样的API  http://xxx.com/getUser?id=1001

“服务器端还要返回又臭又长的XML吗? ”

“不,我们可以用JSON这种数据格式,简洁紧凑,对JavaScript非常友好,处理起来非常方便。”

大家都表示同意。

“大家别激动,如果用这种方式,和原来的XML-RPC本质上是一样的,都是把服务器端看做是一堆函数的集合,然后客户端去调用他们。Java RMI是通过Stub/Skeleton代理的方式,XML-RPC是通过XML的方式。” 一个叫做罗伊的小伙提醒道。


 “那可不咋地,服务器端不就是一堆函数吗?”  有人说道。 

“大家转换一下思路,别把他们当成函数,当成资源(Resource), 从动词转换成名词试试。” 

听到罗伊这新奇的想法,一群人又围了上来。

“名词? 资源? ”

“是啊,比如说用户,学生,订单等等。他们天然可以用uri来表示。”

 

“有点意思, 那对这些资源怎么操作?”

“HTTP的方法GET,POST, DELETE,PUT,HEAD...... 可以充当动词啊。”罗伊说道。 

“我的妈啊,你竟然把HTTP的方法当成增删改查了。”

话虽这么说,可是大家都觉得这种方式挺简单的,充分利用了HTTP的特性,只要脑子里不要把服务器端看成函数,而是当作一堆名词资源就可以了。

“这种方式叫什么名字?”

“RESTful API !” 

“这RESTful看起来不错啊,要不我们试试?”

“试试去!不行的话就找这个罗伊算账!”

用户评论