Delphi application sending data to the server using the POST method (Indy). Indy components used in Delphi

Indy is a fairly powerful package of components that allows you to develop various network applications. In this tutorial I will tell you how you can create client-server applications using the TIdTCPClient and TIdTCPServer components.

First of all, I would like to note two important advantages of these components. The most important of them is multithreading, which means that the server creates a separate thread for each client, and this certainly affects the performance of the server program on computers with a multi-core processor. The second advantage is ease of use. 10-20 lines of code are enough to write a simple client-server application. This package of components is present in standard Delphi assemblies.

Let's write a simple program, which allows you to transfer a text message from a client to a server. Let's start creating the server.
Let's place the IdTCPServer component from the “Indy Servers” tab on the form. We will make all the settings for this component at runtime in the OnCreate event of the form:
IdTCPServer1.DefaultPort:= 12345;
IdTCPServer1.Active:= true;
Everything is simple here - we indicate the port on which the server will work, and activate the server itself.

In order to receive data on the server from the client, there is a special event “OnExecute”. This event looks like this:

begin
end;

Let's edit the event content as follows:
procedure TForm3.IdTCPServer1Execute(AContext: TIdContext);
var
l:string; // string variable into which we will receive
begin
l:= AContext.Connection.IOHandler.ReadLn();
Memo1.Lines.Add(l);
end;

Now, as soon as a message arrives on the server, we will write it to the string variable l and output it to a multi-line text field.

This, not surprisingly, ends the creation of the server. Indy will do the rest for us. Let's start with the client program. It will connect to the server, send a message to it, and disconnect from the server.

Let's create new project, place the IdTCPClient component on the form, which can be found on the “Indy Clients” tab. We will also place a simple Edit and a button. Let's create an OnClick event handler for the button, inside which we will write:
IdTCPClient1.Port:= 12345;
IdTCPClient1.Host:= '127.0.0.1';
IdTCPClient1.Connect;
IdTCPClient1.IOHandler.WriteLn(Edit1.Text);
IdTCPClient1.Disconnect;

This code does not need to be placed in the OnCreate event. You can place this code anywhere you want if you wish.
In the first line we assign a port, and it is necessary to specify the same port that we specified in the server program, otherwise the client simply will not find the server. Then we indicate the IP address of the server. The server itself can be located either in local network, and remotely. In the latter case, the connection will be made via the Internet and you will need to specify an IP address on the Internet.

I specified the address “127.0.0.1”, which means that the server is the computer on which the client is running. This method is very convenient for testing network applications.
Then we make a connection, send a message and disconnect. Just like the message itself, you can also take the IP address from Edit or from any string variable.

Work on the client program is also completed. As you can see, Indy does a tremendous job for us, which makes it possible for even an inexperienced programmer to create their own network application.

The UDP protocol is quite good for transmission text messages, that is, you can organize local chats and the like. I decided to give an example of the simplest work with UDP in Delphi.

Step-by-step instruction:

I gave an example, but forgive me, I didn’t write down every line, because... I don’t see anything complicated and anyone can figure it out.

Actually, if something is unclear, you can ask me a question. And here is the actual code:

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdUDPServer, IdBaseComponent, IdComponent, IdUDPBase,
IdUDPClient, IdSocketHandle;

type
TForm1 = class(TForm)
IdUDPClient1: TIdUDPClient;
IdUDPServer1: TIdUDPServer;
Button1: TButton;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button1Click(Sender: TObject);
procedure IdUDPServer1UDPRead(AThread: TIdUDPListenerThread; AData: TBytes;
ABinding: TIdSocketHandle);
private
(Private declarations)
public
(Public declarations)
end;

var
Form1: TForm1;

($R *.dfm)
[b]//Procedure for sending a message
procedure TForm1.Button1Click(Sender: TObject);
begin
try
IdUDPClient1.Active:= True;
IdUDPClient1.Host:= "localhost";
IdUDPClient1.Connect;
if IdUDPClient1.Connected then
begin
IdUDPClient1.Send(TimeToStr(Time));
Label1.Caption:= "ok";
end;
IdUDPClient1.Active:= False;
Beep;Beep;Beep;
except
MessageDlg("Something went wrong =(", mtError, , 0);
end;
end;
[b]
//On off. UDP server when starting and closing the form
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
IdUDPServer1.Active:= False;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
IdUDPServer1.Active:= True;
end;

[b]//Server reaction procedure when receiving data
procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
AData: TBytes; ABinding: TIdSocketHandle);
Var
i:Integer;
s:String;
begin
s:= "";
try
i:= 0;
while (AData[i] 0) do
begin
s:= s + chr(AData[i]);
i:= i + 1;
end;
finally
Label1.Caption:= s;
end;
end;

Serge Dosyukov Mike Pham

This article shows you how to create a standalone Web service using the Indy kit and Delphi 7, and how to use the Indy kit to support Delphi 7 SOAP-based Web services. Behind additional information For information on creating Web services, see Nick Hodges' excellent article on the Borland community site: Shakespeare on the Web.

Sooner or later, you may need to create a server that is a standalone HTTP server and supports Web services. For example, you might want to create a SOAP-based application server for an n-tier application built using Delphi.

Introduction

Delphi's online help provides excellent sequential instruction on how to create a Web service, MIDAS server (COM, DCOM model), but there is practically no information on creating a stand-alone n-tier MIDAS application based on the SOAP protocol.

Previously published by Dave Nottage. This article described the idea of ​​​​how to create a Web service in Delphi 6 with SOAP support and the ability to publish SOAP interfaces of the Datamodule, that is, this article allowed you to learn how to create your own n-tier MIDAS systems.

Borland's Delphi 7 and the new Indy kit have built-in support for this functionality.

However, despite built-in support, this feature is not documented.

Recent postings on the Borland networking conference and searching the web using a Google server have allowed the authors to develop a way to convert existing code from Delphi 6 to Delphi 7. But everything has its time.

main idea

This article is the first part of a three-part series. It describes the main provisions. The second and third parts will be devoted to some problems and ways to solve them. Let's start describing the main idea.

  • be a standalone HTTP server;
  • use Indy as a platform;
  • support publishing via SOAP protocol;
  • be capable of publishing SOAP DataModules, which would allow you to create your own n-tier server based on SOAP/HTML.

HTTP server and SOAP

Many people know Indy and have used THTTPServer components before. It's easy to put this component on an application form, but how do you make it support SOAP? In the directory "C:Program FilesBorlandDelphi7SourceIndy" you can find the file IdHTTPWebBrokerBridge.pas. This is exactly what you need.

This file is not part of the Indy executable, so you need to include it in your current project as a standard project file. (To compile the project, you will also need the IdCompilerDefines.inc file.) These files must be copied to the current project directory. Code changes may be required to increase speed, so it is best to keep these files separate from the Indy distribution.

The following describes the implementation of a replacement component from THTTPServer, extended to support SOAP packets, called TIdHTTPWebBrokerBridge. This construct is a class that inherits from TCustomHTTPServer and supports basic request binding.

Because this class is not accessible from the palette, you will need to define it as a regular object when executing your code.

This object can be used in exactly the same way as a regular THTTPServer, with the exception of those additional properties that enable operation with SOAP.
However, first let's look at preparing the necessary code.

WebBroker and Indy

For those who have created Web services before, you know that you use WebBroker. Delphi 7, like Delphi 6, uses the WebBroker architecture to support SOAP.

Therefore you need to create a module TWebModule and place the following three components in it: THTTPSoapDispatcher, THTTPSoapPascalInvoker and TWSDLHTMLPublish. All of them are available from the WebServices tab of the component palette. After linking SOAPDispatcher with SOAPPascalInvoker, the application form is ready. The end result should be something like what is shown in the following figure:

(module uWebModule.pas)

It's best to leave everything as is, since there is no need to change or execute any custom code for this form.

WebModule and Indy

Let's move on to the other part of the code needed to implement the HTTP server.

As you can see, TIdHTTPWebBrokerBridge has a RegisterWebModuleClass method, which allows you to register your own WebModule and make it available to the server.

Thus, after creating the fServer server object, you just need to call the fServer.RegisterWebModuleClass (TwmSOAPIndy) class.

Note. In a normal implementation of TIdHTTPWebBrokerBridge, a TwmSOAPIndy object will be created each time a request is received. Obviously this is not necessary. Therefore, the class can be modified to provide permanent creation of this object for as long as the Server object exists. It is recommended that you refer to the class implementation documentation for more information.

Is the server ready?

Indy components used in Delphi 6.

In addition to basic Internet services and protocols, there is a wide range of additional services, the capabilities of which are often used by Internet developers. In addition, the ability to display information using a browser is not always an acceptable solution for Internet applications. In this case, it is reasonable to use the Internet infrastructure for data exchange, and provide information display through more complex client applications developed, for example, in Delphi.

Let's say you need to implement specialized server logic that is not included in standard Web servers. To solve this class of problems, Delphi includes the Internet Direct (Indy) library from Nevrona Designs (http://www.nevrona.com/Indy/). This library, developed specifically for Borland Delphi, already has eight versions, the latest of which is included in new version Delphi. The set of components is divided into three groups: client (Indy Client), server (Indy Servers) and auxiliary (Indy Misc).

Indy Clients and Indy Servers

Majority Indy components Client and Indy Servers are pairs corresponding to the client and server parts of protocols and services (with the exception of individual, mainly server-based components such as TunnelMaster and TunnelSlave), and allow the use of protocols such as TCP/IP, UDP, NNTP, SMTP, FTP , HTTP, as well as ECHO, FINGER, WHOIS, etc. services.

Indy client components are written using sockets. The client side socket requires a connection to the server. If the connection is established, the client and server can begin exchanging messages. These messages are of a different nature, but usually the exchange occurs using a specific protocol (for example, HTTP)

TIdTCPClient and TIdTCPServer

These components are used to support one of the main network protocols - TCP (Transmission Control Protocol), and are also the base classes for the TIdSMTP and TIdFTP components. The TIdTCPServer class has a ThreadMgr property that defaults to nil. If ThreadMgr is nil when TIdTCPServer is enabled, the TIdThreadMgrDeafault class will be created implicitly. Otherwise, the installed process manager is used.

TIdUDPClient and TIdUDPServer

These components are used to support network protocol UDP (User Datagram Protocol) and are also the base classes for a number of other Indy components.

TIdChargenServer

The component is used to generate random symbols, usually for testing purposes.

TIdDayTime and TIdDayTimeServer

The components are used to provide time service. The client requests, and the server reports the current date and time.

TIdDNSResolver

This is a client component that serves requests from a DNS (Domain Name Service) server. DNS server queries are designed to replace a computer's name with its IP address. TIdDNSResolver is a descendant of the TIdUDPClient class.

TIdDICTServer

A server component that supports the Dictionary Server Protocol (DICT), a server-side dictionary based on the TCP protocol that allows a client to access a natural language dictionary.

TIdDISCARDServer

The server component that supports the records server. The recordings can be used as a debugging and measurement tool. The records service simply hands over any data to whoever is willing to receive it.

TI dEcho and TI dECHOServer

The components are designed to provide a response service, typically used to check the health of the network. The client sends a text message to the server, the server returns the message to the client. If the message is garbled, the network malfunctions.

TIdFinger and TIdFingerServer

The components are designed to provide a protocol that allows a user to query data regarding the presence of other users on the system. Some servers handle such client requests. Using this pair of components will allow you to service client requests that determine the presence of other users on the system.

The component includes full support for the file transfer protocol - FTP (File Transfer Protocol). Passive and active data transfer is supported, as well as operations such as GET and PUT, deleting directories, obtaining quotas, file and directory sizes. TI dFTP uses the TIdSimpleServer class to operate. When an FTP file transfer is in progress, a secondary TCP connection is opened for data transfer and is closed when the data has been transferred. This connection is called a "data link", unique for each file being transferred.

TIdGopher and TIdGopherServer

These components are designed to provide a network protocol that has been superseded in Lately from WWW ( World Wide Web) HTTP protocol. The server that implements this protocol provides a hierarchical distributed document flow support system. An example of using this pair of components, located in the demosindyGopherClient and demosindy GopherServer directory, demonstrates how using this protocol you can provide information on the local network about files located on your computer, including closed ones.

TIdHostNameServer

A server component designed to pass the local server name to clients.

TIdHTTP and TIdHTTPServer

The components are used to provide the HTTP network protocol (versions 1.0 and 1.1 are supported, including GET, POST and HEAD operations). In addition, support is provided for authentication and the use of proxy servers. The server component is used to provide services to another Web server that supports a given protocol. TIdHTTPServer facilitates the implementation of functions such as cookies, state management, etc.

TIdIcmpClient

A client component designed to provide the Internet Control Message Protocol (ICMP), which is used to perform ping operations and network tracing.

A client component designed to provide the Post Office Protocol (POP), including support for MIME encoding and decoding, and multibyte character transmission.

TIdIMAP4Server

A server component designed to support IMAP (Internet Message Access Protocol) operations on the server. The protocol allows you to search for messages Email on server. The difference between the IMAP and POP protocols is that the POP protocol requires additional memory to store data, and the IMAP protocol accesses the server instead of the client machine. IMAP4 was created to replace POP3, but POP3 remains a widely used standard to this day.

TIdIRCServer

A server component designed to support the most commonly used service operations on the Internet, commonly called chat. The component provides basic building blocks for IRC (Internet Relay Chat) server.

TIdMappedPortTCP

A server component designed to create mapped ports, which are often used in proxy servers. The methods of this component allow you to map one port to another. For example, port 80 could be mapped to port 3000, and all requests to the first port (port 80) would be forwarded to the second port (port 3000).

TIdNNTP and TIdNNTPServer

These components are required to support the Network News Transfer Protocol (NNTP) used in news services. The client component includes support for MIME encoding and decoding, as well as support for multibyte characters and alternate encodings. The server component allows you to create news servers. It is important to note that TIdNNTPServer is not a full-featured news server, but a component that provides the basic functionality for such a server.

TIdQOTD and TIdQOTDServer

The components are used to provide the Quote of the Day service. The client component connects to the server component instance to obtain the daily quote. Each server instance contains a unique citation database.

A client component designed for use in Simple Mail Transfer Protocol (SMTP) applications, providing support for authentication, MIME encoding and decoding, and multi-byte character support.

A client component designed to provide SNTP (Simple Network Time Protocol) - a time service. Can be used to connect to any time service to determine current dates and time.

TIdSimpleServer

Server component that provides a lightweight TCP server. Allows you to organize a point-to-point connection. It is used to create servers with a single user, that is, it can only serve one connection at a time. Unlike the TIdTCPServer component, it does not spawn secondary processes when waiting for requests from clients and when processing these requests. In other words, if the server is serving a request from a client, and at that time another client is contacting it to connect, then it will be blocked until the end of processing the first request.

TIdTelnet and TIdTelnetServer

The client component is used to organize remote sessions on another computer, including console negotiations and authentication. The communication protocol assumes the presence of a person interacting interactively with the server. The client component does not have display support or terminal emulation, but simply provides a connection to the server part. Typically, the TIdTelnetServer server protocol is used to organize remote databases with a text interface for interactive interaction with clients.

TIdTime and TIdTimeServer

The client component is an alternative to the TIdSNTP component for determining time. It is important to note that the formats of the two protocols are different. TIdTime is based on the RFC 868 format (returns the time in the internal UNIX OS standard, performing all necessary conversions). The server component is similar in functioning to the DayTime server. Can be used to implement a time service on local computer. No additional code is required, just create an instance of TIdTimeServer that will return the time of the server computer's internal clock.

TIdTrivialFTP and TIdTrivialFTPServer

These components are necessary to organize a simple file transfer protocol. The client component of this protocol is used to connect to an instance of the corresponding server component. The protocol is intended for private, lightweight, local cases of file transfer, for example in local area networks or for loading (uploading) routing tables into routers. Due to the weakened characteristics of this protocol, its use is not recommended when using authentication algorithms or any other security mechanisms. The main purpose of this protocol is to transfer files to a hardware device for the purpose of modifying it.

TIdTunnelMaster and TIdTunnelSlave

Server tunnel components are used in proxy servers to organize multiple logical connections over one physical (tunnel). These classes can be used for various purposes, for example, to organize a secret connection over non-secret channels.

TIdWhois and TIdWhoIsServer

This client component connects to any standard Whois server, allowing you to obtain information about domains. The server component provides the basic functionality of a NIC server.

Indy Misc

The Indy Miscellaneous Components palette page includes BASE64, UUE, Quoted Printable and other common email communication formats, encoders (MD2, MD4 and MD5) for cryptography standards used to store passwords and electronic signatures in an irreversible (hard to decipher) form, as well as many other useful components and utilities often used in the development of Internet applications.

TIdAntiFreeze

Due to the block-based algorithms of Indy components, it often appears that the application is stuck while the connection is working. To eliminate the use of secondary processes (threads) when organizing communications to prevent the application from freezing, it is enough to place the specified component on the form.

The component works by parsing requests from the TCP/IP protocol stack and sending messages to the application during the delay when external connections are blocked, which creates the illusion of running code. Since the component affects blocked connections only for the main process, the use of TIdAntiFreeze in secondary processes of the application is not required. Keep in mind that the TIdAntiFreeze component slows down connections because the main process is periodically interrupted to process messages. It follows that care must be taken to ensure that the application being developed does not spend too much time processing messages, including OnClick, OnPaint, OnResize, etc. To some extent, this can be controlled through the properties of the TIdAntiFreeze class. The use of this component is not mandatory, but it allows you to solve the problem of synchronizing connections with the visual interface of the application.

TIdDateTimeStamp

A class for performing date and time math related to the fact that Internet protocols use different date and time formats; in addition, clients and servers may be located in different time zones.

TIdIPWatch

It is a timer-based component that constantly monitors changes in the computer's IP address. Component events occur when a change is detected. This component is usually used to detect whether a computer is connected to the Internet or any other network. The change in IP address in this situation may occur due to the IP address being assigned by the DHCP (Dynamic Host Configuration Protocol) server when connecting to the new network.

TIdLogDebug

The purpose of this component is to intercept events of any client or server component and place a record of the event in specified file. This component is very useful for debugging Indy components.

TIdMessage

The component is used in combination with other components to properly decrypt or encode messages. These can be POP, SMTP and NNTP components. The class supports MIME encryption and decryption, multibyte characters, and ISO encoding.

TIdNetworkCalculator

One of the few Indy components that can be used when building applications. The network calculator can be used to perform calculations on IP addresses, including network masks, subnet, network classes, etc.

TIdThreadMgrDefault

The component provides control of secondary processes by default. Created when any Indy component that supports process management does not have an instance of the TIdThreadManager class defined. The component provides only basic capabilities for managing secondary processes: creating and destroying them on demand.

TIdThreadMgrPool

A more advanced process management component than TIdThreadMgrDefault because it merges processes rather than creating or destroying them on demand.

TIdVCard

VCard is the electronic equivalent of a business card and may contain the owner’s personal information and graphic data.

TIdIMFDecoder

Designed for decoding Internet messages. It is a descendant of the TIdCoder class, just like all other encoder components. The TIdCoder class decodes according to the ARPA Internet text message format standard RFS-822, proposed in August 1982, and the USENET messaging standard RFC 1036, proposed in December 1987.

The component extends the TIdCoder class to allow detection of RFS-822 format by header context, providing decrypt-on-receive mode and MIME encryption and decryption. The TIdIMFDecoder component is used in the TIdMessageClient class to decode received and transmitted messages.

TIdQuotedPrintableEncoder

QuotedPrintableEncoder allows you to decrypt text in the specified format. Can serve as a standalone component with a specified encoding type, allowing messages containing a new encoding type to be transmitted.

TIdBase64Encoder

Implements another encryption algorithm that makes it possible to transmit non-printable characters.

TIdUUEncoder

Implements one of the first encryption algorithms, UU encoding. Sometimes used when mailing articles to a news service.

TIdXXEncoder

This encryption method is unlikely to ever be used. Essentially, this is the same UU encoding, but with a different encryption table.

TIdCoderMD2

Components with different types of MD (Message Digest) encryption algorithm. They are all shuffle-based, one-way, and have no decryption algorithms.

Components of protocol clients and servers can be used to develop server and client Internet applications, together with or instead of basic ones (ClientSocket, ServerSocket) and other components from the Internet and Fastnet palette. Indy components do not use the WebBroker architecture, implementing low-level support for Internet protocols and services directly in their source code ( source codes are attached).

TIdConnectionInterceptOpenSSL and TIdServerInterceptOpenSSL

The SSL protocol - Secure Sockets Layer, which ensures the secrecy and reliability of communication between two applications, has two layers. At the low level of a multi-layer transport protocol (such as TCP), SSL is a recording protocol and is used to encapsulate various higher-level protocols. The advantage of SSL is that it is an independent application protocol, but a higher-level protocol can be used on top of SSL.

SSL provides communication security, which has three main functions: providing a confidential connection; encryption with public key(used to confirm the authenticity of the addressee); support for data transmission reliability.

  • Symmetric cryptography is used to encrypt data (eg DES, RC4, etc.).
  • Digital signature is provided using asymmetric public key encryption (for example, RSA, DSS, etc.).
  • Reliability of communication, message transport includes checking the integrity of the message through MAC correction codes, secure hash functions (eg, SHA, MD5, etc.) using MAC calculations.

Combined with HTTP and server authentication, SSL provides necessary functions encryption and further maintains the established connection, double-checking the authenticity of the Web server, etc. It is important to understand that SSL only protects communications during data transfer and does not replace other security mechanisms.

The TIdConnectionInterceptOpenSSL and TIdServerInterceptOpenSSL components provide both client-side and server-side connections using the SSL protocol. It should be noted that the TIdConnectionInterceptOpenSSL and TIdServerInterceptOpenSSL components are only available in Delphi 6, and not in Kylix. This is due to the complexity of the protocol, which in the case of a Windows implementation is based on operating system functions.

Examples of using Indy components can be found in the /Delphi6/Demos/Indy directories. In total, the Indy library in version 8.0 contains 69 components. It is stated that in version 9.0 the specified library will contain 86 components. All components are unified and included in both Delphi 6 and Kylix, which allows them to be used for developing cross-platform applications. All Indy components support multithreading.

The Indy components implement almost all the functionality found in the Internet and Fastnet components, as is clearly shown in the table.

Fastn et components Indy components Purpose of components
1 TserverSocket, TClientSocket TIdTCPserverSocket, TIdTCPClientSocket Interaction between two computers (client and server) using the TCP/IP protocol
2 TNMDayTime TIdDayTime, TIdDayTimeServer Query the server for the current time
3 TNMEcho TIdEcho, TIdEchoServer Used to communicate with the response server
4 TNMFinger TIdFinger, TIdFingerServer Used to obtain information about the user from an Internet search server
5 TNMFTP TIdFTP, TIdTrivialFTP, TIdTrivialFTPServer Provide file transfer using FTP protocol
6 TNMHTTP TIdHTTP, TIdHTTPServer Use HTTP protocol for data exchange
7 TNMMsgServ, TNMMsg Used to transmit simple text messages from client to server
8 TNMNNTP TIdNNTP, TIdNNTPServer Supports data exchange with news server
9 TNMPOP3 TIdPOP3 Used to receive email from a mail server using the POP3 protocol
10 TNMSMTP TIdSMTP Used to send email via Internet mail server
11 TNMStrm, TNMStrmServ Transmits binary data written to a stream using the TCP/IP protocol
12 TNMUDP TIdUDP, TIdUDPServer Transfer data using the UDP protocol
13 TpowerSock, TNMGeneralServer Component-encapsulated classes that are the basis for writing your own clients (Powersock) and servers (NMGeneralServer)
14 TNMUUProcessor TIdUUEncoder, TIdUUDecoder Carry out recoding binary files to MIME or UUENCODE format
15 TNMURL Converts strings to HTML format and performs reverse recoding

The exceptions are classes such as TNMMsgServ, TNMMsg, TNMStrm, TNMStrmServ, TpowerSock, TNMGeneralServer, TNMURL, which either implement obsolete protocols or have functionality implemented in a large group of alternative classes.

However, unlike its predecessors - the Internet and Fastnet components, Indy contains richer server components and components for data transcoding and encryption, as well as authentication support (Indy Misc palette). As can be seen from the table above, the main protocols and services are provided not only by client, but also by server components. These are time services, response services, obtaining user information, as well as HTTP, NNTP, UDP protocols and even the simplest version of FTP.

Some examples of using Indy components

In Indy components contained in Delphi, the IP address is defined in the Host property, typically only in client applications. Server-hosted components have methods that allow you to start or stop polling the corresponding port - for example, changing the Active property of the IdTCPServer component starts or stops polling the corresponding port. Once the connection between the client and server is established, data transfer can begin.

Indy components place great emphasis on security and reliability when working with data. For example, the IdTCPClient component has Connect and Disconnect methods. Using a programming technique like the below code from the client side:

With TCPClient do begin Connect; try lstMain.Items.Add(ReadLn); finally Disconnect; end; end;

and using the Connection property passed as a parameter to the AThread instance of the TIdPeerThread class from the server side:

With AThread.Connection do begin WriteLn("Hello from Basic Indy Server server."); Disconnect; end;

you can count on either the normal execution of the connection or the correct error handling.

Note the ReadLn and WriteLn methods of the corresponding classes - they resemble standard Pascal I/O statements. This is a tribute to the UNIX programming technique, where most system operations are performed by reading and writing to the corresponding files.

Just like Fastnet components, Indy component classes have events that can be used to provide event management. For example, you can arrange for a message to be displayed on a form when connecting to a client:

Procedure TForm1.IdECHOServer1Connect(AThread: TIdPeerThread); begin lblStatus.caption:= "[ Serving client ]"; end;

Indy provides components that implement protocols with client and server parts that are unique to this library. The TIdGopherServer and TIdGopher components, thanks to the GetExtendedMenu, GetFile, GetMenu, GetTextFile methods on the client side and ReturnGopherItem, SendDirectoryEntry on the server side, help to view files various types, including those marked as hidden, as well as directories on remote computer(similar to what the dir *.* command does in operating system MS-DOS).

Using the IdSMTP and IdMessage components, you can easily create your own Web application that can send mail using the SMTP protocol.

In this case, the IdMessage class (one of 23 components from the Indy Misc page) is responsible for generating the message, which follows from its name, and IdSMTP is for organizing the connection with the mail server.

The technology used in Indy uses locking read and write operations. Any Connect operation used in Indy waits for the connection to complete. When working with Indy client components, you typically need to do the following:

  • request a connection to the server;
  • make read and write requests to the server (depending on the type of server, the step is performed once or repeated many times);
  • end the connection to the server and disconnect.

Indy components are designed to provide an ultra-high level of abstraction. The intricacies and details of the TCP/IP stack are hidden from the programmer so that he can focus on the task at hand.

The following small example shows a typical client bean session:

With IndyClient do begin Host:= "zip.pbe.com"; // Host to call Port:= 6000; // Port to call the server on Connect; try // Your code goes here finally Disconnect; end; end;

In the example, even if the connection to the server is not established, the connection will be gracefully terminated due to the use of the try-finally statement.

Indy's server components describe a variety of server models that can be used depending on your needs and the protocol you're using.

TIdTCPServer is the most commonly used server component, which creates a secondary process independent of the main application process. The created process waits for incoming requests from potential clients. An individual secondary process is created for each client whose request it responds to. Events that occur during the maintenance process are related to the context of the corresponding processes.

In other words, for each client connection, the TIdTCPServer class uses a unique secondary thread by calling that thread's OnExecute event handler. The formal parameter of the OnExecute method is a reference to an instance of the Athread class corresponding to the created thread. The Connection property of this class is a reference to the TIdTCPConnection class, an instance of which is created to process the client request. TIdTCPConnection supports reading and writing over the connection, as well as establishing and terminating a communication session.

The UDP protocol works without first establishing a connection with the server (each sent packet is an independent set of data, and not part of a larger session or connection). While TIdTCPServer spawns separate threads for each connection, TIdUDPServer uses either a main thread or a single secondary thread that handles all UDP protocol requests. When TIdUDPServer is active, a thread is created to listen for incoming UDP packets. For each packet received, an OnUDPRead event is raised either on the main thread or in the context of the listening thread, depending on the value of the ThreadedEvent property. When ThreadedEvent evaluates to False, the event occurs on the main thread, otherwise it occurs on the listening thread. While the event is being processed, other server operations are blocked. Therefore, it is important to ensure that OnUDPRead procedures run as quickly as possible.

If you need to create a new client application for an existing server using an existing protocol, your job is solely to develop and debug the client application. However, when you have to develop both client and server application Whether using an existing or a new protocol, we are faced with the classic “chicken and egg” problem. Where to start programming - from the client or from the server?

Obviously, both the client and the server must be created eventually. For many applications, especially those using a text-based protocol (such as HTTP), it is easier to start building the application by designing the server. And for debugging there is a convenient client that already exists. This is a Telnet console application that is available on both Windows and UNIX.

If you type the console telnet command 127.0.0.1 80 with the IP address of the local computer and port number 80, which is used by default by Web servers, then the application will respond with the text shown in Fig. 6, in case of Windows 2000 OS and IIS 5.0.

To create the simplest server using Indy components you need:

If you need to design a server that will not only correctly inform its clients when the connection is lost, but also provide them with information about error situations that have occurred, use the try-except statement instead of try-finally - for example, as shown in the following example:

Procedure TDataModule1.IdTCPServer1Execute(AThread: IdPeerThread); var s: String; begin with AThread.Connection do try try s:= ReadLn; // Perform the task of the server here // if no exception is raised, // write out the server's response WriteLn(s); except on e: Exception do begin WriteLn(e.Message); end; //on end; //try except finally Disconnect; end; end;

This small example demonstrates the steps to create a simple text server, as well as how to debug it.

The server described above is a typical example of the organization of modern distributed computing.

Features of creating multi-tier applications

Recently, multiple servers are increasingly being used to satisfy client requests. A server of this type, having received a client request and partially prepared it for further processing, contacts another server and sends it the transformed request or requests. The second-tier server can, in turn, communicate with other servers. Thus, we can talk about a multi-tier server architecture.

Next we will create a data access server whose purpose is to return data from the database. This server, however, does not read or write to the database files directly. Instead, it communicates with the database server in search of the data required by the client.

So, we start developing an application with a three-tier architecture. To create a database server using Indy components you need:

  1. Create a new project.
  2. Place on main form project instance of the TIdTCPServer component from the Indy Servers palette.
  3. Set the DefaultPort property of the TIdTCPServer1 class instance to 6001 (it is recommended to assign large values ​​to avoid duplicating port numbers across different applications), and set the Active property to true.
  4. Add a new module to the project by selecting the File | New | Data Module, and place instances of the SQLConnection and SQLDataSet components on it from the dbExpress tab on the components palette.
  5. Set the ConnectionName property of the SQLConnection class to IBLocal and LoginPrompt to False. If you have not configured IBLocal on the employee.gdb database, complete this procedure first.

Hi all!

When developing the next Web project, the task arose - to implement client software in Delphi, which would transfer data to the server using the POST method. The application must transmit text and upload files to the Web server.

Implementation of such data sending using server-side languages Web development(for example, PHP) is quite simple, but if you need to write application-based, multi-user software that interacts with the server, then it’s a little more complicated. The method of directly connecting to the database and via FTP to the server from Delphi is no longer necessary because it is not safe, not reliable (changing passwords, connection data, etc.) and creates additional. software compatibility problems on the client side. To solve the problem, I decided to write scripts (server part) in PHP that will process incoming POST requests and return the result to the client (Delphi application). The advantages of this approach are that all connections and data processing occur on the server, which is much safer than a direct “connection”.

When I started googling, a lot of scattered information was given up, mostly on forums, but it was all in pieces. One thing was certain that Indy would be used, namely the IdHTTP component with the POST method implemented. In fact, everything is simple, this method takes two parameters Url of a resource and DataStream (data stream), and returns the result in text form (it can also be the HTML code of the page). The main thing was the correct formation of the DataStream (stream of transmitted data), but along the way additional pitfalls emerged, namely the Russian encoding (if it were not good). This is where the fun began for several hours of wandering around the Internet. In general, enough chatter, let's move on to practice and implementation of the software.

So the program is simple. She must send data to the server using the POST method, the data contains " Heading " (line), " Description » ( multiline text) And graphic file(jpg,png,gif-binary data). The server must accept this data, process it, save the graphic file on the server and return a response. As a response, we will return Delphi to the application, the same text only with added labels and a link to the downloaded file. Nothing else.

Let's start with the implementation of the server part (similar to the site's API). Open any text editor(notepad) and write the following code in it:

"; ) else ( echo "Title: Missing"."
"; ) //Check the incoming data for the presence of the "content" field data if (!empty($_POST["content"]))( echo "Content: ".$_POST["content"]."
"; ) else ( echo "Content: Missing"."
"; ) //Check the incoming data for the presence of an attached file "file" if (!empty($_FILES["file"])) ( $finfo = pathinfo($_FILES["file"]["name"]); / /get information about the file (name, extension, etc.) //Check the file type in the list of allowed types (IMPROVISATION:)) if (stripos("jpgpnggif",$finfo["extension"])==0)( echo ">>>>>>>Invalid file type<<<<<<<<"; exit; //Если не допустим тип, полностью останавливаем скрипт } $fname = "files/" . "testimgfile." . $finfo["extension"]; //формируем путь и новое имя файла move_uploaded_file($_FILES["file"]["tmp_name"],$fname);//сохраняем временный файл "tmp_name" в файл $fname echo "http://".$_SERVER["HTTP_HOST"]."/".$fname; //возвращаем полный путь к файлу } ?>

note! When saving (via notepad), you must specify the encoding “UTF-8”, otherwise there will be problems with displaying the Cyrillic alphabet!

The script tried to provide detailed comments. Copy this script to your Web server, if you don’t have one, you can use my script for the test, it is located at: http://api..php

The layout uses the following components: Label, Button (2 pcs.), Edit (2 pcs.), Memo (2 pcs.), CheckBox, OpenDialog, IdHTTP. Give the following components names (property “ Name”):

  1. Edit(title) – Name=title;
  2. Edit(path to file) Name = imgfile;
  3. Memo(Contents)Name = content;
  4. Memo(Result) – Name = response;
  5. Button(…) – Name = chkfile;
  6. Button(POST) – Name = PostBut;
  7. OpenDialog (File selection dialog) – Name = PictDialog;

Let's leave IdHTTP1 and CheckBox1 unchanged (tired! :)))).

So as not to accidentally " edit» path to Edit( imgfile), set its ReadOnly property to True. Likewise, at imgfile And chkfile Set the Enabled property to false. We will activate them using CheckBox, i.e. We will provide the opportunity to choose whether to upload an image or not.

For OpenDialog( PictDialog) you need to set the filter (Filter property) as follows:

The actual visual preparation is over! Let's start coding!

In the project we will generate a data flow using the type included with Indy - TidMultiPartFormDataStream. Although we came across implementation options using TStream, working with TidMultiPartFormDataStream – easier!

To make this type available to our project, we need to add the following library to Uses: IdMultipartFormData.

For CheckBox1, create an OnClick event (by double-clicking the mouse on the object) and add the following code to this event:

Procedure TForm1.CheckBox1Click(Sender: TObject); begin //make active or inactive the file path elements and dialog buttons imgfile.Enabled:=CheckBox1.Checked; chkfile.Enabled:=CheckBox1.Checked; end;

Here we activate the objects imgfile Andchkfile depending on the presence of a checkmark (if the checkbox is checked, then the objects become active).

Now let's organize the image selection. To do this, create an OnClick event on the button chkfile(also by double clicking on the object) and write the following:

Procedure TForm1.chkfileClick(Sender: TObject); begin //open the dialog and enter the full path to the file in imgfile(TEdit) if PictDialog.Execute then imgfile.Text:= PictDialog.FileName; end;

This event will trigger an image selection dialog and if the user clicks " Open", then the path to this file will be added to imgfile.

And now we come to the final “POST” button. Create an OnClick event for this button and add the following code:

Procedure TForm1.PostButClick(Sender: TObject); var dataPost:TIdMultiPartFormDataStream; begin dataPost:=TIdMultiPartFormDataStream.Create; dataPost.AddFormField("title",title.Text,"utf-8").ContentTransfer:= "8bit"; dataPost.AddFormField("content",content.Text,"utf-8").ContentTransfer:= "8bit"; if CheckBox1.Checked and (trim(imgfile.Text)="") then //checking whether the file is selected or not begin ShowMessage("You must select a graphic file!"); exit; end; if CheckBox1.Checked then dataPost.AddFile("file",imgfile.Text,""); //add a field with the file response.Text:= StringReplace(idHTTP1.Post("http://api..php",dataPost),"
",#13#10,); datapost.Free; end;

So, in order (although there are comments):

Datapost – object of type TIdMultiPartFormDataStream. Allows you to create a POST request structure consisting of fields of different types.

dataPost . AddFormField (" title ", title . Text ," utf -8 "). ContentTransfer := " 8 bit "; – adds a field named “title” to the DataPost, a value from “title.Text”, sets the encoding of the transmitted data to “utf-8” (the parameter is optional, but without its explicit indication, Cyrillic is transmitted with question marks “?”) and a very important method "Content Transfer". Without this method, data is sent to the server " abracadabra" Please note that the field name (“title”) on the sending side must match the name specified in the script: $_POST["title"].

Data is transferred similarly to the “content” field.

dataPost . AddFile (" file ", imgfile . Text ,"") – with this line we create a stream with data from the file.

That's it, the data is generated, all that remains is to transfer it to the script on the server and receive a response:

response.Text:= StringReplace(idHTTP1.Post("http://api..php",dataPost),"
",#13#10,);

because TMemo does not understand the line break tag "
", we will use the " " function to replace it with understandable line breaks "#13#10".

When everything is complete, clear the memory from the DataPost object with the line:

datapost.Free;

Although in our example this will happen automatically at the end of the procedure, but still...

The actual result of the program on the screen:

Thus, we can send as much data or files to the server as we want, process this data on the server and report back to the application the result of the script. It could even be just 0 or 1, which will signal the application to react further.

All. Good luck to all. I hope the information was useful and you will find use for it.

You can download the finished example and script.

Full module code:

Unit PostUnit; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, IdMultipartFormData, Vcl.ExtDlgs; type TForm1 = class(TForm) IdHTTP1: TIdHTTP; title: TEdit; content: TMemo; PostBut: TButton; response: TMemo; Label1: TLabel; Label2: TLabel; Label3: TLabel; imgfile:TEdit; chkfile: TButton; Label4: TLabel; CheckBox1: TCheckBox; PictDialog:TOpenDialog; procedure PostButClick(Sender: TObject); procedure chkfileClick(Sender: TObject); procedure CheckBox1Click(Sender: TObject); private ( Private declarations ) public ( Public declarations ) end; var Form1: TForm1; implementation ($R *.dfm) procedure TForm1.CheckBox1Click(Sender: TObject); begin //make active or inactive the file path elements and dialog buttons imgfile.Enabled:=CheckBox1.Checked; chkfile.Enabled:=CheckBox1.Checked; end; procedure TForm1.chkfileClick(Sender: TObject); begin //open the dialog and enter the full path to the file in imgfile(TEdit) if PictDialog.Execute then imgfile.Text:= PictDialog.FileName; end; procedure TForm1.PostButClick(Sender: TObject); var dataPost:TIdMultiPartFormDataStream; begin dataPost:=TIdMultiPartFormDataStream.Create; dataPost.AddFormField("title",title.Text,"utf-8").ContentTransfer:= "8bit"; dataPost.AddFormField("content",content.Text,"utf-8").ContentTransfer:= "8bit"; if CheckBox1.Checked and (trim(imgfile.Text)="") then //checking whether the file is selected or not begin ShowMessage("You must select a graphic file!"); exit; end; if CheckBox1.Checked then dataPost.AddFile("file",imgfile.Text,""); //add a field with the file response.Text:= StringReplace(idHTTP1.Post("http://api..php",dataPost),"
",#13#10,); datapost.Free; end; end.