在Delphi 7 中用Indy开发Socket应用程序文档格式.docx
- 文档编号:8324329
- 上传时间:2023-05-11
- 格式:DOCX
- 页数:10
- 大小:90.20KB
在Delphi 7 中用Indy开发Socket应用程序文档格式.docx
《在Delphi 7 中用Indy开发Socket应用程序文档格式.docx》由会员分享,可在线阅读,更多相关《在Delphi 7 中用Indy开发Socket应用程序文档格式.docx(10页珍藏版)》请在冰点文库上搜索。
阻塞式访问更像是文件存取。
当你读取数据,或是写入数据时,读取和写入函数将一直等到相应的操作完成后才返回。
比如说,发起网络连接只需调用Connect方法并等待它返回,如果该方法执行成功,在结束时就直接返回,如果未能成功执行,则会抛出相应的异常。
同文件访问不同的是,Socket调用可能会需要更长的时间,因为要读写的数据可能不会立即就能准备好(在很大程度上依赖于网络带宽)。
阻塞式Socket并非恶魔(Evil)
长期以来,阻塞式Socket都遭到了毫无理由的攻击。
其实阻塞式Socket并非如通常所说的那样可怕。
这还要从Winsock的发展说起。
当Socket被从Unix移植到Windows时,一个严重的问题立即就出现了。
Unix支持fork,客户程序和服务器都能够fork新的进程,并启动这些进程,从而能够很方便地使用阻塞式Socket。
而Windows3.x既不支持fork也不支持多线程,当使用阻塞式Socket时,用户界面就会被“锁住”而无法响应用户输入。
为克服Windows3.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服务器组件创建一个同应用程序主线程分离的监听线程来监听客户连接请求,对于接受的每一个客户,都创建一个新的线程来为该客户提供服务,所有与这一客户相关的事务都由该线程来处理。
使用组件TIdThreadMgrPool,Indy还支持线程池。
图1Indy服务器工作原理
线程与Indy客户程序
Indy客户端组件并未使用线程。
但是在一些高级的客户程序中,程序员可以在自定义的线程中使用Indy客户端组件,以使用户界面更加友好。
简单的Indy应用示例
下面将创建一个简单的TCP客户程序和一个简单的TCP服务器来演示Indy的基本使用方法。
客户程序使用TCP协议同服务器连接,并向服务器发送用户所输入数据。
服务器支持两条命令:
DATA和QUIT。
在DATA命令后跟随要发送的数据,并用空格将命令字DATA和数据分隔开。
表单布局
建立一个项目组,添加一个客户程序项目和一个服务器项目。
客户程序和服务器程序的表单布局如同2和图3所示。
客户程序表单上放置了TIdTCPClient组件,服务器程序表单上放置了TIdTCPServer组件。
为防止客户程序“冻结”,还在其表单上放置TIdAntiFreeze组件。
客户程序和服务器程序的表单上都放置有TListBox组件,用来显示通信记录。
图2简单的TCP客户程序表单
图3简单的TCP服务器程序表单
客户程序代码
客户程序片断如代码列表1所示。
代码列表1
procedureTFormMain.BtnConnectClick(Sender:
TObject);
begin
IdTCPClient.Host:
=EdtHost.Text;
IdTCPClient.Port:
=StrToInt(EdtPort.Text);
LbLog.Items.Add('
正在连接'
+EdtHost.Text+'
...'
);
withIdTCPClientdo
begin
try
Connect(5000);
LbLog.Items.Add(ReadLn());
BtnConnect.Enabled:
=False;
BtnSend.Enabled:
=True;
BtnDisconnect.Enabled:
except
远程主机无响应!
'
IdTCPClient.Disconnect();
end;
//endtry
无法建立到'
的连接!
//endwith
procedureTFormMain.BtnSendClick(Sender:
DATA'
+EdtData.Text);
WriteLn('
LbLog.Items.Add(ReadLn())
发送数据失败!
同主机'
的连接已断开!
procedureTFormMain.BtnDisconnectClick(Sender:
var
Received:
string;
QUIT'
IdTCPClient.WriteLn('
finally
在“连接”按钮事件响应过程中,首先根据用户输入设置IdTCPClient的主机和端口,并调用IdTCPClient的Connect方法向服务器发出连接请求。
然后调用ReadLn方法读取服务器应答数据。
在“发送”按钮事件响应过程中,调用WriteLn方法写DATA命令,向服务器发送数据。
在“断开”按钮事件响应过程中,向服务器发送QUIT命令,并调用Disconnect方法断开连接。
程序中还包含有通信信息记录和异常处理的代码。
服务器程序代码
服务器程序片断如代码列表2所示。
代码列表2
procedureTFormMain.BtnStartClick(Sender:
IdTCPServer.DefaultPort:
IdTCPServer.Active:
BtnStart.Enabled:
BtnStop.Enabled:
服务器已成功启动!
procedureTFormMain.BtnStopClick(Sender:
服务器已成功停止!
procedureTFormMain.IdTCPServerConnect(AThread:
TIdPeerThread);
来自主机'
+AThread.Connection.Socket.Binding.PeerIP
+'
的连接请求已被接纳!
AThread.Connection.WriteLn('
100:
欢迎连接到简单TCP服务器!
procedureTFormMain.IdTCPServerExecute(AThread:
sCommand:
withAThread.Connectiondo
sCommand:
=ReadLn();
FLogEntry:
=sCommand+'
来自于主机'
+AThread.Connection.Socket.Binding.PeerIP;
AThread.Synchronize(AddLogEntry);
ifAnsiStartsText('
sCommand)then
FReceived:
=RightStr(sCommand,Length(sCommand)-5);
200:
数据接收成功!
AThread.Synchronize(DisplayData);
end
elseifSameText(sCommand,'
)thenbegin
='
断开同主机'
的连接!
;
Disconnect;
elsebegin
500:
无法识别的命令!
无法识别命令:
+sCommand;
//endif
procedureTFormMain.DisplayData();
EdtData.Text:
=FReceived;
procedureTFormMain.AddLogEntry();
LbLog.Items.Add(FLogEntry);
“启动”按钮设置IdTCPServer的Active属性为True来启动服务器,“停止”按钮设置Active属性为False来关闭服务器。
IdTCPServerConnect方法作为IdTCPServer的OnCorrect事件响应过程,向客户端发送欢迎信息。
OnCorrect事件在一个客户连接请求被接受时发生,为该连接创建的线程AThread被作为参数传递给IdTCPServerConnect方法。
IdTCPServerExecute方法是IdTCPServer的OnExecute事件响应过程。
OnExecute事件在TIdPeerThread对象试图执行其Run方法时发生。
OnExecute事件与通常的事件有所不同,其响应过程是在某个线程上下文中执行的,参数AThread就是调用它的线程。
这一点很重要,它意味着可能有多个OnExecute事件响应过程被同时执行。
在连接被断开或中断前,OnExecute事件响应过程会被反复执行。
在IdTCPServerExecute方法中,首先读入一条指令,然后对指令进行判别。
如果是DATA指令,就解出数据并显示它。
如果收到的是QUIT指令,则断开连接。
需要特别指出的是,由于IdTCPServerExecute方法在某一线程上下文中执行,因此显示数据和添加事件记录都是将相应的方法传递给Synchronize调用来完成的。
运行程序
运行客户端和服务器程序,按如下流程进行操作:
1.按服务器程序的“启动”按钮启动服务器;
2.按客户程序的“连接”按钮,建立同服务器的连接;
3.在客户程序的待发送数据编辑框中输入“Hello,Indy!
”,并按“发送”按钮发送数据;
4.按客户程序的“断开”按钮,断开同服务器的连接;
5.按服务器程序的“停止”按钮停止服务器。
程序运行的结果如图4和图5所示。
图4简单的TCP客户
图5简单的TCP服务器
更多信息
要了解更多的关于Indy的信息,可以参阅:
[1]Indy主页
[2]Indy的帮助文件;
[3]
[4]ChadZ.Hower(Indy的原始作者)和HadiHariri合著的“IndyInDepth”,可以从
[5]MarcoCantu著,Sybex出版“MasteringDelphi7”中相关的章节。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 在Delphi 中用Indy开发Socket应用程序 Delphi 中用 Indy 开发 Socket 应用程序