HTTP server push
HTTP server push (also known as HTTP streaming) is a mechanism for sending data from a web server to a web browser. HTTP server push can be achieved through several mechanisms.
Generally the web server does not terminate a connection after response data has been served to a client. The web server leaves the connection open such that if an event is received, it can immediately be sent to one or multiple clients. Otherwise the data would have to be queued until the client's next request is received. Most web servers offer this functionality via CGI (e.g. Non-Parsed Headers scripts on Apache).
Another mechanism is related to a special MIME type calledmultipart/x-mixed-replace
, which was introduced by Netscape in 1995. Web browsers would interpret this as a document changing whenever the server felt like pushing a new version to the client.[1] It is still supported by Firefox, Opera and Safari today, but ignored by Internet Explorer.[2] It can be applied to HTML documents, but also for streaming images in webcam applications.
The WHATWG Web Applications 1.0 proposal[3] included a mechanism to push content to the client. On September 1, 2006, the Opera web browser implemented this new experimental technology in a feature called "Server-Sent Events."[4][5] It is now being standardized as part of HTML5.[6] Another related part of HTML5 is the WebSockets API, which allows a web server and client to communicate over a full-duplex TCP connection.
Many examples of this kind of "server push" could be found by Google. :)
I summarize some pages here.
From 偶素Johnny啦~: Mjpeg On The Http: "第二種方式則是利用了類似Push的,讓Server傳送一個連續的資料給Client端,MIME的Content-Type中有一個特別的定義multipart/x-mixed-replace,當瀏覽器讀到這個類型時不會立即斷線,而會不斷的讀取資料,並且將新的Jpeg貼在原來的位置。但是每張Jpeg之間必須有間隔字串讓瀏覽器可以辨識,boundary就是定義分隔字串,只要是資料內不會出現的文字就可以了。
motionjpeg.html
<img src="myjpeg.cgi" />
myjpeg.cgi輸出的內容
Content-type: multipart/x-mixed-replace; boundary=xxx分隔字串xxx
xxx分隔字串xxx\r\n
Content-Type: image/jpeg\r\n
\r\n
Jpeg檔案內容
\r\n
xxx分隔字串xxx\r\n
Content-Type: image/jpeg\r\n
\r\n
Jpeg檔案內容
...
xxx分隔字串xxx\r\n
Another post from stackoverflow. It got more clear explain and sample code.
use strict;
# turn off io buffering
$|=1;
print "Content-type: multipart/x-mixed-replace;";
print "boundary=magicalboundarystring\n\n";
print "--magicalboundarystring\n";
#list the jpg images
my(@file_list) = glob "*.jpg";
my($file) = "";
foreach $file(@file_list ) {
open FILE,">", $file or die "Cannot open file $file: $!";
print "Content-type: image/jpeg\n\n";
while ( <FILE> )
{
print "$_";
}
close FILE;
print "\n--magicalboundarystring\n";
sleep 3;
next;
}
Another code snippet from Server Push using ISAPIunit uMain;
interface
uses
Windows, Messages, SysUtils, Classes, HTTPApp;
type
TWebModule1 = class(TWebModule)
procedure WebModuleCreate(Sender: TObject);
procedure WebModule1WebActionItem1Action(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
procedure WebModule1waImageAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
private
Boundary : string;
MultipartContentType : string;
{ Private declarations }
public
{ Public declarations }
end;
var
WebModule1: TWebModule1;
implementation
{$R *.DFM}
procedure TWebModule1.WebModuleCreate(Sender: TObject);
begin
Boundary := 'erERT45GSqJtasftnd31Afghdrte6';
MultipartContentType := 'Content-type: multipart/x-mixed-replace';
end;
procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
Request.WriteString('HTTP/1.1 200' #13#10);
Request.WriteString(Format('%s;boundary="%s"'#13#10#13#10, [MultipartContentType, Boundary]));
repeat
Request.WriteString(#13#10 '--' Boundary #13#10);
Request.WriteString('Content-type: text/html' #13#10#13#10);
Request.WriteString('<title>Server Push Example</title>' #13#10);
Request.WriteString('<body>' #13#10);
Request.WriteString('<h3>' FormatDateTime('dddd, dd mmm yyyy hh:nn:ss', Now) '</h3>' #13#10);
Request.WriteString('</body>' #13#10);
Request.WriteString('--' Boundary #13#10);
Sleep(1000);
until (False);
end;
procedure TWebModule1.WebModule1waImageAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
MemStrm : TMemoryStream;
Images : array[0..9] of string;
ImageNo : Integer;
begin
Images[0] := 'C:\Inetpub\wwwroot\images\thumb_1.jpg';
Images[1] := 'C:\Inetpub\wwwroot\images\thumb_2.jpg';
Images[2] := 'C:\Inetpub\wwwroot\images\thumb_3.jpg';
Images[3] := 'C:\Inetpub\wwwroot\images\thumb_4.jpg';
Images[4] := 'C:\Inetpub\wwwroot\images\thumb_5.jpg';
Images[5] := 'C:\Inetpub\wwwroot\images\thumb_6.jpg';
Images[6] := 'C:\Inetpub\wwwroot\images\thumb_7.jpg';
Images[7] := 'C:\Inetpub\wwwroot\images\thumb_8.jpg';
Images[8] := 'C:\Inetpub\wwwroot\images\thumb_9.jpg';
Images[9] := 'C:\Inetpub\wwwroot\images\thumb_10.jpg';
ImageNo := 0;
MemStrm := TMemoryStream.Create;
try
Request.WriteString('HTTP/1.1 200' #13#10);
Request.WriteString(Format('%s;boundary="%s"'#13#10#13#10, [MultipartContentType, Boundary]));
repeat
MemStrm.LoadFromFile(Images[ImageNo]);
MemStrm.Position := 0;
Request.WriteString(#13#10 '--' Boundary #13#10);
Request.WriteString('Content-type: image/jpeg' #13#10#13#10);
Response.SendStream(MemStrm);
Request.WriteString('--' Boundary #13#10);
if ImageNo = High(Images) then
ImageNo := -1;
Inc(ImageNo);
Sleep(1000);
until (False);
finally
MemStrm.Free; {The Web server normally takes care of this }
end;
end;
end.
No comments:
Post a Comment