To read
TCP.GetResponse
TCP.SendCmd
TCP.Capture (Indy 10?)
May 26, 2006 Delphi Enterprise delivers all the tools necessary for developing, testing and deploying applications for Windows with a wide variety of reusable components included. The Enterprise edition contains additional tools and extensive options for Internet allowing easy and efficient application development. I just downloaded a version of INDY 10 (10.5.). According to the install i have 2 choices and i select this: 1) use the command-line FULLD#.BAT script that corresponds to your Delphi version.
7.6
TIdUDPClient is the base UDP client for sending UDP packets to other destinations. The mostcommonly used method is Send, which uses the Host and Port properties to send a UDP packet. Itaccepts a string as an argument.
There is also a SendBuffer method which performs the same task as Send, except that it accepts aBuffer and Size as arguments.
TIdUDPClient can also be used as a server of sorts to wait and receive incoming UDP packets on anindividual basis.
TIdUDPServer when active creates a listening thread to listen for inbound UDP packets. For each UDP packet received, TIdUDPServer will fire the OnUDPRead event in the main thread, or in the context of the listening thread depending on the value of the ThreadedEvent property.When ThreadedEvent is false, the OnUDPRead event will be fired in the context of the main program thread. When ThreadedEvent is true, the OnUDPRead event is fired in the context of the listener thread.When ThreadedEvent is true or false, its execution will block the receiving of more messages. Because of this the processing of the OnUDPRead event must be quick.
Infos
The TTL property is declared as protected in TIdRawBase, and TIdIcmpClient does not promote it to public. You will have to declare a descendant class to gain access to it, ie:
- type
- TIdIcmpClientAccess = class(TIdIcmpClient);
- procedure TMainForm.PingFirst;
- //...
- TIdIcmpClientAccess(IdIcmpClient1).TTL := CurrentTTL;
- //...
- end;
Introduction
Along with ICS and Synapse, Indy is one of the most use open-source set of Internet components. It supports HTTP, SMTP, ICMP, etc.
Note: All Indy exceptions descend from EIdException. By default, Delphi 7 has at least one item in Tools > Debugger Options > Language Exceptions related to Indy, 'Indy EIDSilentException Exceptions', and, possibly 'Indy EIDSocketError Exceptions'... which do not prevent the IDE to fail when running in the by design exception EIdSocketError 'Socket Error # 10004'. The reason is that the actual exception is 'EIdSocketError', not 'Indy EIDSocketError Exceptions'. Add the former through the Add button, don't forget to add IdException in the users section, and you won't be stopped by the IDE anymore.
Upgrading to Indy 10
Delphi 7 ships with Indy 9. Since the only documentation on the Indy website is now based on release 10, and some examples won't work with older releases, you must remove Indy 9 from the IDE, and install release 10.
There are two possibilities, but both require your uninstalling Indy 9 yourself before installing Indy 10:
- upgrade manually following thoses instructions: How do I install Indy into Borland Delphi?, Upgrading to Indy 10, [D7] Upgrade propre des composants Indy vers Indy 10.1.5?, [D7 Ent] How to upgrade Indy properly?, Indy 10 in Delphi 2006
- run the upgrader Indy Plus Install, free for personal or educational users, while commercial projects require buying the Indy Plus package
Removing Indy9:
- Close the Borland Delphi IDE if it is open.
- If you are using the version of Indy included in Delphi 6 or 7, use the MSI installer to remove Indy: In 'Program Files', click on the drop-down list before Indy, and select Do Not Install. If you didn't install Corba, uncheck 'Use Visibrocker/CORBA Support' before proceeding with the uninstall
- Remove all Indy files from the Delphi directory, including dclIndy*.bpl, Indy*.bpl, the Id*.pas, and the Id*.dcu's. Take care that you only remove the old Indy files and not something else. Be sure that you also remove any Indy*.bpl from your WindowsSystem32 directory (IndyCore70.bpl, IndyProtocols70.bpl, and IndySystem70.bpl)
- When restarting Delphi, it will fail loading the Indy 9 BPL: 'Error/Can't load package c:program filesborlanddelphiBindclindy70.bpl. The specified module could not be found. Do you want to attempt to load the package the next time a project is loaded?' Just tell it not to try reloading this package the next time.
Manually installing Indy10
- Place the new version of Indy in a directory of your choice. When unzipping, please keep the source directory for the archive intact because that is used by some build batch files.
- In the source directory, there are several batch files. Run the appropriate one for your version of Indy:
- FULLD4.BAT - Delphi 4
- FULLD5.BAT - Delphi 5
- FULLD6.BAT - Delphi 6
- FULLD7.BAT - Delphi 7
- These batch files create subdirectories in the main Indy directory folder. They are (D4 for Delphi 4, D5 for Delphi 5, D6 for Delphi 6, and D7 for Delphi 7). These directories contain:
- The Indy .DCU's
- The Indy Design-Time .BPL
- In your Delphi IDE, add the Indy design-time package with Component|Install Package...|Add... Go to the subdirectory where the Indy .DCU's and Design-Time .BPL was placed by the batch file. Add the Design-Time .BPL that is listed. It usually is named dclIndy followed by the Borland Delphi version and an 0
- Add the path where the .DCU's are located to your environment. Do this with Tools|Environment Options...|Library...|Library Path...
Free Download Indy 10 For Delphi 7 Download
(Difference with above instructions?) Compiling and installing manually:
Note: All packages are followed by X0 (Where X is your Delphi verison). Example: For Delphi 6, the IndySystem package would be named: IndySystem60.dpk
- Download the latest source code
- Open and compile .dpk files in the following order:
LibSystemIndySystemX0.dpk
LibCoreIndyCoreX0.dpk
LibProtocolsIndyProtocolsX0.dpk
LibSuperCoreIndySuperCoreX0.dpk
If you are not using SuperCore, then you do not need to compile this package. - Now open these .dpk files and click install in the following order:
LibCoredclIndyCoreX0.dpk
LibProtocolsdclIndyProtocolsX0.dpk
LibSuperCoredclSuperCoreX0.dpk
Only install this if you have compiled SuperCore.
After installing Indy 10, you might get the following error when adding a IdUDPServer widget and code for the UDPRead event: '[Error] Unit1.pas(15): Undeclared identifier: 'TBytes'
=> 'That is a known Delphi bug, not an Indy one. The bug is that Delphi parses the signature wrong when generating the event handler. As for why TIdBytes is used in the event, it is because the Intercept system in Indy 10 is based on TIdBytes to begin with. It Indy 9, it was based on Streams instead.'
Connecting to a server in TCP
Here's an example from Indy in Depth:
- uses [...] IdException;
- [...]
- try
- IdTCPClient1.Host := 'localhost';
- IdTCPClient1.Port := 80;
- try
- try
- IdTCPClient1.Connect;
- // Do your communications here
- finally
- IdTCPClient1.Disconnect;
- end;
- except //Failed during transfer
- on E: EIdException do begin
- ShowMessage('A network error occurred during communication: ' + E.Message);
- end;
- on E: Exception do begin
- ShowMessage('An unknown error occurred during communication: ' + E.Message);
- end;
- end;
- except //Couldn't even connect
- on E: EIdException do begin
- ShowMessage('An network error occurred while trying to connect: ' + E.Message);
- end;
- on E: Exception do begin
- ShowMessage('An unknown error occurred while trying to connect: ' + E.Message);
- end;
- end;
Downloading a web page into a variable
The easiest way is to use the open-source IdHTTP component provided with Delphi 6+ and located in the Indy Clients tab. Note that adding this component in a form adds the following units to the project: IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient:
- procedure TForm1.Button1Click(Sender: TObject);
- begin
- ShowMessage(IdHTTP1.Get('http://yahoo.com'));
- end;
Another way is to use UtilMind's freeware component HTTP GET ('This component intended for downloading files/documents/results of CGI scripts from the web using standard Microsoft Windows Internet library (winInet.dll) which also used by Internet Explorer.'):
Another way is to use the TDownloadUrl component (but data is saved into a file, not a variable)
- uses ExtActns;
- procedure TForm1.Button1Click(Sender: TObject);
- begin
- with TDownloadUrl.Create(Self) do
- try
- URL := 'http://www.acme.com/forum.asp?ID=123';
- FileName := 'forum.html';
- Execute;
- WebBrowser1.Navigate(ExtractFilePath(Application.ExeName) + 'forum.html');
- finally
- Free;
- end;
- end;
Here's how to download a bunch of files that have an increasing suffix:
- //From Simple HTML page scraping with Delphi
- function Download_HTM(const sURL, sLocalFileName:string): boolean;
- begin
- Result:=True;
- with TDownLoadURL.Create(nil) do
- try
- URL:=sURL;
- Filename:=sLocalFileName;
- try
- ExecuteTarget(nil);
- except
- Result:=False
- end;
- finally
- Free;
- end;
- end;
- procedure TForm1.Button1Click(Sender: TObject);
- const
- ADPNEWHOTURL='http://acme/picture_';
- var
- sPathToF : String;
- iIndex : Integer;
- sPictureFileName : String;
- begin
- sPathToPictures := ExtractFilePath(Application.ExeName) + 'pictures';
- if not DirectoryExists(sPathToPictures) then
- CreateDir(sPathToPictures);
- SetCurrentDir(sPathToPictures);
- For iIndex := 1 to 274 do begin
- sPictureFileName := 'picture_' + Format('%.4d', [iIndex]) + '.jpg';
- Label1.Caption := 'Source = ' + ADPNEWHOTURL + IntToStr(iIndex) + ' Target = ' + sPictureFileName;
- if NOT Download_HTM(ADPNEWHOTURL + IntToStr(iIndex),sPictureFileName) then begin
- ShowMessage('Error in HTML file download ' + IntToStr(iIndex));
- Exit;
- end;
- Application.ProcessMessages;
- end;
- end;
Downloading a web page using the POST method
- uses IdMultipartFormData;
- [...]
- data := TIdMultiPartFormDataStream.Create;
- try
- //Note: If the variable uses accented characters like é, type them as is,and
- //IdMultipartFormData will take care of the conversion to eg. %E9
- data.AddFormField('search', '1');
- //bad
- Memo1.Lines.Text := IdHTTP1.Post('http://www.acme.com/index.html', data);
- except
- //Note: Not called in IDE, but OK otherwise
- ShowMessage(intToStr(IdHTTP1.Response.ResponseCode));
- end;
- data.Free;
Pinging a server
Here's how to do it using Indy 9 (The version that ships with Delphi 7):
- procedure TForm1.Timer1Timer(Sender: TObject);
- var
- Icon: TIcon;
- Index : Integer;
- begin
- IdIcmpClient1.Host := '(some unreachable server here)';
- IdIcmpClient1.ReceiveTimeout := 2000; //2 seconds
- //Try/except to get rid of the Socket Error #10004 Interrupted System Call
- try
- IdIcmpClient1.Ping;
- except
- ShowMessage('Error when pinging');
- end;
- end;
- procedure TForm1.IdIcmpClient1Reply(ASender: TComponent; const AReplyStatus: TReplyStatus);
- begin
- if (AReplyStatus.ReplyStatusType = rsTimeOut) or (AReplyStatus.ReplyStatusType = rsErrorUnreachable) then begin
- Label1.Caption := 'Computer is down.';
- end else begin
- Label1.Caption := 'Packet round trip time: ' + IntToStr(AReplyStatus.MsRoundTripTime) + ' ms.';
- end;
- end;
Another example:
- uses
- Windows, [...] IdException;
- procedure TForm1.Timer1Timer(Sender: TObject);
- begin
- IdIcmpClient1.Host:= 'www.cisco.com';
- try
- IdIcmpClient1.Ping();
- except
- case IdIcmpClient1.ReplyStatus.ReplyStatusType of
- rsEcho:
- begin
- ListBox1.Items.Append(format('response from host %s in %d millisec.',
- [IdIcmpClient1.ReplyStatus.FromIpAddress,
- IdIcmpClient1.ReplyStatus.MsRoundTripTime]));
- end;
- rsError:
- ListBox1.Items.Append('Unknown error.');
- rsTimeOut:
- ListBox1.Items.Append('Timed out.');
- rsErrorUnreachable:
- ListBox1.Items.Append(format('Host %s reports destination network unreachable.',
- [IdIcmpClient1.ReplyStatus.FromIpAddress]));
- rsErrorTTLExceeded:
- ListBox1.Items.Append(format('Hope %d %s: TTL expired.',
- [IdIcmpClient1.TTL, IdIcmpClient1.ReplyStatus.FromIpAddress]));
- end; // case
- on E: EIdException do begin
- ListBox1.Items.Append('Error : ' + E.Message);
- end;
- end; //Except
- end;
Q&A
Indy vs. ICS vs. Synape
Those three open-source projects offer support for IP connections.
- Indy : blocking sockets make for easier programming; ships with Delphi; some incompatibilities between Indy 9 and 10 require rewriting code
- ICS :
- Synapse : doesn't install in the IDE, ie. no widgets in forms, just units
How to prevent the UI from freezing while waiting on a socket to respond?
'Indy has a special component that solves the User Interface freeze problem transparently. Simply add one TIdAntiFreeze anywhere in your application, and you can perform standard blocking Indy calls in your program without the User Interface being frozen.
Download Delphi 7 Free
Indy 10 Delphi Download
Since the user interface freeze is only affected by blocking calls in the main thread, TIdAntiFreeze only affects Indy calls made from the main thread. If an application uses Indy in threads, TIdAntiFreeze is not required. If used, it will only affect calls made from the main thread.'
Socket Error # 10004 Interrupted system call when using Indy components?
Delphi 10.3 Download
In Tools > Debugger Options > Language Exceptions, add EIdSocketError to the list of exceptions to ignore, and use a try/except to go around the exception.