怎么得到TStreamword里面怎么打勾的内容

> 怎么实现复制和全选CppWebBrowser 内容功能,通过自己定义的菜单
怎么实现复制和全选CppWebBrowser 内容功能,通过自己定义的菜单
发布时间: & &
浏览:6 & &
回复:1 & &
悬赏:0.0希赛币
如何实现复制和全选CppWebBrowser 内容功能,通过自己定义的菜单。CppWebBrowser
我是用 & TStreamAdapter & 类实现的载入流功能,但不知不执行 & delete & sa & 会不会造成内存泄露,还有就是
SendMessage(CppWebBrowser1-& Handle,WM_COPY,0,0);
SendMessage(CppWebBrowser1-& Handle,EM_SETSEL,0,-1);
两条指令无法实现复制和全选CppWebBrowser & 功能,不知还有什么别的好办法。在这里先谢谢了。
TMemoryStream & *pstream & =new & TMemoryStream();
pstream-& Write(cnt.c_str(),cnt.Length());
pstream-& Seek(0,0);
sa & = & new & TStreamAdapter(pstream,soReference);
// & 初始化文档.
hr & = & pPersistStreamInit-& InitNew();
if & ( & SUCCEEDED(hr) & )
// & 载入流内容
hr & = & pPersistStreamInit-& Load((IStream*)*sa); &
pPersistStreamInit-& Release();
//delete &
CppWebBrowser-& ExecWB(Shdocvw_tlb::OLECMDID_SELECTALL,Shdocvw_tlb::OLECMDEXECOPT_DODEFAULT,NULL,NULL);
CppWebBrowser-& ExecWB(Shdocvw_tlb::OLECMDID_COPY,Shdocvw_tlb::OLECMDEXECOPT_DODEFAULT,NULL,NULL);hahaaj_ & &
15:31:37 & &
& & (0)(0)引用
本问题标题:
本问题地址:
温馨提示:本问答中心的任何言论仅代表发言者个人的观点,与希赛网立场无关。请对您的言论负责,遵守中华人民共和国有关法律、法规。如果您的言论违反希赛网问答中心的规则,将会被删除。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&Intranet与Internet
第16章& Intranet与Internet编程
最早出现的网络协议分为两个集合,二者一同出现,分别是TCP和IP。TCP(传输控制协议)和IP(网际协议)通过协作,在局域网、内部网、外部网和Internet连接之上提供了一个逻辑层。局域网是计算机通过导线和网卡(NIC卡)在物理上连接起来,或像我家里和办公室那样,通过无线连接。楼下供孩子用的计算机使用AirEzy
2405无线收发器,使得地下室中的计算机可以连接到我办公室的局域网,进而又连接到Internet。这样孩子们可以上网冲浪、玩Half
Life游戏;而其他工作也可以同时进行。
TCP协议并未涉及过多细节,其中包括了对报文头的描述,可以使数据在网络上漫游。TCP协议会维护状态信息,使得连接的两端可以相互了解。IP协议向报文添加了特定的头部信息,用于对点分IP地址进行分类和解析。例如,198.109.162.177与域名相关联。我的ISP服务提供商向DNS(域名服务器)添加了一个名字项,将与198.109.162.17关联起来。当向我的网站收发信息时,IP数据报中包括了寻址信息。在数据包由工作站移动到集线器再移动到网络服务器,通过铜缆调制解调器(经AT&T许可),再经过路由器和其他服务器的过程中,TCP和IP协议定义了跟踪数据的手段。
其他协议如Gopher等在TCP/IP出现之前很流行,在TCP/IP层之上还有其他基于TCP/IP的协议,这些协议都是具有特定用途的。例如,FTP(File
Transfer Protocol,文件传输协议)用于方便网络上的文件传输。UDP(User Datagram
Packet,用户数据报)协议是无连接的,它由TCP/IP发展而来,并不维护客户与服务器之间的连接信息,它在某些方面非常有用,如流类型的媒体,其中有一些报文丢失是可以接受的。
如果想要深入了解各种协议的细节,包括TCP/IP、FTP、UDP、Gopher等等,可能需要找一本书来看看,如Que出版的《Using
TCP/IP》,作者是John Ray。另一种方法是,可以查找特定的RFC(Request For
Comment)和白皮书,来阅读有关特定协议的所有细节。本章并不讲述有关协议的底层细节,但您可以学到如何使用Delphi提供的各种组件和类,对大多数常见的协议进行编程。Delphi
6中新增了来自Nevrona的Internet
Direct组件。除了前一版本的Delphi提供的Internet和Fastnet组件之外,在Internet
Direct或Indy中包括了许多客户和服务器端的组件来支持TCP/IP、UDP、Echo、Finger、Gopher、HTTP、POP3、SMTP,NNTP和Telnet等协议。对特定协议内容的简要评论可能较为有用,除此之外,本章还将示范许多新的客户和服务器端组件。到本章结束,通过使用这些强大的组件,您可以学到大量Internet和内部网编程技术,还可以在实例程序中很好的实践一下。
16.1& 传输控制协议(TCP)组件
组件面板Indy Clients和Indy
Servers属性页上的IdTCPClient和IdTCPServer组件直接支持TCP协议,而Internet属性页上来自Borland公司的TcpClient和TcpServer组件也同样支持该协议。由于支持TCP的Indy组件较新,本节我们将把注意力集中于它们。请记住,两对组件都支持同一协议,而每对组件都可以用TCP编程;而Nevrona和Borland的组件可能在特定的名字和特性上不同。
注意:所有的Internet Direct(Indy)组件都以Id为前缀。
16.1.1& Indy客户端TCP组件
通过给出服务器的主机名或IP地址,以及服务器程序所监听的端口号,一个TCP客户程序即可连接到TCP服务器。对于Internet或HTTP来说,服务器程序的通用端口号是80。其他已分配的通用端口号包括:FTP协议20和21,Telnet协议23,SMTP协议25,Gopher协议70,POP3协议110。在命令行运行netstat.exe,即可确定系统使用的所有端口号。下面的列表包括了在我的工作站上使用的一部分端口。
注意:在巴隆计算机术语词典中,将端口定义为CPU与另一设备(非内存)之间的连接,信息可以通过该连接出入计算机。虽然该定义没有达到非常令人不满的程度,但端口确实是一个被滥用的术语。将一根5型电缆插入到网络接口卡中,插口也可称为端口。对我们的目的而言,端口是微处理器与物理设备之间的一个微小的物理连接。端口号告诉CPU向何处发送数据。扬声器的端口号是$61。在向端口$61发送比特值0和1之后,扬声器将发出稳定的蜂鸣声。而发送另一个值清除01比特,就关掉扬声器。下面的步骤示范了直接向扬声器端口发送数据的过程。
1.打开命令行窗口。
2.在命令行进入Debug,运行Debug程序。
3.Debug程序使用短划线(-)作为命令提示符。在Debug命令提示符后键入o61,3,并敲回车键。
4.然后可以听到扬声器发出蜂鸣声。键入o61,0将关掉扬声器。这些指令将直接从微处理器发送到61端口。
Active Connections
Proto Local Address Foreign Address
&&&&&&&&&&&&
&&ptk800:1025&&
SCI.TCIMET.NET:nbsession
ESTABLISHED
ptk800:1482&&
64.124.41.:8888 ESTABLISHED
ptk800:1621&& SCI.TCIMET.NET:1046
&&&&&&&&&&&
ESTABLISHED
TCP& & ptk800:1625
& SCI.TCIMET.NET:1072
&&&&&&&&&&&
ESTABLISHED
TCP& & ptk800:1630
& SCI.TCIMET.NET:1046
&&&&&&&&&&&
ESTABLISHED
TCP& & ptk800:1634
& SCI.TCIMET.NET:1072
&&&&&&&&&&&
ESTABLISHED
TCP& & ptk800:1636
& SCI.TCIMET.NET:nbsession
ESTABLISHED
TCP& & ptk800:1026
& LocalHost:1029
&&&&&&&&&&&&&&&&
ESTABLISHED
TCP& & ptk800:1029
& LocalHost:1026
&&&&&&&&&&&&&&&&
ESTABLISHED
即使没有Web服务器来测试应用程序也不要担心;可以使用LocalHost——127.0.0.1——地址来测试客户和服务器程序。另外,也可以建立测试专用的Web服务器,在Windows
NT下可以从Network Applet(控制面板中的网络设置)中安装Peer Web Server,而Windows
98中可以安装Personal Web Server。要在使用Windows NT的计算机上安装Peer Web
Server,打开控制面板上的Network
Applet。然后转到Services属性页,单击Add按钮。安装过程可能需要Windows NT光盘以完成安装。
netstat输出的第二栏中是本地计算机名,后接端口号;第三个栏目是远程计算机,或接收主机和端口号,后接状态。当Foreign
Address栏中显示LocalHost时,指的是IP地址127.0.0.1,即所谓的loopback地址,PC机可以使用该地址引用其自身。LocalHost的URL是IP地址127.0.0.1。
注意:由于某些原因,使得运行Peer Web
Server是个好主意。首先,规模较小的Web服务器可以成为很好的单元测试平台;其次,它可以迅速而简易地建立起内部网的网站,用于在公司内与您的项目有关的人共享信息。它对于团队开发是既有价值又较为廉价的工具。
IdTCPClient——Internet Direct TCP客户组件,位于组件面板的Indy
Clients属性页上;要测试该组件,需要完成下列步骤并添加列出的代码。
1.Windows NT下,在控制面板的Network Applet中添加Peer Web Server(Windows
9x下使用Personal Web
Server)。默认情况下,该服务器将使用LocalHost地址的80端口以及default.htm页面。
2.启动Delphi,向默认的空白窗体添加TIdTCPClient组件。
3.向窗体添加TMemo组件,可在其中放置TCP连接的输出。
4.向FormCreate事件处理程序添加下列代码。
procedure TForm1.FormCreate( Sender : TObject );
IdTCPClient1.Host := '127.0.0.1';
IdTCPClient1.Port := 80;
IdTCPClient1.C
IdTCPClient1.SendCmd('GET /default.htm' );
Memo1.Lines.Add( IdTCPClient1.CurrentReadBuffer );
IdTCPClient1.D
警告:如果为TIdTCPClient.OnStatus编写事件处理程序,需要手工向uses组件添加IdStatus,在该单元中包括了TIdTCPClient.OnStatus事件方法,否则将出现编译错误(当您阅读到这里时,该问题可能已经解决)。
代码的第一行将主机的IP地址定义为字符串。可以使用TIPAddress组件,它可以方便地从用户输入得到IP地址。第二行包含了端口号。对于HTTP协议,通常是80端口,但如果要通过代理服务器,可能是别的端口号,像8080。第三行使用指定的端口号连接到服务器。SendCmd方法向进行响应的服务器发送合适的字符串。GET和POST对于HTTP服务器来说是合适的。命令字符串是否合适是依赖于协议的,例如对于21端口上的FTP协议,其他的命令如LIST可能较为合适。如果要建立支持某个特定协议的程序,可能需要子类化客户和服务器组件,以通过非基于文本的命令集。
如果在运行这个简单的示例时出现问题,可以打开Windows
NT任务管理器并确认inetinfo.exe已经出现在进程列表中。如果inetinfo.exe(即Peer Web
Services)已经运行,可以打开Internet Service Manager(从开始菜单中选择Start | Program
Files | Micorsoft Peer Web Services | Internet Service
Manager即可)。然后确认TCP端口和Home目录(见图16.1)。在安装Peer Web
Services后Web、FTP和Gopher程序被注册为服务程序。在系统启动时,这些程序自动启动。可以使用Internet
Service Manager或Services Applet(如图16.2所示)来停止这些服务。也可以使用Services
Applet使这些服务在启动时自动运行;如果您在使用内部网,您可能希望这样设置。
图16.1& Web Services Properties对话框可以配置
Peer Web Server,或确认端口和目录信息
图16.2& Peer Web Services在Windows NT中作为服务运行,
默认情况下,在Windows启动时,该服务将自动启动
在本书的CD-ROM中包括了TCPClient程序的一个稍加完善的版本,TCPClient.dpr。TCPClient程序并不限于使用HTTP服务器。许多通用的协议是基于TCP的,这意味着您可以使用同一TCPClient程序连接到特定类型的服务器。对前面的代码稍加修改,即可连接到FTP服务。
IdTCPClient1.Host := '127.0.0.1';
IdTCPClient1.Port := 21;
IdTCPClient1.C
IdTCPClient1.SendCmd('USER anonymous');
IdTCPClient1.SendCmd('PASS ');
IdTCPClient1.SendCmd('HELP' );
Memo1.Lines.Add( IdTCPClient1.CurrentReadBuffer );
IdTCPClient1.D
提示:关于TCP协议的更多知识,可以阅读RFC 0793,位于http://sunsite.
iisc.ernet.in/collection/rfc/rfc0793.html。
列出的代码假定您已经安装了FTP服务和Peer Web
Services,并在默认情况下允许匿名登录(您也可以在Microsoft Internet Service
Manager中确认FTP服务的设置)。通常,您可能觉得特定协议的客户和服务器组件比一般的TCP组件更容易使用。
16.1.2& Indy服务器TCP组件
IdTCPServer组件可用于创建TCP服务器程序。TCP服务器组件绑定到一个服务器端口,例如8080,通过响应OnExecute事件在该端口上接收TCP客户请求。例如,如果TCP客户程序使用WriteLn向服务器发送文本,然后即可用OnExecute方法的AThread参数读出客户发送的文本(TIdUDPServer组件的使用可以参见下一节,特性和方法都非常相似)。
表16.1列出了TIdTCPServer组件值得注意的特性。
TIdTCPServer组件的特性。设置Bindings特性(IP:Port)、DefaultPort和
Active状态,即可通过传递给OnExecute方法的TIdPeerThread对象接收客户请求
AcceptWait
对客户连接的超时等待时间
布尔值,表示服务器是否处于激活状态
IP:Port格式的地址字符串,表示服务器所监听的IP地址和端口号
DefautlPort
监听客户连接的默认端口号
对TIdServerInterceptOpenSSL组件的引用,该组件接收发送到TIdTCPServer组件的数据
对线程管理器集合的引用,其中包括了引用客户连接的线程对象的列表
如果要在端口9090创建一个响应客户的服务器程序,需要将DefaultPort特性设置为9090,并把Active特性设置为True。设置好特性后,使用OnExecute事件处理程序和TIdPeerThread参数即可与客户程序进行通信。例如,读出客户程序发送的文本字符串,可使用下列代码:
procedure TForm1.IdTCPServer1Execute(AThread:
TIdPeerThread);
ShowMessage( AThread.Connection.ReadLnWait );
TCP服务器组件的事件处理程序IdTCPServer1.OnExecute是通过TIdPeerThread对象的一个实例来调用的。AThread参数中包括了对进行调用TIdTCPServerConnection实例的引用,TIdTCPServerConnection由TIdTCPConnection子类化而来。TIdTCPConnection中包含了发送和接收文本格式数据、字符串命令或TStream对象的方法,还可以检测TCP组件的连接状态。
16.2& 用户数据报(UDP)组件
UDP协议由TCP协议衍生而来。TCP用于确保点对点的连接,而UDP并不保证发送的数据一定到达,也不表明数据报的传输成功或失败。UDP协议所失去的在其速度中得到了补偿。可以发送流化数据的程序中找到UDP的应用,如视频、声音和视频游戏等。对于这种类型的数据,丢失一两帧不会有什么影响,速度才是最重要的。“当程序的目的在于要传输尽可能多的信息时,当数据的丢失相对不重要时,可以使用UDP。(Ray,1999)”
注意:当编写本章时,UDP组件只支持发送接收字符串数据,这使得建立能够流化视频和图像的UDP客户和服务器较为困难。也许还会有些变化,等到您使用Delphi
6时,可能已经可以传输TStream对象和二进制数据了。
0768中描述,可以在http://www.cis.ohio-state.edu/htbin/rfc/rfc0768.html得到。Delphi提供了UDP协议的客户和服务器组件:TIdUDPClient和TIdUDPServer。TIdUDPClientServer.bpg文件中包含了一个客户服务器程序的例子。客户通过发送程序员定义的字符串命令来停止和开始由TMediaPlayer播放的.AVI视频。
注意:演示用的客户和服务器程序并不代表着UDP协议的最佳用途,只是对Internet
Direct实现的该组件的功能性的示范。
为创建使用TIdUDPClient和TIdUDPServer的示例程序,首先创建Delphi工程。然后向工程组再添加一个工程。把一个工程作为客户,另一个作为服务器。为连接到UDP服务器,需要一个TIdUDPClient组件。用来表示服务器的IP地址和端口号。对于示例程序,可以选择一个未被其他基于TCP的协议占用的端口号,如8090。由于UDP是无连接的,因此在UDP的接口方法中不包括Connect方法。要使用Internet
Direct实现的组件,只需使用Send向给定的IP地址和端口号广播一个命令字符串。示例中的客户程序向服务器发送“PLAY”和“STOP”字符串。假定一个通常的窗体,使用按钮在播放和停止状态之间进行切换,可以如下实现。
procedure TForm1.Button2Click(Sender: TObject);
Command : string = 'PLAY';
IdUDPClient1.Send(Command);
Memo1.Lines.Add( IdUDPClient1.ReceiveString );
if( Command = 'PLAY' ) then
Command := 'STOP'
Command := 'PLAY';
较为重要的代码是IdUDPClient1.Send(Command),这个语句很简单。可以注意到其中并未表示连接或断开。
服务器是作为应用程序实现的,它对客户程序发出的一个简单的命令集进行响应。为实现服务器,程序将监听DefaultPort端口(8090,与客户相匹配)上的广播,并将TIdUDPServer.Active设置为True。当UDP服务器从客户接收数据时,将调用TIdUDPServer.OnUDPRead事件处理程序。下面列出的代码示范了如何从OnUDPRead事件的参数中读出数据。
procedure TForm2.IdUDPServer1UDPRead(Sender: TO AData:
const APeerIP: S const APeerPort: Integer);
S : TStringS
S := TStringStream.Create('');
S.CopyFrom( AData, AData.Size );
if( CompareText( S.DataString, 'PLAY' ) = 0 ) then
MediaPlayer1.Play
else if (CompareText( S.DataString, 'STOP' ) = 0 ) then
MediaPlayer1.S
IdUDPServer1.Send( APeerIP, APeerPort, S.DataString );
OnUDPRead有四个参数,类型分别是:TObject、TStream、string和integer。TObject参数表示发送者对象。TStream参数包含了从客户端发送的数据。字符串参数APeerIP,即第三个参数,包含了发送数据的客户计算机的IP地址。APeerPort参数用于标识广播的端口号。
提示:本章进行写作时,Delphi 6 beta版并未集成Indy帮助文档和示例程序。当Delphi
6正式版出售时,应该已经包括文档和示例;现在可以访问/Indy/Download.html来得到示例程序、源代码和帮助文件。
上面列出的代码使用TStringStream来把数据从TStream对象复制到StringStream,使得代码可以像处理字符串一样处理该数据(另外,也可以使用As操作符来确定TStream对象实际数据类型)。在本例中,把字符串数据与简单的命令集进行比较,然后在使用调用客户的IP地址和端口号将该命令回送到客户端。
16.3& 建立FTP客户程序
文件传输协议(FTP)是一个基于TCP/IP的协议,用于在网络上传输文件。当从Internet下载文件时,可能使用HTTP命令GET,也可能使用FTP。FTP协议具有自身的命令集合,Delphi中包含了一些组件,可用于建立FTP客户程序(例如Ipswitch公司的WS_FTPPro程序和Windows自带的命令行FTP程序)和FTP服务器程序(例如与Microsoft
Internet Information Server一同发布的FTP服务器)。
注意:在浏览器中,像AOL的Netscape Navigator或Microsoft的Internet
Explorer,可能最常用的协议是超文本传输协议(HTTP),但也可以使用其他几种协议,包括FTP、file、gopher和Telnet。
本书的光盘包含了几个FTP示例程序,包括SimpleFTP,它是一个简单的示例程序,使用NetMasters公司的TNMFTP组件实现,该组件可以在组件面板的FastNet属性页上找到,该程序的另一个版本是使用Nevrona公司的TIdFTP组件实现的。除此之外,光盘上还有一个精致的FTP程序FTPPro(如图16.3所示)。FTPPro程序完整的代码并未在此列出,该程序共有大约2000行代码。FTPPro.exe程序还演示了应用程序在注册表中的设置(参考本章稍后POP3示例的章节,其中有一个例子,使用TIniFile类来把程序设置保存在INI文件中)。FTPPro.exe示例程序还包括了闪烁屏幕、新的shell控件、可选窗体、密码对话框和很多的FTP功能。可以从光盘上复制该程序,并仔细查看一下。本节涵盖了FTP功能中最重要的部分,同时也突出强调了与FTP协议明确相关的代码。
图16.3& FTPPro.exe演示了一个基于Windows的FTP客户程序的
完整实现,其中使用了NetMasters公司的TNMFTP组件
16.3.1& 连接到FTP服务器
FTP客户程序的所有完整实现都必须满足FTP协议的要求。无论特定的特性和方法是否命名相同,这一点都是必须的。在Delphi中有两个组件可用于创建FTP客户程序。分别是NetMasters
LLC公司的TNMFTP组件和Nevrona公司的TIdFTP组件。本节演示了为把FTP客户程序连接到FTP服务器,所有必要的特性和代码实例。
使用TNMFTP组件连接到FTP服务器
FTP协议要求主机IP和端口号。主机IP可以是如何运行FTP服务器的主机地址,而端口号通常是21。依赖于FTP服务器的配置,您可能需要提供用户名和密码。如果服务器允许匿名登录,那么可以使用anonymous作为用户名,并使用任何包含@字符的字符串作为密码(在匿名登录时,通常要求使用电子邮件地址作为密码)。下面的代码演示了匿名登录到FTP站点的过程,其中使用名为NMFTP1的TNMFTP组件。
NMFTP1.Host := '198.109.162.177';
NMFTP1.Port := 21;
NMFTP1.UserID := 'anonymous';
NMFTP1.Password := '';
假定主机和端口号是正确的(本例中是正确的),而且服务器允许匿名登录,则上述代码将把FTP客户程序连接到所指定的主机。
两种组件都提供了基本的FTP服务,其不同点在于完全性和示范易于实现。在与文件上传和下载相关的章节中提供了一个例子,演示了如何用TNMFTP组件执行基本的FTP服务。FTPPro示例程序是用TNMFTP实现的;您可以从本书的CD-ROM中装载并运行FTPPro工程。
&如果使用TNMFTP组件登录到需要有效用户和密码的站点(而不是匿名登录时),则TNMFTP组件需要进行认证。通过实现TNMFTP.OnAuthenticationNeeded事件处理程序,可以提供动态认证功能。OnAuthenticationNeeded事件处理程序传递一个布尔变量参数Handled。将Handled赋值为True,TNMFTP将继续尝试登录。下面列出的代码示范了认证事件的实现。
procedure TFormMain.NMFTP1AuthenticationNeeded(var Handled:
UserID, Password :
UserID := NMFTP1.UserID;
Password := NMFTP1.P
Handled := GetPassword( UserID, Password );
if( Handled ) then
NMFTP1.Password := P
NMFTP1.UserID := UserID;
GetPassword是一个全局函数(定义在本书光盘的UFormPassword单元中),该函数创建一个模式对话框窗体,该窗体非常简单,只包括两个输入域,分别代表用户名和密码。
代理服务器
&有些FTP服务器可能会使用代理服务器作为防火墙,以避免黑客攻击;也可能像Software
Conceptions公司一样,使用代理服务器向几台工作站通过Internet访问功能。通过设置TNMFTP.Proxy特性,可以指定代理服务器IP地址;通过设置TNMFTP.ProxyPort特性可以指定代理服务器端口。
使用TIdFTP连接到FTP服务器
Nevrona实现的Indy
FTP组件TIdFTP支持的公开特性较少,但与TNMFTP基本相同。分别设置TIdFTP.Host、TIdFTP.Port、TIdFTP.User和TIdFTP.Password特性,并调用connect方法,即可将FTP客户程序连接到FTP服务器。SimpleFTP.exe的第二种实现位于本书的光盘上。
16.3.2& 上传和下载文件
FTP协议的首要目的在于提供客户与服务器之间的文件传输功能。您可能对TNMFTP了解较多,这里对两种FTP实现TNMFTP和TIdFTP进行了比较,使得您可以了解不同的实现风格。
TNMFTP组件的文件传输方法
TNMFTP.Upload和TNMFTP.Download方法都需要两个参数。上传是将文件从客户复制到服务器的过程,而下载刚好相反。两个方法的声明如下。
procedure Download(RemoteFile, LocalFile: string);
procedure Upload(LocalFile, RemoteFile: string)
假定已经连接到FTP服务器,可以将要下载的服务器上文件的名字作为第一个参数,而本地计算机上保存的文件名作为第二个参数。
如果目标文件在远程或本地计算机已经存在,相应的上传和下载过程将覆盖目标文件。文件传输是异步的。这样,对上传和下载方法的调用将在文件传输完成之前返回。文件传输的成功或失败,需要通过实现TNMFTP.OnSuccess和TNMFTP.OnFailure事件方法来进行通知。两个事件方法的Trans_Type参数类型都是TCmdType。例如,如果调用OnFailure方法而TCmdType参数是cmdDownload,则可以知道下载操作已经失败。
TIdFTP组件的文件传输方法
Indy的FTP实现中,下载方法命名为Get,上传方法命名为Put。Get实现为过载方法。
procedure Get(const ASourceFile: ADest: TStream);
procedure Get(const ASourceFile: const ADestFile:
const ACanOverwrite: boolean);
Get方法的第一个版本取得远程计算机上的源文件名,并把文件下载到TStream对象中。第二个版本与TNMFTP的实现较为相似。第一和第二个参数分别表示远程和本地文件名,第三个参数指明在目标文件已经存在时是否覆盖。下面列出的代码示范了如何将文件下载到TStream对象中。
FileName :
S : TStringS
FileName := Copy( ListView1.Selected.Caption, LastDelimiter('
ListView1.Selected.Caption), 255 );
S := TStringStream.Create('');
if( Pos( '&DIR&',
ListView1.Selected.Caption ) = 0 ) then
IDFTP1.Get( FileName, S );
S.Position := 0;
Memo1.Lines.LoadFromStream(S);
代码中有一些假定。第一个假定是TListView组件的Caption特性中包括文件名(在演示TIdFTP组件的SimpleFTP示例工程中确实如此,该工程在本书的光盘上),而且窗体上有一个名为Memo1的TMemo组件。代码将文件名从TListView组件中提取出来。然后创建TStringStream对象,TStringStream是TStream的后代,因此我们可以对TIdFTP.Get方法的TStream参数使用TStringStream对象。将创建的流对象传递给Get方法。在调用Get方法后需要将流的位置重置为0,向流对象复制数据将改变流的当前位置。在装载了StringStream对象之后,可以使用TStrings.LoadFromStream方法将TStringStream对象中的数据复制到TMemo对象中(请记住,TMemo的Lines特性是一个TStrings类型的对象特性)。
实现中过载了Put方法,以便直接在流对象和文件上进行工作(该实现是对称的,使得组件的使用非常直接。按照直觉,我们可以认为,既然Get方法可以在流对象和文件上工作,那么,与之相对应的Put方法也应该能够在流对象和文件上工作)。Put方法的声明如下:
procedure Put(const ASource: TS const ADestFile:
const AAppend: boolean);
procedure Put(const ASourceFile: const ADestFile:
const AAppend: boolean);
在Put的第一个实现中,该方法将数据从客户端的流对象复制到远程服务器上的文件。如果AAppend参数设置为True,那么数据将附加在已存在的文件之后。在Put方法的第二个实现中,源数据和目标数据都是文件,而AAppend参数的作用与第一种实现相同。
16.3.3& 向FTP服务器发送命令
FTP协议包含一个命令集,由大约20条命令组成。对于特定的组件而言,不见得把协议命令集中的每个命令都作为公有方法实现。通过使用一个一般性的方法向服务器发送命令字符串,可以支持在TIdFTP和TNMFTP组件的接口中并不直接支持的FTP命令。TIdFTP使用SendCmd方法实现了这种能力。
function SendCmd(const AOut: const AResponse:
SmallInt):
function SendCmd(const AOut: const AResponse: Array
SmallInt): SmallI
在上述函数中,需要传递一个命令字符串和一个响应代码(或一组响应代码)。如果服务器的响应与响应代码并不匹配,将产生异常。在下面的代码片断中,使用响应代码150和226向FTP服务器发送了一个通常的list命令。如果服务器的响应不是150(打开连接)和226(传输完成),将产生异常。第二行代码将把缓冲区中的内容读入到TString对象Dest中。
IdFTP1.SendCmd('ls', [150, 226]);
Dest.Text := IdFTP1.CurrentReadB
如果一个方法是可用的,则无需使用一般性的SendCmd方法。TIdFTP.List方法实现如下。
procedure List(ADest: TS const ASpecifier:
const ADetails: boolean);
第一个参数类型为TStrings,第二个参数不是文件掩码,而第三个参数表示返回文件信息。使用下述代码中的参数调用List,可以只返回文件名。
Dest : TStringList.C
IDFtp1.List( Dest, '*.*', False );
for I := 0 to Dest.Count - 1 do
with ListView1.Items.Add do
Caption := Dest[I];
上面的代码向List传递了TStrings对象Dest和文件掩码‘*.*’,而且不要求返回详细信息。for循环将字符串数组中的数据复制到名为ListView1的TListView组件中。
提示:FTP协议定义在RFC 959中。
幸运的是,Indy和NetMaster
FTP组件实现了许多通常的FTP命令,如上传和下载文件、建立和改变目录、删除和列出文件等。DoCommand是SendCmd方法的TNMFTP版本,该方法只有一个字符串参数,即所用的命令。对于FTP客户端的实现细节,请参见本书光盘上的FTPPro例子程序。
16.4& 创建Telnet客户程序
终端仿真客户可以利用Telnet协议连接到Telnet服务器,通常使用端口23。尽管可以连接到其他的TCP/IP服务器,通常Telnet客户只用于连接到返回终端数据的服务器(参见John
Ray的《Special Edition Using
TCP/IP》一书,其中有一些有趣的例子使用Telnet客户端连接到POP3和SMTP服务器)。本书光盘上的例子程序TelnetPro包含有演示Telnet客户端的源代码,该客户端模仿了Windows自带的Telnet.exe程序。
TelnetPro程序的终端仿真器非常基本。为创建完整的Telnet程序,需要实现(或找到)一个终端仿真器。如果要实现终端仿真器,可以在/pdp10/ANSIcode.txt
找到仿真器所必须支持的ANSI代码的完整描述。ANSI代码的形式类似于$1B[,即ASCII码27(十六进制$1B)所代表的Esc字符后接左方括号,其后是特定的字符串序列。
图16.4& 如图所示,使用TelnetPro.exe示例程序连接到密歇根州
&&&&立大学图书馆的MAGIC服务器,网址为magic.msu.edu
为完成终端仿真器,需要定义一个语法分析循环,用于从明文中提取ANSI转义代码,并根据ANSI代码确定何时删除显示内容、滚屏或修改显示字体。除了工作站上自带的很小的Telnet客户端(可以通过Start
| Run菜单运行)之外,提供了Rumba。这两个产品演示了Telnet程序应具有的功能。
使用TIdTelnet组件,需要指定主机和端口号。例如,将主机设置为magic.msu.edu,端口号设置为23,即可连接到MSU大学的MAGIC服务器。实现TIdTelnet.OnDataAvailable方法从字符串参数Buffer中读入服务器的响应。Buffer参数中包含了ANSI代码和要显示的文本。可使用SendCh或SendStr向服务器发送数据。SendCh每次通过Telnet端口发送一个字符,而SendStr每次向服务器传递一个字符串参数。下面的示例代码捕获RichEdit控件中的击键事件,并按每次一个字符将其发送出去。
procedure TFormMain.RichEdit1KeyPress(Sender: TO var
Input : string = '';
if( Not IdTelnet1.Connected )
IdTelnet1.SendCh(Key);
Key := #0;
如果TIdTelnet组件并未连接到服务器,上面的代码将忽略key参数。否则,每次将向服务器发送一个字符,并把key参数设置为#0;这使得一直可以向RichEdit控件直接插入字符。下面列出的代码示范了一个简单的Telnet应用程序。
unit UFormM
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms,
Dialogs, IdBaseComponent, IdComponent, IdTCPConnection,
IdTCPClient,
IdTelnet, StdCtrls, M
TFormMain = class(TForm)
IdTelnet1: TIdT
MainMenu1: TMainM
Connect1: TMenuI
Connect2: TMenuI
Disconnect1: TMenuI
N1: TMenuI
Exit1: TMenuI
procedure IdTelnet1DataAvailable(Buffer: String);
procedure FormDestroy(Sender: TObject);
procedure Memo1KeyPress(Sender: TO var Key: Char);
procedure Exit1Click(Sender: TObject);
procedure Connect2Click(Sender: TObject);
procedure Disconnect1Click(Sender: TObject);
procedure FormClose(Sender: TO var Action:
TCloseAction);
procedure FormCreate(Sender: TObject);
{ Private declarations }
{ Public declarations }
FormMain: TFormM
implementation
{$R *.DFM}
procedure TFormMain.IdTelnet1DataAvailable(Buffer: String);
Memo1.Lines.Add(Buffer);
procedure TFormMain.FormDestroy(Sender: TObject);
IdTelnet1.D
procedure TFormMain.Memo1KeyPress(Sender: TO var Key:
if( IdTelnet1.Connected ) then
if( Key = #13 ) then Memo1.C
IdTelnet1.SendCh(Key);
procedure TFormMain.Exit1Click(Sender: TObject);
procedure TFormMain.Connect2Click(Sender: TObject);
Host := 'magic.msu.edu';
Disconnect1Click(Self);
if( InputQuery( 'Host', 'Enter host address:', Host )) then
IdTelnet1.Host := H
IdTelnet1.C
procedure TFormMain.Disconnect1Click(Sender: TObject);
if( IdTelnet1.Connected ) then
IdTelnet1.D
procedure TFormMain.FormClose(Sender: TO var Action:
TCloseAction);
Disconnect1Click(Self);
procedure TFormMain.FormCreate(Sender: TObject);
Connect2Click(Self);
当创建窗体或单击Connect菜单项时,该应用程序需要用户输入主机名。还实现了Disconnect和Exit菜单。当客户连接到服务器时,如果已经定义了OnDataAvailable事件处理程序,将调用该事件。在本例中,文本直接发送到TMemo控件。为正确显示数据流,需要终端仿真器来读入并解释服务器发送的ANSI命令。如果客户已连接到服务器,Memo1KeyPress处理程序将把每个字符都发送到Telnet服务器。您可以使用例子程序连接到远程服务器,但其显示可能不很美观(从实现代码即可看出)。
16.5& 使用POP3和SMTP建立Internet Email客户端程序
POP3和SMTP也可称为Internet email协议,它们支持收发email。POP3(Post Office
Protocol)和SMTP(Simple Mail Transfer Protocol)是用于收发Internet
email的两个协议。TIdPOP3和TIdSMTP两个组件提供了email支持,可用于建立Internet
email的客户端程序。这两个组件使用了一个第三方组件TIdMessage,该组件代表了邮件服务器发送到客户程序的内容。要成功地传输数据,这些协议需要比前面的协议更多的信息,因此我们将从基于任务的角度来仔细查看每个组件;您可以看一下本书光盘上的SimplePOP3例子程序(我们不会在这里列出完整的程序代码)。
16.5.1& 使用TIdPOP3组件
TIdPOP3组件需要一些必要的信息,以便使用POP3协议进行工作。组件的Host、Password、Port和UserID特性代表了这些信息。这些值存储在控制面板的Mail小应用程序中,可使用这些值接到POP3服务器(如图16.5所示)。在Mail小应用程序中,选定Internet
E-mail配置文件并单击Properties按钮即可看到这些特性的值。
图16.5& Mail Properties对话框包含了特定邮件服务
器的信息,如POP3或Exchange服务器
POP3组件可用于向邮件服务器查询邮件。调用TIdPOP3.CheckMessages将返回邮件的数目。下面的代码中将邮件数目存储到Count,然后进行Count次循环,重复调用TIdPOP3.Retrieve从邮件服务器获取每一个邮件。Retrieve的参数为邮件序号和TIdMessage对象。邮件序号从1开始。如果使用从0开始循环,需要向循环控制变量加1,才能得到有效的邮件序号。下面的代码对此进行了示范:
procedure TFormMain.ActionSendReceiveExecute(Sender:
I, Count : I
Count := IdPOP31.CheckM
for I := 0 to Count - 1 do
if( IdPOP31.Retrieve( I + 1, IdMessage1 )) then
ShowMessage( IdMessage.From.Name + ':' +
IdMessage1.Subject );
列出的代码假定已经调用了TIdPOP3.Connect方法并成功连接到邮件服务器。如果TIdPOP3.CheckMessages方法返回的邮件数目大于零,则使用TIdMessage对象示例IdMessage1来获取所有的邮件(TIdMessage是一个组件,位于组件面板的Indy
Misc属性页上)。TIdMessage组件包含了所有必要的特性,可以看到附件并对邮件进行响应。关于SMTP组件可以阅读后面的章节,其中包含了一些响应和发送邮件的例子。
在TIdPOP3组件的当前实现中,Delete方法有一个参数表示邮件序号。您需要根据邮件获取顺序把序号存储起来。在TIdMessage对象中并不存储该信息。TIdMessage组件确实存储了MsgId字符串,但Delete方法无法使用MsgId进行工作。
IdPOP31.Delete( 1 );
从这个语句可以看出,在服务器上删除信息显然是很简单的。但并不显然的是,在邮件对象中没有存储服务器上的邮件序号。您只能手工编写代码来存储邮件序号。
注意:在更好的实现方法中可能会基于邮件的内容进行删除,以后可能会进行这样的修订。
当使用相对邮件序号调用Delete方法时,邮件被标记为删除,但直到与服务器断开连接时才真正删除。在图形用户界面中,可以选择删除或只是标记为删除。
16.5.2& 使用TIdMessage组件
当使用Internet Direct
POP3和SMTP组件时,无论是使用POP3组件获取邮件,还是使用SMTP组件发送邮件,都需要使用TIdMessage组件存储邮件。TIdMessage组件将邮件体存储为TStrings对象,可通过Body属性进行访问。From特性是一个TIdEmailAddressItem对象,使用TCollectionItem实现。Recipients特性定义为TIdEmailAddressList对象,是由TOwnedCollection子类化而来。Subject是一个字符串特性。像CCList、Date和ReplyTo等特性在集成帮助文档中都可以查到。
要发送一个基本的邮件,需要对上述特性赋值。下面的代码片段摘自SimplePOP3程序,示范了如何从可视化组件向TIdMessage类型的对象IdMessage1复制数据。
IdMessage1.Body.Assign( MemoBody.Lines );
IdMessage1.From.Text := IniFile.EmailA
IdMessage1.Recipients.EmailAddresses :=
LabeledEditRecipient.T
IdMessage1.Subject := LabeledEditSubject.T
当准备好发送邮件时,需要使用TIdSMTP组件,将TIdMessage对象作为参数传递给该组件的send方法。下一节演示了如何发送邮件。
16.5.3& 使用TIdSMTP组件
假定已经正确的配置了TIdMessage对象,下面就需要使用TIdSMTP组件来发送邮件。POP3服务器通常监听110端口,主机就是POP3主机名。SMTP服务器通常监听25端口。SMTP主机可能与POP3主机并不相同。为配置SMTP客户,需要给出SMTP主机、端口、用户名和密码。例如,您的SMTP主机名可能是与邮件有关的字符串,而端口号可能是25。
提示:如果不知道POP3和SMTP端口号、主机、用户id和密码,可以使用相应的email管理程序或控制面板中的Mail
Properties Applet进行查看。
注意:.INI文件的作用与注册表相仿。两种方法都是可以接收的,但注册表对于存储应用程序的持久数据是首选方法(INI文件进行开发时更容易使用,而且应用程序出现问题时也不容易破坏注册表)。
TIdSMTP.Port、TIdSMTP.Host、TIdSMTP.UserID和TIdSMTP.Password特性可以在设计时或运行时配置。例如,本书光盘上的SimplePop3示例程序使用INI文件来存储连接信息。下面的代码演示了如何将静态值赋予SMTP组件特性并发送邮件(要发送的参数是一个TIdMessage对象实例。关于初始化邮件对象的例子,其参见上一节)。
IdSMTP1.Host := 'mail';
IdSMTP1.Port := 25;
IdSMTP1.UserID := 'userid';
IDSMTP1.Password := 'password';
IdSMTP1.Send(IdMessage1);
上面的代码假定已经正确的配置了TIdMessage对象。发送邮件前对TIdMessage对象的配置,请参见上一节。另外,您可以使用类方法QuickSend来发送email而无需使用TIdMessage组件。
IdSMTP1.QuickSend('mets.tcimet.net', 'Reminder',
'Buy Building Delphi 6 Applications');
还有其他几种协议是在TCP/IP上实现的,当然也可以另行实现自己的协议,或子类化并扩展Internet
Direct组件来得到自定义接口。关于使用Delphi进行TCP/IP编程的进一步信息,请阅读Andrew
Wozniewicz的《Web Programming with
Delphi》一书,关于TCP/IP协议的一般性信息,可以阅读John Ray的《Special Edition Using
TCP/IP》。
16.6& 小& 结
本章涵盖了若干种不同的协议,它们都是基于TCP/IP的。TCP/IP并非联网的惟一手段,但它是一种跨越Internet、内部网和外部网连接计算机的可靠手段。本章中,您已经学到了如何使用一些新的来自Nevrona公司的Internet
Direct组件;并测试了FTP、UDP、Telnet、TCP、POP3和SMTP组件。还有其他许多新的组件可用于创建客户和服务器程序。
下一章我们将继续讨论Web编程,使用一些协议来建立Web服务器和基于Web的应用程序。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

我要回帖

更多关于 怎么判断li里面的内容 的文章

 

随机推荐