我要做个软件,以HTTP协议向HTTP服务器发送请求,怎么做啊?(100分)

  • 主题发起人 主题发起人 sunlinglong
  • 开始时间 开始时间
S

sunlinglong

Unregistered / Unconfirmed
GUEST, unregistred user!
哪位老大做过,给点源代码看看,谢谢啦
 
谈Delphi编程中Http协议的应用(一)
关键字: Http协议
分类?: 0
密级?: 参赛
(评分: , 回复: 0, 阅读: 32) ??
参加工作后写的第一篇东西
谈Delphi编程中Http协议的应用(一)

陈经韬

Http协议是TCP协议中的一种,因为有了它,您现在才可以看到这篇文章:)
Http协议的通信遵循一定的约定.例如,请求一个文件的时候先发送Get请求,然后服务器会返回请求的数据.如果需要进行断点传输,那么先发送'HEAD /'请求,其中返回的'Content-Length: '就是文件实际大小.将其和我们本地需要断点下载的文件大小比较,发送GET请求和发送需要下载的文件开始位置'RANGE: bytes='+inttostr(iFilePos)+'-'+#13#10;服务器如果支持断点下载的话就会接着发送余下的数据了.因为这方面的文章比较多,我在这里就不详细讲述了.感兴趣的朋友可以自行查阅相关资料或者RFC文档.我写的"搜霸"就是采用这种方式进行断点下载的.
当然,如果你是个懒人,也可以直接采用Delphi自带的控件.以Delphi6的INDY组件为例.新建一个工程,放上一个TIdHTTP控件,一个TIdAntiFreeze控件,一个TProgressBar用于显示下载进度.最后放上一个TButton用于开始执行我们的命令.代码如下:

procedure TForm1.Button1Click(Sender: TObject);//点击按钮的时候开始下载我们的文件
var
MyStream:TMemoryStream;
begin
IdAntiFreeze1.OnlyWhenIdle:=False;//设置使程序有反应.
MyStream:=TMemoryStream.Create;
try
IdHTTP1.Get('http://www.138soft.com/download/Mp3ToExe.zip',MyStream);//下载我站点的一个ZIP文件
except//INDY控件一般要使用这种try..except结构.
Showmessage('网络出错!');
MyStream.Free;
Exit;
end;
MyStream.SaveToFile('c:/Mp3ToExe.zip');
MyStream.Free;
Showmessage('OK');
end;

procedure TForm1.IdHTTP1WorkBegin(Sender: TObject; AWorkMode: TWorkMode;
const AWorkCountMax: Integer);//开始下载前,将ProgressBar1的最大值设置为需要接收的数据大小.
begin
ProgressBar1.Max:=AWorkCountMax;
ProgressBar1.Min:=0;
ProgressBar1.Position:=0;
end;

procedure TForm1.IdHTTP1Work(Sender: TObject; AWorkMode: TWorkMode;
const AWorkCount: Integer);//接收数据的时候,进度将在ProgressBar1显示出来.
begin
ProgressBar1.Position:=ProgressBar1.Position+AWorkCount;
end;

IdHTTP1的Get还有一种形式就是获取字符串:例如,上面的程序可以改写成:

procedure TForm1.Button1Click(Sender: TObject);
var
MyStr:String;
begin
IdAntiFreeze1.OnlyWhenIdle:=False;//设置使程序有反应.
try
MyStr:=IdHTTP1.Get('http://www.138soft.com/default.htm');
except
Showmessage('网络出错!');
Exit;
end;
Showmessage(MyStr);
end;

应用:现在很多程序都有自动升级功能,实际上就是应用了GET.先在自己站点放一个文本文件注明程序版本号,当检查升级的时候,取文本内容与当前版本号比较,然后决定升级与否.

实际上,GET还可以用在其它方面,前提是与你的网页文件挂钩.例如,你的个人站点放在你的硬盘上面,你在http://my.yeah.net申请了一个免费的域名,你将URL指向你的IP.但是你的IP是动态的,经常会改变,每次改变后需要手工打开http://my.yeah.net站点进行设置是非常麻烦的.这时候,你可以自己动手写一个程序.
首先,我们来写两个函数从返回页面里提取我们需要的信息.

function GetInfoByYearNetHtm1(const str:string):String;
{
功能:从Yeah.Net的域名申请和修改返回网页文件中提取需要的信息
参数:Yeah.Net的网页文件内容
输出:实际的信息
作者:陈经韬
日期:2003,2,8
修改:无
}
const
SubColor='<font color=red>';
SubCenter1='<center>';
SubCenter2='</center>';
var
S:String;
i,j,k:integer;
begin
Result:='';
S:=str;

j:=0;
repeat
i:=Pos(SubColor,LowerCase(S));
if i=0 then break;
if Length(s)<(i+Length(SubColor)-1) then Break;
Delete(S,1,i+Length(SubColor)-1);

i:=Pos(SubCenter1,LowerCase(S));
if i=0 then break else if i<=10 then j:=-1;
until j=-1;

k:=Pos(SubCenter2,LowerCase(S));
S:=Copy(S,i+Length(SubCenter1),k-i-Length(SubCenter1));

k:=0;
repeat
i:=pos('<',s);
j:=pos('>',s);
if (i=0) or (j=0) then Break;
Delete(s,i,j-i+1);
Insert(' ', S, i);
until k=-1;
s:=s+'.';
Result:=s;
end;

function GetInfoByYearNetHtm2(const Str:String):String;
{
功能:从Yeah.Net的域名转向返回网页文件中提取需要的信息
参数:Yeah.Net的网页文件内容
输出:实际的信息
作者:陈经韬
日期:2003,2,8
修改:无
}
var i,j,k:integer;
begin
Result:='';
i:=Pos('url=',Str);
if i=0 then Exit;
i:=i+4;
j:=Pos('',Str);
if i=0 then Exit;
j:=j-2; k:=j-i;
Result:=copy(Str,i,k);
end;

第一步,我们先来实现注册功能.放上五个Edit控件分别代表注册用户名称,密码1,密码2,Email地址和需要指向的URL.然后用GET方式来注册:

procedure TForm1.Button1Click(Sender: TObject);
var
StrRecive:String;
begin
Memo1.Lines.Clear;
Memo1.Lines.Add('正在申请域名!');
try
StrRecive:=IdHTTP1.Get('http://my.yeah.net/cgi-bin/register?username='+Edit1.Text//注册名称
+'&domain=yeah.net'
+'&password='+Edit2.Text//密码1
+'&password2='+Edit3.Text//密码2
+'&email='+Edit4.Text//注册人Email地址
+'&url=http://'+Edit4.Text);//该域名指向的URL
Memo1.Lines.Add(GetInfoByYearNetHtm1(StrRecive));
except
Memo1.Lines.Add('申请域名错误!请检查网络!');
end;
end;

第二步,当你需要更新自己的IP地址的时候:

procedure TForm1.Button2Click(Sender: TObject);
var
StrRecive:String;
begin
Memo1.Lines.Clear;
Memo1.Lines.Add('正在更新域名!');
try
StrRecive:=IdHTTP1.Get('http://my.yeah.net/cgi-bin/modify?username='+Edit1.Text//注册名称
+'&domain=yeah.net'
+'&password='+Edit2.Text//密码1
+'&url=http://'+Edit4.Text);//该域名指向的URL
Memo1.Lines.Add(GetInfoByYearNetHtm1(StrRecive));
except
Memo1.Lines.Add('更新IP错误!请检查网络!');
end;
end;

第三步:当然是你的程序取的真实指向了:)

procedure TForm1.Button3Click(Sender: TObject);
begin
try
Memo1.Lines.Add(GetInfoByYearNetHtm2(IdHTTP1.Get(Edit4.Text)));//eg:http://lovejingtao.yeah.net
except
Memo1.Lines.Add('更新IP错误!请检查网络!');
end;
end;

当然,如果你的程序想写的非常小,那么就要动用API了.大概过程如下:
...........
...........
HeadInfo:='';
HeadInfo:=HeadInfo+'GET /'+''+' HTTP/1.1'+#13#10;
HeadInfo:=HeadInfo+'Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*'+#13#10;

HeadInfo:=HeadInfo+'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705)'+#13#10;
HeadInfo:=HeadInfo+'RANGE: bytes='+inttostr(533263)+'-533263'+#13#10;
HeadInfo:=HeadInfo+'Host: '+GetHost(HostName)+#13#10;
HeadInfo:=HeadInfo+#13#10;
ZeroMemory(@SendStrBuf,SizeOf(SendStrBuf));
for Re:=0 to Length(HeadInfo)-1 do SendStrBuf[Re]:=HeadInfo[Re+1];
Re:=send(MySocket,SendStrBuf,Strlen(SendStrBuf),0);

if Re = SOCKET_ERROR then
begin
CloseSocket(MySocket);
WSACleanUP();//Winsocket释构
Exit;
end;

Re:=recv(MySocket,ReciveStrBuf,SizeOf(ReciveStrBuf),0);
if Re = SOCKET_ERROR then
begin
CloseSocket(MySocket);
WSACleanUP();//Winsocket释构
Exit;
end;
Result:=GetInfoByYearNetHtm2(ReciveStrBuf);
..........
..........

应用:(1)无IP电脑取有IP电脑的地址,就是有IP的电脑把自己的IP更新上去,然后无IP的电脑去取回来连接.两者均是用GET.(2)注册版软件:在网站后台建立一个数据库,软件自动去取ID判断合法与否.现在一般注册软件都采用这种办法.

第一节终于写完了.很久没写技术文档资料,倒是经常写开发文档和公司硬件设备的开发SDK,已经有点生疏了.参加工作后一直都非常忙,今天晚上和小枫去拨火罐,要四小时后才能洗澡,于是坐下来花了半个小时写了这篇东西.希望大家喜欢.实际上,http协议的用途是非常大的.后面的章节讲述的内容可能如下:(1)http隧道的实现:写一个HTTP服务器,实现一些奇特的功能.例如:用IE查看别人的屏幕.遥控别人的电脑等.(2)WEB自动下载程序的三种方法.以及其它一些鲜为人知的应用.什么时候写出来?就要看有没有时间了,更重要的是你们喜欢与否.
2003,9,18凌晨.

作者:陈经韬
主页:http://www.138soft.com
转载请注明出处.谢谢.



 

©CopyRight 2000-2005



2003-9-28 15:19:00
发表评语???




使用INDY的IdMappedPortTCP控件实现动态的HTTP代理服务器
关键字: INDY PROXY HTTP
分类?: 开发技巧
密级?: 参赛
(评分:★★★★★ , 回复: 4, 阅读: 763) ??
在工作中,需要一个时间控制条件非常复杂的代理服务器,因此只能自编。从网络中找到一些用ServerSocket和ClientSocket开发的代理服务器源代码,比较复杂。因此想用INDY控件组中的IdMappedPortTC开发代理服务器。DELPHI附带例子演示的是一个静态的代理,比如例中的www.borland.com,而实际应用中需要的却一个动态的代理。本文即介绍如何使用INDY的IdMappedPortTCP控件实现动态的HTTP代理服务器
分析INDY9所带的源代码,发现NETDATA属性中了存放用户的请求内容和服务器的回复信息,OnExecute事件是在接收到用户请求后与向WEB服务器转发请求之前执行的。因此可以在OnExecute事件写些根据用户的请求更改代理主机的代码,这样就可实现动态代理。
代码如下:
procedure TForm1.IdMappedPortTCP1Execute(AThread: TIdMappedPortThread);
var
RequestHost:string;
RequestPort:integer;
begin
//改变连接
IDLock.Acquire;
try
RequestHost:=GetHost(AThread.NetData);
RequestPort:=GetPort(AThread.NetData);
if (RequestHost<>IdMappedPortTcp1.MappedHost) or
(RequestPort<>IdMappedPortTcp1.MappedPort) then
begin
IdMappedPortTCP1.MappedHost:=RequestHost;
IdMappedPortTCP1.MappedPort:=RequestPort;
TidTcpClient(AThread.OutboundClient).Host:=RequestHost;
TidTcpClient(AThread.OutboundClient).Port:=RequestPort;
TidTcpClient(AThread.OutboundClient).Disconnect;
TidTcpClient(AThread.OutboundClient).Connect(AThread.ConnectTimeOut);
end; //ChangeConnect
finally
IDLock.Release;
end;
end;

实际应用中,访问www.163.com和www.sina.com.cn网站会出现错误,经分析发现需对浏览器的请求格式作些调整,即删除GET请求中的主机名。 在该事件中再加一行改变请求的代码,如下:
//改变请求
AThread.NetData:=DelHostOfURL(AThread.NetData,RequestHost,RequestPort);
上述方法实现HTTP代理服务器非常简单,不信你试试。本次工作的一个重要体会就是分析源代码比看手册资料更有效。
砍死微软,开放源代码万岁!

附:本程序所需的三个自定义函数的代码。
1.获取主机名
function TForm1.GetHost(URL: string):string;
var
LURI:TIdURI;
begin
LURI:=TIdURI.Create(URL);
result:=LURI.Host;
LURI.Free;
end; //GetHost

2.获取端口号
function TForm1.GetPort(URL: string):integer;
var
LURI:TIdURI;
begin
LURI:=TIdURI.Create(URL);
if Length(LURI.Port)<>0 then
result:=StrToInt(LURI.Port)
else
result:=80;
LURI.Free;
end; //GetPort

3.删除URL中的HOST字符串
function TForm1.DelHostOfURL(URL,Host:string;Port:integer):string;
var
s:string;
begin
result:= URL;

s:='http://'+Host;
if Port <> 80 then
s:= s + ':' + IntToStr(Port);

Delete(result,pos(s,result),length(s));
end; //DelHostOfURL






2003-5-19 21:06:00


 
下面是我用TClientSocket连接sms.sina.com.cn发送短信,你需要把密码设置好,就可以用了!
看在100分公布我的组件,里面有通讯的!自己看吧!
{function:short messages service
this is link sms.sina.com.cn website;
author:dcs
date:2002-12-25
}
unit smstomdcs;

interface

uses
Windows, Messages, SysUtils, Classes,ScktComp;

type
Tsmstomdcs = class(Tcomponent)
private
fcs:TClientSocket;
fhandno:string;//手机号码
fpassword:string;//网站的密码
fstrlist:TstringList;
ftttt:TstringList;
fsendcontent:string;
fsendhandno:string;
frecstr:string;//recevide string
procedure csConnect(Sender: TObject; Socket: TCustomWinSocket);
procedure csRead(Sender:TObject;Socket:TCustomWinSocket);
procedure csDisconnect(Sender: TObject; Socket: TCustomWinSocket);
procedure csError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);//各种错误
protected
procedure sethandno(Value:string);
procedure setpassword(Value:string);
procedure setsendcontent(Value:string);
procedure setsendhandno(Value:string);
procedure s_open;
public
errormaket:boolean;
tid:integer;
constructor Create(AOwner: TComponent);override;
destructor destroy;override;
procedure p_send;
function isconnected:boolean;
published
property sendhandno:string read fsendhandno write Setsendhandno;
property sendcontent:string read fsendcontent write setsendcontent;
property handno:string read fhandno write sethandno;
property password:string read fpassword write setpassword;
end;

procedure Register;
{$define dcsdebug_off}
implementation
uses unit1;
function Tsmstomdcs.isconnected:boolean;
begin
result:=fcs.Active;
end;
procedure Tsmstomdcs.s_open;
begin
errormaket:=false;
fcs.Open;
end;
procedure Tsmstomdcs.p_send;
begin
if ((length(fsendhandno)=11) and (copy(fsendhandno,1,2)='13')) then
s_open;
end;
procedure Tsmstomdcs.csConnect(Sender: TObject; Socket: TCustomWinSocket);
var
tmpstr:string;
i:integer;
begin
frecstr:='';
tmpstr:='';
for i:=1 to length(fsendcontent) do
begin
if ord(fsendcontent)>127 then
tmpstr:=tmpstr+'%'+inttohex(ord(fsendcontent),2)
else
tmpstr:=tmpstr+fsendcontent;
end;
tmpstr:='sname=&msg='+tmpstr+'&mob1='+fsendhandno+'&login=1&user='+fhandno+'&passwd='+fpassword;
tmpstr:=format('%sContent-Length:%d%s%s%s',[fstrlist.text,length(tmpstr),#13#10#13#10,tmpstr,#13#10]);
{$ifdef dcsdebug}
ftttt.clear;
ftttt.Add(tmpstr);
ftttt.savetofile('c:/dcs1.txt');
{$endif}
fcs.Socket.SendText(tmpstr);
end;
procedure Tsmstomdcs.csDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
{$ifdef dcsdebug}
ftttt.clear;
ftttt.Add(frecstr);
ftttt.savetofile('c:/dcs.txt');
{$endif}
if pos('成功',frecstr)>0 then
errormaket:=false
else
errormaket:=true;
end;
procedure Tsmstomdcs.csError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
{if ((ErrorEvent=eeConnect) and (ErrorCode=10061)) then
showmessage('连接错误!')
else
showmessage('其他错误!'); }
errormaket:=true;
ErrorCode:=0;
fcs.Close;
end;
procedure Tsmstomdcs.csRead(Sender:TObject;Socket:TCustomWinSocket);
begin
//数据到达;
frecstr:=frecstr+Socket.ReceiveText;
end;
procedure Tsmstomdcs.sethandno(Value:string);
begin
fhandno:=Value;
end;
procedure Tsmstomdcs.setpassword(Value:string);
begin
fpassword:=Value;
end;
procedure Tsmstomdcs.setsendcontent(Value:string);
begin
fsendcontent:=Value;
end;
procedure Tsmstomdcs.setsendhandno(Value:string);
begin
fsendhandno:=Value;
end;
constructor Tsmstomdcs.Create(AOwner: TComponent);
begin
inherited;
fcs:=TClientSocket.create(AOwner);
fcs.Host:='sms.sina.com.cn';
fcs.Port:=80;
fstrList:=TstringList.create;
ftttt:=TstringList.Create;
fcs.OnConnect:=csConnect;
fcs.OnRead:=csRead;
fcs.OnDisconnect:=csDisconnect;
fcs.OnError:=csError;
fhandno:='1390000000';
fpassword:='0000';
errormaket:=false;
fstrList.add('POST http://sms.sina.com.cn/cgi-bin/sms/send.cgi HTTP/1.0');
fstrList.add('Accept:*/*');
fstrList.add('Accept-Language: zh-cn');
fstrList.add('Content-Type: application/x-www-form-urlencoded');
fstrList.add('Accept-Encoding: gzip, deflate');
fstrList.add('User-Agent: Mo_dcs/9.0');
fstrList.add('Host: sms.sina.com.cn');
fstrList.add('Cookie: SMSLOGIN=0; USRTYPE=C');
fstrList.add('Pragma: no-cache');
end;
destructor Tsmstomdcs.destroy;
begin
if fcs.Active then
fcs.close;
fcs.free;
fstrlist.Free;
ftttt.Free;
inherited;
end;
procedure Register;
begin
RegisterComponents('Samples', [Tsmstomdcs]);
end;
end.
 
后退
顶部