




已阅读5页,还剩9页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
用Indy组件开发Socket应用程序介绍:细处着手,巧处用功。高手和菜鸟之间的差别就是:高手什么都知道,菜鸟知道一些。电脑小技巧收集最新奇招高招,让你轻松踏上高手之路。笔者在前一段的工作中,需要开发一套简单的网络数据传输程序。由于平时常用Delphi做点开发,故此次也不例外。Delphi 7中带有两套TCP Socket组件:Indy Socket组件(IdTCPClient和IdTCPServer)和Delphi原生的TCP Socket组件(ClientSocket和ServerSocket)。但是,Borland已宣称ClientSocket和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开发环境中。Indy曾经叫做WinShoes(双关于WinSockWindows的Socket库),是由Chad Z. Hower领导的一群开发者构建的,可以从Indy的站点/indy上找到更多的信息并下载其新版本。到笔者撰写本文时为止,Indy的最新稳定版是9.0.14,Indy 10也进入了Beta测试阶段。Delphi 7中所带的是Indy 9。在其的组件面板上,一共安装有100多个Indy组件。使用这些组件你可以开发基于各种协议的TCP客户和服务器应用程序,并处理相关的编码和安全问题。你可以通过前缀Id来识别Indy组件。Indy是阻塞式(Blocking)的当你使用Winsock开发网络应用程序时,从Socket中读取数据或者向Socket写入数据都是异步发生的,这样就不会阻断程序中其它代码的执行。在收到数据时,Winsock会向应用程序发送相应的消息。这种访问方式被称作非阻塞式连接,它要求你对事件作出响应,设置状态机,并通常还需要一个等待循环。与通常的Winsock编程方法不同的是,Indy使用了阻塞式Socket调用方式。阻塞式访问更像是文件存取。当你读取数据,或是写入数据时,读取和写入函数将一直等到相应的操作完成后才返回。比如说,发起网络连接只需调用Connect方法并等待它返回,如果该方法执行成功,在结束时就直接返回,如果未能成功执行,则会抛出相应的异常。同文件访问不同的是,Socket调用可能会需要更长的时间,因为要读写的数据可能不会立即就能准备好(在很大程度上依赖于网络带宽)。阻塞式Socket并非恶魔(Evil)长期以来,阻塞式Socket都遭到了毫无理由的攻击。其实阻塞式Socket并非如通常所说的那样可怕。这还要从Winsock的发展说起。当Socket被从Unix移植到Windows时,一个严重的问题立即就出现了。Unix支持fork,客户程序和服务器都能够fork新的进程,并启动这些进程,从而能够很方便地使用阻塞式Socket。而Windows 3.x既不支持fork也不支持多线程,当使用阻塞式Socket时,用户界面就会被“锁住”而无法响应用户输入。为克服Windows 3.x的这一缺陷,微软在Winsock中加入了异步扩展,以使Winsock不会“锁住”应用程序的主线程(也是唯一的线程)。然而,这需要了一种完全不同的编程方式。于是有些人为了掩饰这一弱点,就开始强烈地诽谤阻塞式Socket。当Win32出现的时候,它能够很好地支持线程。但是既成的观念已经很难更改,并且说出去的话也无法收回,因此对阻塞式Socket的诽谤继续存在着。事实上,阻塞式Socket仍然是Unix实现Socket的唯一方式,并且它工作得很好。阻塞式Socket的优点归结起来,在Windows上使用阻塞式Socket开发应用程序具有如下优点:编程简单阻塞式Socket应用程序很容易编写。所有的用户代码都写在同一个地方,并且顺序执行。 容易向Unix移植由于Unix也使用阻塞式Socket,编写可移植的代码就变得比较容易。Indy就是利用这一点来实现其多平台支持而又单一源代码的设计。 很好地利用了线程技术阻塞式Socket是顺序执行的,其固有的封装特性使得它能够很容易地使用到线程中。 阻塞式Socket的缺点事物都具有两面性,阻塞式Socket也不例外。它的一个主要的缺点就是使客户程序的用户界面“冻结”。当在程序的主线程中进行阻塞式Socket调用时,由于要等待Socket调用完成并返回,这段时间就不能处理用户界面消息,使得Update、Repaint以及其它消息得不到及时响应,从而导致用户界面被“冻结”。使用TIdAntiFreeze对抗“冻结”Indy使用一个特殊的组件TIdAntiFreeze来透明地解决客户程序用户界面“冻结”的问题。TIdAntiFreeze在Indy内部定时中断对栈的调用,并在中断期间调用Application.ProcessMessages方法处理消息,而外部的Indy调用继续保存阻塞状态,就好像TIdAntiFreeze对象不存在一样。你只要在程序中的任意地方添加一个TIdAntiFreeze对象,就能在客户程序中利用到阻塞式Socket的所有优点而避开它的一些显著缺点。Indy使用了线程技术阻塞式Socekt通常都采用线程技术,Indy也是如此。从最底层开始,Indy的设计都是线程化的。因此用Indy创建服务器和客户程序跟在Unix下十分相似,并且Delphi的快速开发环境和Indy对WinSock的良好封装使得应用程序创建更加容易。Indy服务器模型一个典型的Unix服务器有一个或多个监听进程,它们不停地监听进入的客户连接请求。对于每一个需要服务的客户,都fork一个新进程来处理该客户的所有事务。这样一个进程只处理一个客户连接,编程就变得十分容易。Indy服务器工作原理同Unix服务器十分类似,只是Windows不像Unix那样支持fork,而是支持线程,因此Indy服务器为每一个客户连接分配一个线程。图1显示了Indy服务器的工作原理。Indy服务器组件创建一个同应用程序主线程分离的监听线程来监听客户连接请求,对于接受的每一个客户,都创建一个新的线程来为该客户提供服务,所有与这一客户相关的事务都由该线程来处理。图1 Indy服务器工作原理使用组件TIdThreadMgrPool,Indy还支持线程池。线程与Indy客户程序Indy客户端组件并未使用线程。但是在一些高级的客户程序中,程序员可以在自定义的线程中使用Indy客户端组件,以使用户界面更加友好。简单的Indy应用示例下面将创建一个简单的TCP客户程序和一个简单的TCP服务器来演示Indy的基本使用方法。客户程序使用TCP协议同服务器连接,并向服务器发送用户所输入数据。服务器支持两条命令:DATA和QUIT。在DATA命令后跟随要发送的数据,并用空格将命令字DATA和数据分隔开。表单布局建立一个项目组,添加一个客户程序项目和一个服务器项目。客户程序和服务器程序的表单布局如同2和图3所示。客户程序表单上放置了TIdTCPClient组件,服务器程序表单上放置了TIdTCPServer组件。为防止客户程序“冻结”,还在其表单上放置TIdAntiFreeze组件。图2 简单的TCP客户程序表单图3 简单的TCP服务器程序表单客户程序和服务器程序的表单上都放置有TListBox组件,用来显示通信记录。客户程序代码客户程序片断如代码列表1所示。代码列表1procedure TFormMain.BtnConnectClick(Sender: TObject);beginIdTCPClient.Host := EdtHost.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();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(发送数据失败!);IdTCPClient.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.WriteLn(QUIT);finallyIdTCPClient.Disconnect();LbLog.Items.Add(同主机 + EdtHost.Text + 的连接已断开!);BtnConnect.Enabled := True;BtnSend.Enabled := False;BtnDisconnect.Enabled := False;end;/end tryend;在“连接”按钮事件响应过程中,首先根据用户输入设置IdTCPClient的主机和端口,并调用IdTCPClient的Connect方法向服务器发出连接请求。然后调用ReadLn方法读取服务器应答数据。在“发送”按钮事件响应过程中,调用WriteLn方法写DATA命令,向服务器发送数据。在“断开”按钮事件响应过程中,向服务器发送QUIT命令,并调用Disconnect方法断开连接。程序中还包含有通信信息记录和异常处理的代码。服务器程序代码服务器程序片断如代码列表2所示。代码列表2procedure TFormMain.BtnStartClick(Sender: TObject);beginIdTCPServer.DefaultPort := StrToInt(EdtPort.Text);IdTCPServer.Active := True;BtnStart.Enabled := 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);beginLbLog.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 + 来自于主机 + 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 := 断开同主机 + AThread.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.AddLogEntry();beginLbLog.Items.Add(FLogEntry);end;“启动”按钮设置IdTCPServer 的Active属性为True来启动服务器,“停止”按钮设置Active属性为False来关闭服务器。IdTCPServerConnect方法作为IdTCPServer 的OnCorr
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年贵港市教育局选调直属事业单位考试笔试试题(含答案)
- 2025年宁夏中考地理试题卷(含答案解析)
- 互联网医学考试题及答案
- 网络广告推广及效果评估合同
- 湛江一中大考试卷及答案
- 公务员时事政治试试题及答案2025年
- 腹膜炎护理考试题及答案
- 人保车险笔试题目及答案
- 泉州大队委笔试题目及答案
- 内燃机原理考试题及答案
- 人工智能算力中心项目环境影响报告书
- 无人机飞防应急处置预案
- 四川蜀道养护集团有限公司招聘笔试题库2025
- 高一历史第一次月考卷02(考试版)(新高考适用)
- 人教PEP版(2024)四年级上册英语-Unit 2 My friends 单元整体教学设计(共6课时)
- 《数星星的孩子》课件 部编版语文二年级上册
- 爆破安全培训课件
- 报废产品处置合同范本
- 中国石化加油站视觉形象(VI)标准手册-课件
- 铺轨工程监理规划及工作内容
- 女生青春期生理卫生知识讲座(课堂PPT)
评论
0/150
提交评论