用Indy组件开发Socket应用程序

利用indy编写的socket通信实例,一个客户端,一个服务端 利用indy控件编写的socket通信实例 立即下载
用Indy组件开发Socket应用程序 http://dev.21tx.com 2004年03月16日 Yesky 虚度

笔者在前一段的工作中,需要开发一套简单的网络数据传输程序。由于平时常用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(双关于WinSock——Windows的Socket库),是由 Chad Z. Hower领导的一群开发者构建的,可以从Indy的站点www.nevrona.com/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所示。

  代码列表1

procedure TFormMain.BtnConnectClick(Sender: TObject);
begin
IdTCPClient.Host := EdtHost.Text;
IdTCPClient.Port := StrToInt(EdtPort.Text);
LbLog.Items.Add('正在连接 ' + EdtHost.Text + '...');
with IdTCPClient do
begin
try
Connect(5000);
try
LbLog.Items.Add(ReadLn());
BtnConnect.Enabled := False;
BtnSend.Enabled := True;
BtnDisconnect.Enabled := True;
except
LbLog.Items.Add('远程主机无响应!');
IdTCPClient.Disconnect();
end;//end try
except
LbLog.Items.Add('无法建立到' + EdtHost.Text + '的连接!');
end;//end try
end;//end with
end;

procedure TFormMain.BtnSendClick(Sender: TObject);
begin
LbLog.Items.Add('DATA ' + EdtData.Text);
with IdTCPClient do
begin
try
WriteLn('DATA ' + EdtData.Text);
LbLog.Items.Add(ReadLn())
except
LbLog.Items.Add('发送数据失败!');
IdTCPClient.Disconnect();
LbLog.Items.Add('同主机 ' + EdtHost.Text + ' 的连接已断开!');
BtnConnect.Enabled := True;
BtnSend.Enabled := False;
BtnDisconnect.Enabled := False;
end;//end try
end;//end with
end;

procedure TFormMain.BtnDisconnectClick(Sender: TObject);
var
Received: string;
begin
LbLog.Items.Add('QUIT');
try
IdTCPClient.WriteLn('QUIT');
finally
IdTCPClient.Disconnect();
LbLog.Items.Add('同主机 ' + EdtHost.Text + ' 的连接已断开!');
BtnConnect.Enabled := True;
BtnSend.Enabled := False;
BtnDisconnect.Enabled := False;
end;//end try
end;

  在“连接”按钮事件响应过程中,首先根据用户输入设置IdTCPClient的主机和端口,并调用IdTCPClient的Connect方法向服务器发出连接请求。然后调用ReadLn方法读取服务器应答数据。

  在“发送”按钮事件响应过程中,调用WriteLn方法写DATA命令,向服务器发送数据。

  在“断开”按钮事件响应过程中,向服务器发送QUIT命令,并调用Disconnect方法断开连接。

  程序中还包含有通信信息记录和异常处理的代码。

服务器程序代码

  服务器程序片断如代码列表2所示。

  代码列表2

procedure TFormMain.BtnStartClick(Sender: TObject);
begin
IdTCPServer.DefaultPort := StrToInt(EdtPort.Text);
IdTCPServer.Active := True;
BtnStart.Enabled := False;
BtnStop.Enabled := True;
LbLog.Items.Add('服务器已成功启动!');
end;

procedure TFormMain.BtnStopClick(Sender: TObject);
begin
IdTCPServer.Active := False;
BtnStart.Enabled := True;
BtnStop.Enabled := False;
LbLog.Items.Add('服务器已成功停止!');
end;

procedure TFormMain.IdTCPServerConnect(AThread: TIdPeerThread);
begin
LbLog.Items.Add('来自主机 '
+ AThread.Connection.Socket.Binding.PeerIP
+ ' 的连接请求已被接纳!');
AThread.Connection.WriteLn('100: 欢迎连接到简单TCP服务器!');
end;

procedure TFormMain.IdTCPServerExecute(AThread: TIdPeerThread);
var
sCommand: string;
begin
with AThread.Connection do
begin
sCommand := ReadLn();
FLogEntry := sCommand + ' 来自于主机 '
+ AThread.Connection.Socket.Binding.PeerIP;
AThread.Synchronize(AddLogEntry);
if AnsiStartsText('DATA ', sCommand) then
begin
FReceived := RightStr(sCommand, Length(sCommand)-5);
WriteLn('200: 数据接收成功!');
AThread.Synchronize(DisplayData);
end
else if SameText(sCommand, 'QUIT') then begin
FLogEntry := '断开同主机 '
+ AThread.Connection.Socket.Binding.PeerIP
+ ' 的连接!';
AThread.Synchronize(AddLogEntry);
Disconnect;
end
else begin
WriteLn('500: 无法识别的命令!');
FLogEntry := '无法识别命令:' + sCommand;
AThread.Synchronize(AddLogEntry);
end;//endif
end;
end;

procedure TFormMain.DisplayData();
begin
EdtData.Text := FReceived;
end;

procedure TFormMain.AddLogEntry();
begin
LbLog.Items.Add(FLogEntry);
end;

  “启动”按钮设置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控件使用指南 使用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还支持线程池。   线程与Indy客户程序   Indy客户端组件并未使用线程。但是在一些高级的客户程序中,程序员可以在自定义的线程中使用Indy客户端组件,以使用户界面更加友好。 立即下载

相关推荐

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的使用方法。

delphi下使用indy进件socket通信的简单实例介绍

<br />      很久没有专门用过delphi 了,大概有二三年了吧,最近接手一与银行有关的项目,对方银行使用的是unix操作系统,用socket与项目程序进行通信。而这边项目肯定是要在windows下跑的,由于考虑到unix下socket采用的是阻塞式通信,由于项目紧张,思索再三,决定采用delphi的indy组件来编写服务器端的通信部分。其中通信的格式如下定义:<br /><br />信息段<br />类型<br />长度(单位:字节)<br />说明<br />包长<br />字符<br />6

hui717的专栏 1万+

利用Delphi Socket组件制作的简单TCP服务器和客户端

利用Delphi Socket控件开发的一个简单的TCP服务器和客户端。经过回送地址测试,本机IP和其它主机测试都可用。 TClientSocket 本来是D5默认安装的,但是D7使用的Indy组件后,就没有默认安装了,如果你喜欢这个组件,可以在delphi 7,delphi2007 delphi 2009 delphi 2010的安装目录lib文件夹或是bin文件夹找到dclsockets70.bpl or dclsockets100.bpl dclsockets140.bpl 组件包,安装上去就OK了.dclsockets70.bpl or dclsockets100.bpl dclsockets140.bpl 是TCientSocket和TServerSocket必需的运行包.

在Delphi 7 中用Indy开发Socket应用程序(下)

客户程序代码客户程序片断如代码列表1所示。代码列表1procedure TFormMain.BtnConnectClick(Sender: TObject);beginIdTCPClient.Host := EdtHost.Text;IdTCPClient.Port := StrToInt(EdtPort.Text);LbLog.Items.Add(正在连接 +

dingrj的专栏 3417

Delphi7 indy组件 已编译的indy组件 Internet组件

Delphi7 indy组件 Internet组件 已编译好的,添加到库文件就能用!

indy控件的应用

indy的简单应用,研究 INDY控件的应用,服务端反传给客户端一个文本文件的DEMO

【转】 delphi --- 用Indy组件开发Socket应用程序

最终编辑 e__jin Delphi 7中带有两套TCP Socket组件:Indy Socket组件(IdTCPClient和IdTCPServer)和Delphi原生的TCP Socket组件(ClientSocket和ServerSocket)。 但是,Borland已宣称ClientSocket和ServerSocket组件即将被废弃,建议用相应的In...

380

C#串口通讯实战:如何用SerialPort类搞定工业传感器数据采集(附完整代码)

本文详细介绍了如何使用C#的SerialPort类实现工业级传感器数据采集,涵盖串口通讯基础配置、数据帧处理、异常恢复机制及性能优化策略。通过实战代码示例,帮助开发者构建稳定可靠的工业数据采集系统,特别适合需要处理高频数据采集和复杂工业环境的场景。

weixin_42525551的博客 1085

[转]Delphi 7中用Indy组件开发Socket应用程序

 笔者在前一段的工作中,需要开发一套简单的网络数据传输程序。由于平时常用Delphi做点开发,故此次也不例外。Delphi 7中带有两套TCP Socket组件:Indy Socket组件(IdTCPClient和IdTCPServer)和Delphi原生的TCP Socket组件(ClientSocket和ServerSocket)。 但是,Borland已宣称ClientSocket和Serv...

weixin_30477797的博客 347

一种导弹追踪算法的MATLAB仿真实现

以下是一个用于模拟机动变轨导弹和防空导弹追踪过程的 MATLAB 代码,同时会提供 3D 效果展示。你可以运行这段代码,从而观察机动变轨导弹和防空导弹的速度与位置变化。

SmartGridequation的博客 933

U8+ 新建账套

一、登录 账套主管:demo 对账套有修改权限,有账套库权限 系统管理员:admin 其他所有权限 二、新建账套 admin登录–>点击系统管理–>账套–>建立 选择了参照已有账套结转期初:就是上一个的期末数据作为这一次新表的期初数据 启用会计期一旦选择更改不了。 ...

茶茶很困i 3693

在Delphi 7 中用Indy开发Socket应用程序

在Delphi 7 中用Indy开发Socket应用程序  作者:Scrub 笔者在前一段的工作中,需要开发一套简单的网络数据传输程序。由于平时常用Delphi做点开发,故此次也不例外。Delphi 7中带有两套TCP Socket组件:Indy Socket组件(IdTCPClient和IdTCPServer)和Delphi原生的TCP Socket组件(Cl

蚂蚁 863

BLE天线设计避坑:NRF52832官方50欧姆阻抗匹配的3个常见误区

本文深入解析NRF52832蓝牙SoC天线设计中的常见误区,重点探讨50欧姆阻抗匹配的3个关键问题:PCB板材介电常数差异、匹配元件寄生参数及VSWR测试。通过实测数据和优化方案,帮助工程师规避设计陷阱,提升BLE通信性能。

beer8的博客 214

[转]Delphi 7中用Indy组件开…

[转]Delphi 7中用Indy组件开发Socket应用程序 [转]Delphi 7中用Indy组件开发Socket应用程序  笔者在前一段的工作中,需要开发一套简单的网络数据传输程序。由于平时常用Delphi做点开发,故此次也不例外。Delphi 7中带有两套TCP Socket组件:Indy Socket组件(IdTCPClient和IdTCPServer)和Delphi原生的TC...

qizhanfeng的专栏 523

VM与欧姆龙PLC通讯设置:Fins TCP/UDP协议实战避坑指南

本文详细解析了VM视觉平台与欧姆龙PLC通过Fins TCP/UDP协议进行通讯的实战配置与避坑要点。文章对比了Fins TCP与Fins UDP的差异,推荐在多数工业控制场景下优先选用Fins TCP以保证可靠性,并深入讲解了网络设置、寄存器地址映射、轮询优化等核心配置步骤。同时,针对常见的多次触发拍照、数据解析错误等问题提供了具体的解决方案和调试技巧,旨在帮助工程师快速建立稳定高效的通讯连接。

e4f5g6h7的博客 594

数据资产可视化分析:PowerBI在大数据管理中的实战

目的:帮你搞懂“为什么数据资产需要可视化?”“PowerBI能帮企业解决什么问题?”,并掌握用PowerBI做大数据可视化的实战技巧。范围:覆盖数据资产定义、可视化分析原理、PowerBI核心功能(数据连接、建模、可视化)、零售企业实战案例,以及未来趋势与挑战。背景:为什么企业的数据像乱堆的玩具?核心概念:数据资产、可视化分析、PowerBI分别是什么?它们怎么配合?实战步骤:用PowerBI帮零售企业整理“销售玩具箱”,做出能指导决策的仪表盘;应用场景:不同部门怎么用这个“整理好的玩具箱”?

2501_92132293的博客 906

USEFUL LINKS ...

在Delphi 7 中用Indy开发Socket应用程序(上) - dingrj的专栏 - 优快云Blog在Delphi 7 中用Indy开发Socket应用程序(下) - dingrj的专栏 - 优快云Blog 如果使用TCP/IP,使用什么方法可以让一个服务器同时接受上千个客户端连接而且能高效的工作? 专题开发/技术/项目 / 网络通信 - 优快云社区 community.csdn.ne

runawaya的专栏 390

最佳RANSAC算法拟合矩形的实现(基于PCL库)

最佳RANSAC算法是一种常用的参数估计方法,用于从数据集中拟合出最佳的模型。在计算机视觉和图像处理领域,最佳RANSAC算法常用于拟合几何形状,如矩形。本文将详细介绍如何使用点云库(PCL)中的最佳RANSAC算法来拟合矩形,并提供相应的源代码。

JbPatch的博客 1541
上一篇: C++ Builder下三种UDP通信实现方法的比较 选择自 findheart 的 Blog
下一篇: J2ME的现状与发展
hawkzone
博客等级 码龄22年 1粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值