由 TIdTCPServer 提供客户端安装程序 WEB 下载的实现方法
2007-05-17 16:05
901 查看
相信众多的 TCP 网络服务器,均是由 TIdTCPServer 来提供服务,我的《网络存储服务器》也是。
即然是TCP服务器,若是需要相应的客户端来支持,那么,由这个服务端口(TCP)直接来提供客户端安装程序 WEB 下载是不是变得很方便?再也不用另加一个TIdHTTPServer来做了, 当然,若是需要提供 WEB 管理,还得麻烦他老人家。
HTTP协议:
在 IE 由 http://127.0.0.1:3001 连接到这个端口(Port=3001)时,发过来以下内容:
GET / HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322)
Host: 127.0.0.1:3001
Connection: Keep-Alive
Cookie: iscookies=0
只有第一行才是我所需要的并且是有用的,后面的可省略,假定下载的客户端安装程序文件名是 ClientSetup.exe, 此时提供下载时,IE 会有不知道是什么文件的麻烦,因此必须将客户端IE地址改成 http://127.0.0.1:3001/ClientSetup.exe 他才能知道是什么文件与文件名,通常是采用J***A网页转向技术(见后面的代码)。
GET /ClientSetup.exe HTTP/1.1
...... 下面的省略
其他服务器应回应 IE 的内容,见下面:
// TIdTCPServer * IdTcpServer 的 OnExecute 事件处理函数
void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
...{
AnsiString ReadLn;
TIdIOHandler * IOHandler = AContext->Connection->IOHandler;
try
...{
while (IdTCPServer->Active)
...{
ReadLn = IOHandler->ReadLn();
if (ReadLn.Length())
if (ReadLn.Pos("GET ") == 1)
...{
ReadLn.SetLength(ReadLn.Pos(" HTTP/")-1);
ReadLn.Delete(1, 4); // 删除前面的 GET 与空格
while (IOHandler->ReadLn().Length()); // 读取完后面的内容
if (!FileExixts("ClientSetup.exe"))
...{
AnsiString HTML = "<HTML> <HEAD> ";
HTML += "<script LANGUAGE="JavaScript"> ";
HTML += "function closeit() {";
HTML += "setTimeout("self.close()",10000)"; //
HTML += "} ";
HTML += "closeit()";
HTML += "</script> ";
HTML += "</HEAD> ";
HTML += "<BODY>客户端安装程序不存在,正在关闭窗口...</BODY> ";
HTML += "</HTML>";
ReadLn = "HTTP/1.1 200 OK ";
ReadLn += "Server: Goldray Network Storage Server 2.0 ";
ReadLn += "Date: " + DateTimeToHTTPFormat(Now()) + " ";
ReadLn += "Content-Length: " + IntToStr(HTML.Length()) + " ";
ReadLn += "Content-Type: text/html ";
ReadLn += "Expires: " + DateTimeToHTTPFormat(Now()) + " ";
ReadLn += "Set-Cookie: path=/ ";
ReadLn += "Cache-control: no-cache";
IOHandler->WriteLn(ReadLn);
IOHandler->WriteLn();
Sleep(100);
IOHandler->WriteLn(HTML);
IOHandler->WriteLn();
}
else if (ReadLn.UpperCase() == "/CLIENTSETUP.EXE")
...{
ReadLn = "HTTP/1.1 200 OK ";
ReadLn += "Server: Goldray Network Storage Server 2.0 ";
ReadLn += "Date: " + DateTimeToHTTPFormat(Now()) + " ";
ReadLn += "Content-Type: application/octet-stream ";
ReadLn += "Accept-Ranges: bytes ";
ReadLn += "Last-Modified: ";
ReadLn += DateTimeToHTTPFormat(FileDateToDateTime(FileAge("ClientSetup.exe")));
ReadLn += " ";
ReadLn += "Content-Length: " + IntToStr(FileGetSize("ClientSetup.exe"));
IOHandler->WriteLn(ReadLn); // 发送HTTP前导
IOHandler->WriteLn();
IOHandler->WriteFile("ClientSetup.exe");
Sleep(100);
AContext->Connection->Disconnect(); // 断开吧,已经不需要了
break;
}
else // 若 IE 不是 http://......./ClientSetup.exe 读取的,总是转向这里
...{
AnsiString HTML = "<HTML> <HEAD> ";
HTML += "<script LANGUAGE="JavaScript"> ";
HTML += "<!-- ";
HTML += "window.location="http://";
HTML += AContext->Binding()->IP + ":";
HTML += IntToStr(AContext->Binding()->Port) + "/ClientSetup.exe" ";
HTML += "// --> ";
HTML += "</script> ";
HTML += "</HEAD> ";
HTML += "<BODY>正在转向客户端下载,请稍候...</BODY> ";
HTML += "</HTML>";
ReadLn = "HTTP/1.1 200 OK ";
ReadLn += "Server: Goldray Network Storage Server 2.0 ";
ReadLn += "Date: " + DateTimeToHTTPFormat(Now()) + " ";
ReadLn += "Content-Length: " + IntToStr(HTML.Length()) + " ";
ReadLn += "Content-Type: text/html ";
ReadLn += "Expires: " + DateTimeToHTTPFormat(Now()) + " ";
ReadLn += "Set-Cookie: path=/ ";
ReadLn += "Cache-control: no-cache";
IOHandler->WriteLn(ReadLn);
IOHandler->WriteLn();
Sleep(100);
IOHandler->WriteLn(HTML);
IOHandler->WriteLn();
}
}
else
...{
// ... 这里才是你的 TCP 服务器指令处理过程
}
}
}
catch (...)
...{
Sleep(100);
}
}
当然,实际使用时建议文件名使用含路径的全称, 使用变量是不错的选择。
哦,还小了两个函数,一并附上:
// HTML 回应时间必须是 GMT 格式
AnsiString DateTimeToHTTPFormat(TDateTime ADateTime)
...{
TSystemTime GMTTime;
TFileTime DT;
DateTimeToSystemTime(ADateTime, GMTTime);
SystemTimeToFileTime(&GMTTime, &DT);
LocalFileTimeToFileTime(&DT, &DT);
FileTimeToSystemTime(&DT, &GMTTime);
AnsiString wdays[7] = ...{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
AnsiString monthnames[12] = ...{"Jan", "Feb", "Mar", "Apr", "May",
"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
AnsiString Result = wdays[GMTTime.wDayOfWeek];
Result += ", ";
TVarRec argd[1] = ...{GMTTime.wDay};
TVarRec args[4] = ...{GMTTime.wYear, GMTTime.wHour, GMTTime.wMinute, GMTTime.wSecond};
Result += Format("%.2d ", argd, 0);
Result += monthnames[GMTTime.wMonth-1];
Result += Format(" %.4d %.2d:%.2d:%.2d", args, 3);
Result += " GMT";
return Result;
}
下面的代码,网上到处都是啦,也就来凑一下字数吧
// 取文件大小
#include <stdio.h>
__int64 __fastcall FileGetSize(AnsiString AFileName)
...{
__int64 fSize = 0;
if (FileExists(AFileName))
...{
FILE * fp = fopen(AFileName.c_str(),"rb");
if(fp)
...{
fseek(fp,0,SEEK_END);
fSize = ftell(fp);
fclose(fp);
}
}
return fSize;
}
以上程序在 C++Builder 2006 + Indy10 下通过。
即然是TCP服务器,若是需要相应的客户端来支持,那么,由这个服务端口(TCP)直接来提供客户端安装程序 WEB 下载是不是变得很方便?再也不用另加一个TIdHTTPServer来做了, 当然,若是需要提供 WEB 管理,还得麻烦他老人家。
HTTP协议:
在 IE 由 http://127.0.0.1:3001 连接到这个端口(Port=3001)时,发过来以下内容:
GET / HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322)
Host: 127.0.0.1:3001
Connection: Keep-Alive
Cookie: iscookies=0
只有第一行才是我所需要的并且是有用的,后面的可省略,假定下载的客户端安装程序文件名是 ClientSetup.exe, 此时提供下载时,IE 会有不知道是什么文件的麻烦,因此必须将客户端IE地址改成 http://127.0.0.1:3001/ClientSetup.exe 他才能知道是什么文件与文件名,通常是采用J***A网页转向技术(见后面的代码)。
GET /ClientSetup.exe HTTP/1.1
...... 下面的省略
其他服务器应回应 IE 的内容,见下面:
// TIdTCPServer * IdTcpServer 的 OnExecute 事件处理函数
void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
...{
AnsiString ReadLn;
TIdIOHandler * IOHandler = AContext->Connection->IOHandler;
try
...{
while (IdTCPServer->Active)
...{
ReadLn = IOHandler->ReadLn();
if (ReadLn.Length())
if (ReadLn.Pos("GET ") == 1)
...{
ReadLn.SetLength(ReadLn.Pos(" HTTP/")-1);
ReadLn.Delete(1, 4); // 删除前面的 GET 与空格
while (IOHandler->ReadLn().Length()); // 读取完后面的内容
if (!FileExixts("ClientSetup.exe"))
...{
AnsiString HTML = "<HTML> <HEAD> ";
HTML += "<script LANGUAGE="JavaScript"> ";
HTML += "function closeit() {";
HTML += "setTimeout("self.close()",10000)"; //
HTML += "} ";
HTML += "closeit()";
HTML += "</script> ";
HTML += "</HEAD> ";
HTML += "<BODY>客户端安装程序不存在,正在关闭窗口...</BODY> ";
HTML += "</HTML>";
ReadLn = "HTTP/1.1 200 OK ";
ReadLn += "Server: Goldray Network Storage Server 2.0 ";
ReadLn += "Date: " + DateTimeToHTTPFormat(Now()) + " ";
ReadLn += "Content-Length: " + IntToStr(HTML.Length()) + " ";
ReadLn += "Content-Type: text/html ";
ReadLn += "Expires: " + DateTimeToHTTPFormat(Now()) + " ";
ReadLn += "Set-Cookie: path=/ ";
ReadLn += "Cache-control: no-cache";
IOHandler->WriteLn(ReadLn);
IOHandler->WriteLn();
Sleep(100);
IOHandler->WriteLn(HTML);
IOHandler->WriteLn();
}
else if (ReadLn.UpperCase() == "/CLIENTSETUP.EXE")
...{
ReadLn = "HTTP/1.1 200 OK ";
ReadLn += "Server: Goldray Network Storage Server 2.0 ";
ReadLn += "Date: " + DateTimeToHTTPFormat(Now()) + " ";
ReadLn += "Content-Type: application/octet-stream ";
ReadLn += "Accept-Ranges: bytes ";
ReadLn += "Last-Modified: ";
ReadLn += DateTimeToHTTPFormat(FileDateToDateTime(FileAge("ClientSetup.exe")));
ReadLn += " ";
ReadLn += "Content-Length: " + IntToStr(FileGetSize("ClientSetup.exe"));
IOHandler->WriteLn(ReadLn); // 发送HTTP前导
IOHandler->WriteLn();
IOHandler->WriteFile("ClientSetup.exe");
Sleep(100);
AContext->Connection->Disconnect(); // 断开吧,已经不需要了
break;
}
else // 若 IE 不是 http://......./ClientSetup.exe 读取的,总是转向这里
...{
AnsiString HTML = "<HTML> <HEAD> ";
HTML += "<script LANGUAGE="JavaScript"> ";
HTML += "<!-- ";
HTML += "window.location="http://";
HTML += AContext->Binding()->IP + ":";
HTML += IntToStr(AContext->Binding()->Port) + "/ClientSetup.exe" ";
HTML += "// --> ";
HTML += "</script> ";
HTML += "</HEAD> ";
HTML += "<BODY>正在转向客户端下载,请稍候...</BODY> ";
HTML += "</HTML>";
ReadLn = "HTTP/1.1 200 OK ";
ReadLn += "Server: Goldray Network Storage Server 2.0 ";
ReadLn += "Date: " + DateTimeToHTTPFormat(Now()) + " ";
ReadLn += "Content-Length: " + IntToStr(HTML.Length()) + " ";
ReadLn += "Content-Type: text/html ";
ReadLn += "Expires: " + DateTimeToHTTPFormat(Now()) + " ";
ReadLn += "Set-Cookie: path=/ ";
ReadLn += "Cache-control: no-cache";
IOHandler->WriteLn(ReadLn);
IOHandler->WriteLn();
Sleep(100);
IOHandler->WriteLn(HTML);
IOHandler->WriteLn();
}
}
else
...{
// ... 这里才是你的 TCP 服务器指令处理过程
}
}
}
catch (...)
...{
Sleep(100);
}
}
当然,实际使用时建议文件名使用含路径的全称, 使用变量是不错的选择。
哦,还小了两个函数,一并附上:
// HTML 回应时间必须是 GMT 格式
AnsiString DateTimeToHTTPFormat(TDateTime ADateTime)
...{
TSystemTime GMTTime;
TFileTime DT;
DateTimeToSystemTime(ADateTime, GMTTime);
SystemTimeToFileTime(&GMTTime, &DT);
LocalFileTimeToFileTime(&DT, &DT);
FileTimeToSystemTime(&DT, &GMTTime);
AnsiString wdays[7] = ...{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
AnsiString monthnames[12] = ...{"Jan", "Feb", "Mar", "Apr", "May",
"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
AnsiString Result = wdays[GMTTime.wDayOfWeek];
Result += ", ";
TVarRec argd[1] = ...{GMTTime.wDay};
TVarRec args[4] = ...{GMTTime.wYear, GMTTime.wHour, GMTTime.wMinute, GMTTime.wSecond};
Result += Format("%.2d ", argd, 0);
Result += monthnames[GMTTime.wMonth-1];
Result += Format(" %.4d %.2d:%.2d:%.2d", args, 3);
Result += " GMT";
return Result;
}
下面的代码,网上到处都是啦,也就来凑一下字数吧
// 取文件大小
#include <stdio.h>
__int64 __fastcall FileGetSize(AnsiString AFileName)
...{
__int64 fSize = 0;
if (FileExists(AFileName))
...{
FILE * fp = fopen(AFileName.c_str(),"rb");
if(fp)
...{
fseek(fp,0,SEEK_END);
fSize = ftell(fp);
fclose(fp);
}
}
return fSize;
}
以上程序在 C++Builder 2006 + Indy10 下通过。
相关文章推荐
- Android客户端apk自动检测更新自动下载自动安装的实现方法
- 关于web程序调试相关工具谷歌访问助手,和测试 POST 请求客户端工具,Advanced REST Client的下载和安装
- server 2003 安装 VS 2003 遇到的问题 :安装frontpage 2000 web 客户端 和 安装程序运行时文件 失败
- FastDFS详细安装步骤,测试;Nginx中配置FastDFS,并提供优化,下载方法,楼主已测
- Web服务器文件传输程序客户端程序实现
- 利用eWebEditor提供的Client API实现在客户端与编辑器的交互(转自http://www.ewebeditor.net/documentation/)
- spring+jpg环境下,spring实现文件下载web实现通用的文件下载方法
- Win7上安装32位Oracle客户端错误解决方法:[INS-30131] 执行安装程序验证所需的初始设置失败
- C#:一个增强的TcpClient(*)客户端演示程序及源代码下载
- Guacamole安装step by step,实现基于web的vnc客户端
- 简单实现WEB程序在线安装 (附源码)
- 实现支持断点续传多线程下载的 Http Web 客户端工具类()
- 实现支持断点续传多线程下载的 Http Web 客户端工具类
- 利用WinForm 更好的实现Web安装程序的更多功能
- 389 Directory Server RHEL 6.0以下客户端安装方法
- centos中安装tomcat7,并实现web程序的热部署
- 简易游戏修改器(C#实现,提供程序下载)
- JS实现 浏览器判断本地是否安装程序,并下载与启动 Chrome,IE,360可用
- 为了在本机上测试,必须先安装memcache的服务器端,安装文件见附件,只能在Administrator用户下才能启动memcached服务。 首先要下载memcache的客户端java实现的jar
- SVN--下载、安装VisualSVN server 服务端和 TortoiseSVN客户端