您的位置:首页 > 理论基础 > 计算机网络

由 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 下通过。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐