收藏 分享(赏)

Indy简单教程.doc

上传人:jw66tk88 文档编号:7761659 上传时间:2019-05-25 格式:DOC 页数:14 大小:145KB
下载 相关 举报
Indy简单教程.doc_第1页
第1页 / 共14页
Indy简单教程.doc_第2页
第2页 / 共14页
Indy简单教程.doc_第3页
第3页 / 共14页
Indy简单教程.doc_第4页
第4页 / 共14页
Indy简单教程.doc_第5页
第5页 / 共14页
点击查看更多>>
资源描述

1、用 Indy 组件开发 Socket 应用程序介绍:细处着手,巧处用功。高手和菜鸟之间的差别就是:高手什么都知道,菜鸟知道一些。电脑小技巧收集最新奇招高招,让你轻松踏上高手之路。笔者在前一段的工作中,需要开发一套简单的网络数据传输程序。由于平时常用 Delphi 做点开发,故此次也不例外。Delphi 7 中带有两套TCP Socket 组件:Indy Socket 组件(IdTCPClient 和 IdTCPServer)和Delphi 原生的 TCP Socket 组件(ClientSocket 和 ServerSocket) 。但是,Borland 已宣称 ClientSocket 和

2、ServerSocket 组件即将被废弃,建议用相应的 Indy 组件来代替。因此,笔者使用了 Indy。本文在对 Indy 进行简要介绍的基础上,创建了一组简单的 TCP Socket 数据传输应用来演示了Indy 的使用方法。开放源代码的 Internet 组件集Internet Direct(Indy)Internet Direct(Indy)是一组开放源代码的 Internet 组件,涵盖了几乎所有流行的 Internet 协议。Indy 用 Delphi 编写,被包含在 Delphi 6,Kylix 1 和C+ Builder 6 及以上各个版本的 Borland 开发环境中。Ind

3、y 曾经叫做WinShoes(双关于 WinSockWindows 的 Socket 库) ,是由 Chad Z. Hower 领导的一群开发者构建的,可以从 Indy 的站点 上找到更多的信息并下载其新版本。到笔者撰写本文时为止,Indy 的最新稳定版是 9.0.14,Indy 10 也进入了 Beta 测试阶段。Delphi 7 中所带的是 Indy 9。在其的组件面板上,一共安装有 100多个 Indy 组件。使用这些组件你可以开发基于各种协议的 TCP 客户和服务器应用程序,并处理相关的编码和安全问题。你可以通过前缀 Id 来识别 Indy 组件。Indy 是阻塞式(Blocking)

4、的当你使用 Winsock 开发网络应用程序时,从 Socket 中读取数据或者向 Socket 写入数据都是异步发生的,这样就不会阻断程序中其它代码的执行。在收到数据时,Winsock 会向应用程序发送相应的消息。这种访问方式被称作非阻塞式连接,它要求你对事件作出响应,设置状态机,并通常还需要一个等待循环。与通常的 Winsock 编程方法不同的是,Indy 使用了阻塞式 Socket调用方式。阻塞式访问更像是文件存取。当你读取数据,或是写入数据时,读取和写入函数将一直等到相应的操作完成后才返回。比如说,发起网络连接只需调用 Connect 方法并等待它返回,如果该方法执行成功,在结束时就直

5、接返回,如果未能成功执行,则会抛出相应的异常。同文件访问不同的是,Socket 调用可能会需要更长的时间,因为要读写的数据可能不会立即就能准备好(在很大程度上依赖于网络带宽) 。阻塞式 Socket 并非恶魔(Evil)长期以来,阻塞式 Socket 都遭到了毫无理由的攻击。其实阻塞式Socket 并非如通常所说的那样可怕。这还要从 Winsock 的发展说起。当 Socket 被从 Unix 移植到 Windows 时,一个严重的问题立即就出现了。Unix 支持 fork,客户程序和服务器都能够 fork 新的进程,并启动这些进程,从而能够很方便地使用阻塞式 Socket。而 Windows

6、 3.x 既不支持 fork 也不支持多线程,当使用阻塞式 Socket 时,用户界面就会被“锁住”而无法响应用户输入。为克服 Windows 3.x 的这一缺陷,微软在 Winsock 中加入了异步扩展,以使 Winsock 不会“ 锁住”应用程序的主线程(也是唯一的线程) 。然而,这需要了一种完全不同的编程方式。于是有些人为了掩饰这一弱点,就开始强烈地诽谤阻塞式 Socket。当 Win32 出现的时候,它能够很好地支持线程。但是既成的观念已经很难更改,并且说出去的话也无法收回,因此对阻塞式 Socket 的诽谤继续存在着。事实上,阻塞式 Socket 仍然是 Unix 实现 Socket

7、 的唯一方式,并且它工作得很好。阻塞式 Socket 的优点归结起来,在 Windows 上使用阻塞式 Socket 开发应用程序具有如下优点:编程简单阻塞式 Socket 应用程序很容易编写。所有的用户代码都写在同一个地方,并且顺序执行。 容易向 Unix 移植由于 Unix 也使用阻塞式 Socket,编写可移植的代码就变得比较容易。Indy 就是利用这一点来实现其多平台支持而又单一源代码的设计。 很好地利用了线程技术阻塞式 Socket 是顺序执行的,其固有的封装特性使得它能够很容易地使用到线程中。 阻塞式 Socket 的缺点事物都具有两面性,阻塞式 Socket 也不例外。它的一个主

8、要的缺点就是使客户程序的用户界面“冻结” 。当在程序的主线程中进行阻塞式Socket 调用时,由于要等待 Socket 调用完成并返回,这段时间就不能处理用户界面消息,使得 Update、Repaint 以及其它消息得不到及时响应,从而导致用户界面被“冻结 ”。使用 TIdAntiFreeze 对抗 “冻结”Indy 使用一个特殊的组件 TIdAntiFreeze 来透明地解决客户程序用户界面“冻结 ”的问题。 TIdAntiFreeze 在 Indy 内部定时中断对栈的调用,并在中断期间调用 Application.ProcessMessages 方法处理消息,而外部的Indy 调用继续保存

9、阻塞状态,就好像 TIdAntiFreeze 对象不存在一样。你只要在程序中的任意地方添加一个 TIdAntiFreeze 对象,就能在客户程序中利用到阻塞式 Socket 的所有优点而避开它的一些显著缺点。Indy 使用了线程技术阻塞式 Socekt 通常都采用线程技术,Indy 也是如此。从最底层开始,Indy 的设计都是线程化的。因此用 Indy 创建服务器和客户程序跟在 Unix下十分相似,并且 Delphi 的快速开发环境和 Indy 对 WinSock 的良好封装使得应用程序创建更加容易。Indy 服务器模型一个典型的 Unix 服务器有一个或多个监听进程,它们不停地监听进入的客户

10、连接请求。对于每一个需要服务的客户,都 fork 一个新进程来处理该客户的所有事务。这样一个进程只处理一个客户连接,编程就变得十分容易。Indy 服务器工作原理同 Unix 服务器十分类似,只是 Windows 不像Unix 那样支持 fork,而是支持线程,因此 Indy 服务器为每一个客户连接分配一个线程。图 1 显示了 Indy 服务器的工作原理。Indy 服务器组件创建一个同应用程序主线程分离的监听线程来监听客户连接请求,对于接受的每一个客户,都创建一个新的线程来为该客户提供服务,所有与这一客户相关的事务都由该线程来处理。图 1 Indy 服务器工作原理使用组件 TIdThreadMg

11、rPool,Indy 还支持线程池。线程与 Indy 客户程序Indy 客户端组件并未使用线程。但是在一些高级的客户程序中,程序员可以在自定义的线程中使用 Indy 客户端组件,以使用户界面更加友好。简单的 Indy 应用示例下面将创建一个简单的 TCP 客户程序和一个简单的 TCP 服务器来演示 Indy 的基本使用方法。客户程序使用 TCP 协议同服务器连接,并向服务器发送用户所输入数据。服务器支持两条命令:DATA 和 QUIT。在DATA 命令后跟随要发送的数据,并用空格将命令字 DATA 和数据分隔开。表单布局建立一个项目组,添加一个客户程序项目和一个服务器项目。客户程序和服务器程序

12、的表单布局如同 2 和图 3 所示。客户程序表单上放置了 TIdTCPClient 组件,服务器程序表单上放置了 TIdTCPServer 组件。为防止客户程序“冻结” ,还在其表单上放置 TIdAntiFreeze 组件。图 2 简单的 TCP 客户程序表单图 3 简单的 TCP 服务器程序表单客户程序和服务器程序的表单上都放置有 TListBox 组件,用来显示通信记录。客户程序代码客户程序片断如代码列表 1 所示。代码列表 1procedure TFormMain.BtnConnectClick(Sender: TObject);beginIdTCPClient.Host := EdtH

13、ost.Text;IdTCPClient.Port := StrToInt(EdtPort.Text);LbLog.Items.Add(正在连接 + EdtHost.Text + .);with IdTCPClient dobegintryConnect(5000);tryLbLog.Items.Add(ReadLn();BtnConnect.Enabled := False;BtnSend.Enabled := True;BtnDisconnect.Enabled := True;exceptLbLog.Items.Add(远程主机无响应! );IdTCPClient.Disconnect(

14、);end;/end tryexceptLbLog.Items.Add(无法建立到 + EdtHost.Text + 的连接!);end;/end tryend;/end withend;procedure TFormMain.BtnSendClick(Sender: TObject);beginLbLog.Items.Add(DATA + EdtData.Text);with IdTCPClient dobegintryWriteLn(DATA + EdtData.Text);LbLog.Items.Add(ReadLn()exceptLbLog.Items.Add(发送数据失败! );Id

15、TCPClient.Disconnect();LbLog.Items.Add(同主机 + EdtHost.Text + 的连接已断开!);BtnConnect.Enabled := True;BtnSend.Enabled := False;BtnDisconnect.Enabled := False;end;/end tryend;/end withend;procedure TFormMain.BtnDisconnectClick(Sender: TObject);varReceived: string;beginLbLog.Items.Add(QUIT);tryIdTCPClient.W

16、riteLn(QUIT);finallyIdTCPClient.Disconnect();LbLog.Items.Add(同主机 + EdtHost.Text + 的连接已断开!);BtnConnect.Enabled := True;BtnSend.Enabled := False;BtnDisconnect.Enabled := False;end;/end tryend;在“连接 ”按钮事件响应过程中,首先根据用户输入设置 IdTCPClient的主机和端口,并调用 IdTCPClient 的 Connect 方法向服务器发出连接请求。然后调用 ReadLn 方法读取服务器应答数据。在“

17、发送 ”按钮事件响应过程中,调用 WriteLn 方法写 DATA 命令,向服务器发送数据。在“断开 ”按钮事件响应过程中,向服务器发送 QUIT 命令,并调用Disconnect 方法断开连接。程序中还包含有通信信息记录和异常处理的代码。服务器程序代码服务器程序片断如代码列表 2 所示。代码列表 2procedure TFormMain.BtnStartClick(Sender: TObject);beginIdTCPServer.DefaultPort := StrToInt(EdtPort.Text);IdTCPServer.Active := True;BtnStart.Enabled

18、 := False;BtnStop.Enabled := True;LbLog.Items.Add(服务器已成功启动! );end;procedure TFormMain.BtnStopClick(Sender: TObject);beginIdTCPServer.Active := False;BtnStart.Enabled := True;BtnStop.Enabled := False;LbLog.Items.Add(服务器已成功停止! );end;procedure TFormMain.IdTCPServerConnect(AThread: TIdPeerThread);beginL

19、bLog.Items.Add(来自主机 + AThread.Connection.Socket.Binding.PeerIP+ 的连接请求已被接纳!);AThread.Connection.WriteLn(100: 欢迎连接到简单 TCP 服务器!);end;procedure TFormMain.IdTCPServerExecute(AThread: TIdPeerThread);varsCommand: string;beginwith AThread.Connection dobeginsCommand := ReadLn();FLogEntry := sCommand + 来自于主机

20、+ AThread.Connection.Socket.Binding.PeerIP;AThread.Synchronize(AddLogEntry);if AnsiStartsText(DATA , sCommand) thenbeginFReceived := RightStr(sCommand, Length(sCommand)-5);WriteLn(200: 数据接收成功! );AThread.Synchronize(DisplayData);endelse if SameText(sCommand, QUIT) then beginFLogEntry := 断开同主机 + AThre

21、ad.Connection.Socket.Binding.PeerIP+ 的连接! ;AThread.Synchronize(AddLogEntry);Disconnect;endelse beginWriteLn(500: 无法识别的命令! );FLogEntry := 无法识别命令: + sCommand;AThread.Synchronize(AddLogEntry);end;/endifend;end;procedure TFormMain.DisplayData();beginEdtData.Text := FReceived;end;procedure TFormMain.AddL

22、ogEntry();beginLbLog.Items.Add(FLogEntry);end;“启动 ”按钮设置 IdTCPServer 的 Active 属性为 True 来启动服务器,“停止”按钮设置 Active 属性为 False 来关闭服务器。IdTCPServerConnect 方法作为 IdTCPServer 的 OnCorrect 事件响应过程,向客户端发送欢迎信息。OnCorrect 事件在一个客户连接请求被接受时发生,为该连接创建的线程 AThread 被作为参数传递给IdTCPServerConnect 方法。IdTCPServerExecute 方法是 IdTCPServ

23、er 的 OnExecute 事件响应过程。OnExecute 事件在 TIdPeerThread 对象试图执行其 Run 方法时发生。OnExecute 事件与通常的事件有所不同,其响应过程是在某个线程上下文中执行的,参数 AThread 就是调用它的线程。这一点很重要,它意味着可能有多个 OnExecute 事件响应过程被同时执行。在连接被断开或中断前,OnExecute 事件响应过程会被反复执行。在 IdTCPServerExecute 方法中,首先读入一条指令,然后对指令进行判别。如果是 DATA 指令,就解出数据并显示它。如果收到的是 QUIT指令,则断开连接。需要特别指出的是,由于

24、 IdTCPServerExecute 方法在某一线程上下文中执行,因此显示数据和添加事件记录都是将相应的方法传递给 Synchronize 调用来完成的。运行程序运行客户端和服务器程序,按如下流程进行操作:1. 按服务器程序的“ 启动”按钮启动服务器;2. 按客户程序的 “连接 ”按钮,建立同服务器的连接;3. 在客户程序的待发送数据编辑框中输入“Hello, Indy!”,并按“发送”按钮发送数据;4. 按客户程序的 “断开 ”按钮,断开同服务器的连接;5. 按服务器程序的“ 停止”按钮停止服务器。程序运行的结果如图 4 和图 5 所示。图 4 简单的 TCP 客户图 5 简单的 TCP 服务器

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报