server push具体实现
---摘自《网易》(文/wangjinhua)
拙作“推”向更快发表后,笔者收到了很多朋友的来信,希望能了解更多的关于 SERVER PUSH的技术资料,说实话对这一新技术笔者也不是太了解,但本着知无不言的思想,在这里根据笔者的实际使用情况作一些详细的介绍,希望给那些对 SERVER PUSH有兴趣的朋友一点点的帮助和参考。也希望能借此抛砖引玉,求得高手的不吝指教。
“推”由于篇幅的原因,只对 SERVER PUSH作了一般的介绍,下面我们来看看SERVER PUSH的具体实现过程:
一、作业系统:
目前 SERVER PUSH还不能在WIN9X上实现,至少是我自己还没有在WIN9X作为主机上实现过这一功能。经笔者试验成功的作业系统有:WINNT4.0,UNIX,LINUX,FREEBSD,以LINUX支持最好。因为我使用的LINUX都是最新的版本,可以方便地编译最新的功能模块。当然还有其它的作业系统也能很好地支持 SERVER PUSH功能,但笔者限于条件没有测试过。
二、WWW服务器:
其实目前除了IIS和APACHE这两个WWW服务器,你没有更好的选择,值得庆辛的是它们都能很好地支持 SERVER PUSH,当然你应该选择它们的最新版。别的那些小孩子过家家那样的WWW服务器就不用试了。在这里笔者极力推荐在LINUX上安装APACHE,以便能自由编译功能模块,这样可以充分使用SERVER PUSH、FASTCGI、E-CGI、HPH等新的扩展功能。
三、脚本支持:
虽然 SERVER PUSH可以用更多的脚本程序来编写,但笔者强烈推荐用PERL或C语言来写CGI脚本,因为PERL已经是CGI脚本程序事实上的标准。而且在PERL5中已经可以直接调用C子程序而不需要任何声明。不管你用什么语言来写CGI脚本,解释器中应该有CGI.PM模块,笔者试用的版本是 5.004,这一模块的更新版大家可以从网上下载,找不到?用搜索引擎输入CGI.PM就行了,要多少个都有。
好了,有了上面的工具,下面我们就来写一个 SERVER PUSH程序来说明它的实现过程:
#!/usr/bin/perl
use CGI qw/
ush -nph/;
$| = 1;
print multipart_init(-boundary=>'--boundary');
while (1) {
print multipart_start(-type=>'text/plain'),
"The current time is ",scalar(localtime),"n",
multipart_end;
sleep 1;
}
use CGI qw/
ush -nph/;这一行告诉CGI解释程序,调用支持SERVER PUSH的功能模块(CGI.PM),在这个模块中预先定义了三个涵数:multipart_init()、multipart_start()和multipart_end,只要在程序中有use CGI qw/
ush -nph/声明。就可以直接使用这三个涵数。
multipart_init()涵数的作用是声明了一个文档类型,就象普通的CGI程序中的“Content-Type: text/html”声明,告诉服务器下面传送的是HTML文档,而multipart_init()这一涵数声明的文件类型却是实现SERVER PUSH最根本的方法类型:Content-Type: multipart/x-mixed-replace; boundary='--boundary'如果你对HTTP的MIME类型有详细的了解,你就知道multipart类型是一种复合类型,它的子类型是mixed,子类型的X参数大家可以参看详细的MIME类型说明,这里最关键的是replace方法,它不停地用新接收的数据更新旧的数据。这,就是SERVER PUSH最大的技术内涵。boundary只是一个边界值,告诉浏览器从这儿开始,使用SERVER PUSH方法了。其实你完全可以这样理解,只要在脚本程序中声明了multipart/x-mixed-replace; boundary='--boundary'这样一个文档类型,服务器就和客户机建立了一个特别的连结。服务器就不断地把客户机请求的数据源源不断地推向了客户机。而传统的CLIENT PULL方法是:1、CLIENT和SERVER建立连结。2、CLIENT发送请求。3、SERVER响应请求。4、SERVER断开连结以响应下一请求。通过这两种方法的比较大家可以看出SERVER PUSH优点主要在于服务器和客户机之间这种不间断的连结方式。使得它不需要采用CLIENT PULL的<META http-equiv=refresh content="n">这种方法来刷新页面,不仅更新速度快,而且不会产生闪动效果。
可以看到,如果你不用multipart_init(),直接在脚本程序中用这样的语句也可以达到同样的目的:
print "Content-Type: multipart/x-mixed-replace;boundary='boundary'nn"
这样做的好处是当系统不能支持multipart_init()涵数时,就可以直接这样声明.
multipart_start()这个涵数是为服务器指定了传送一个确定的文档,如果不用这个涵数,根据脚本程序的内容服务器可以直接把指定数据传送给客户机,当然客户机不能识别这种类型的文档可以忽略而不会产生错误。但如果你指明了具体的文档类型,如例程中的text/plain(纯文本类型),客户机就不要再对文档加以分析从而提高了处理速度。否则客户机只知道传送过来的是multipart(复合型)而要重新对其分析。
至于multipart_end涵数不需作详细说明,只是说明了一个PUSH过程的结束。
为了使大家能更好地理解这三个涵数详细的技术内容,我把这三个涵数的实现过程解析给大家:
sub multipart_init {
my($self,@p) = self_or_default(@_);
my($boundary,@other) = $self->rearrange([BOUNDARY],@p);
$boundary = $boundary || '------- =_aaaaaaaaaa0';
$self->{'separator'} = "n--$boundaryn";
$type = SERVER_PUSH($boundary);
return $self->header(
-nph => 1,
-type => $type,
(map { split "=", $_, 2 } @other),
) . $self->multipart_end;
}
sub multipart_start {
my($self,@p) = self_or_default(@_);
my($type,@other) = $self->rearrange([TYPE],@p);
$type = $type || 'text/html';
return $self->header(
-type => $type,
(map { split "=", $_, 2 } @other),
);
}
sub multipart_end {
my($self,@p) = self_or_default(@_);
return $self->{'separator'};
}
用delphi 进行socket连接怎样做?像asp.net做的无刷新聊天室那样