Tải bản đầy đủ (.pdf) (111 trang)

Developer’s Guide Borland Delphi 7 for Windows PHẦN 9 pptx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (601.79 KB, 111 trang )

38-16
Developer’ s Guide
Writing servers that support Web Services
Defining and using SOAP headers
The SOAP encoding of a request to your Web Service application and of the response
your application sends include a set of header nodes. Some of these, such as the
SOAP Action header, are generated and interpreted automatically. However, you
can also define your own headers to customize the communication between your
server and its clients. Typically, these headers contain information that is associated
with the entire invokable interface, or even with the entire application, rather than
just the method that is the subject of a single message.
Defining header classes
For each header you want to define, create a descendant of TSOAPHeader.
TSOAPHeader is a descendant of TRemotable. That is, SOAP header objects are simply
special types of remotable objects. As with any remotable object, you can add
published properties to your TSOAPHeader descendant to represent the information
that your header communicates. Once you have defined a SOAP header class, it must
be registered with the remotable type registry. For more information about remotable
objects, see “Using remotable objects” on page 38-6. Note that unlike other remotable
classes, which are registered automatically when you register an invokable interface
that uses them, you must explicitly write code to register your header types.
TSOAPHeader defines two properties that are used to represent attributes of the
SOAP header node. These are MustUnderstand and Actor. When the MustUnderstand
attribute is True, the recipient of a message that includes the header is required to
recognize it. If the recipient can’t interpret a header with the MustUnderstand
attribute, it must abort the interpretation of the entire message. An application can
safely ignore any headers it does not recognize if their MustUnderstand attribute is
not set. The use of MustUnderstand is qualified by the Actor property. Actor is a URI
that identifies the application to which the header is directed. Thus, for example, if
your Web Service application forwards requests on to another service for further
processing, some of the headers in client messages may be targeted at that other


service. If such a header includes the MustUnderstand attribute, you should not abort
the request even if your application can’t understand the header. Your application is
only concerned with those headers that give its URL as the Actor.
Sending and receiving headers
Once you have defined and registered header classes, they are available for your
application to use. When your application receives a request, the headers on that
message are automatically converted into the corresponding TSOAPHeader
descendants that you have defined. Your application identifies the appropriate
header class by matching the name of the header node against the type name you
used when you registered the header class. Any headers for which it can’t find a
match in the remotable type registry are ignored (or, if their MustUnderstand attribute
is True, the application generates a SOAP fault).
You can access the headers your application receives using the ISOAPHeaders
interface. There are two ways to obtain this interface: from an instance of
TInvokableClass or, if you are implementing your invokable interface without using
TInvokableClass, by calling the global GetSOAPHeaders function.
Using Web Services
38-17
Writing servers that support Web Services
Use the Get method of ISOAPHeaders to access the headers by name. For example:
TServiceImpl.GetQuote(Symbol: string): Double;
var
Headers: ISOAPHeaers;
H: TAuthHeader;
begin
Headers := Self as ISOAPHeaders;
Headers.Get(AuthHeader, TSOAPHeader(H)); { Retrieve the authentication header }
try
if H = nil then
raise ERemotableException.Create('SOAP header for authentication required');

{ code here to check name and password }
finally
H.Free;
end;
{ now that user is authenticated, look up and return quote }
end;
If you want to include any headers in the response your application generates to a
request message, you can use the same interface. ISOAPHeaders defines a Send
method to add headers to the outgoing response. Simply create an instance of each
header class that corresponds to a header you want to send, set its properties, and
call Send:
TServiceImpl.GetQuote(Symbol: string): Double;
var
Headers: ISOAPHeaers;
H: TQuoteDelay;
TXSDuration Delay;
begin
Headers := Self as ISOAPHeaders;
{ code to lookup the quote and set the return value }
{ this code sets the Delay variable to the time delay on the quote }
H := TQuoteDelay.Create;
H.Delay := Delay;
Headers.OwnsSentHeaders := True;
Headers.Send(H);
end;
Handling scalar-type headers
Some Web Services define and use headers that are simple types (such as an integer
or string) rather than a complex structure that corresponds to a remotable type.
However, Delphi’s support for SOAP headers requires that you use a TSOAPHeader
descendant to represent header types. You can define header classes for simple types

by treating the TSOAPHeader class as a holder class. That is, the TSOAPHeader
descendant has a single published property, which is the type of the actual header.
To signal that the SOAP representation does not need to include a node for the
TSOAPHeader descendant, call the remotable type registry’s RegisterSerializeOptions
method (after registering the header type) and give your header type an option of
xoSimpleTypeWrapper.
38-18
Developer’ s Guide
Writing servers that support Web Services
Communicating the structure of your headers to other applications
If your application defines headers, you need to allow its clients to access those
definitions. If those clients are also written in Delphi, you can share the unit that
defines and registers your header classes with the client application. However, you
may want to let other clients know about the headers you use as well. To enable your
application to export information about its header classes, you must register them
with the invocation registry.
Like the code that registers your invokable interface, the code to register a header
class for export is added to the initialization section of the unit in which it is defined.
Use the global InvRegistry function to obtain a reference to the invocation registry
and call its RegisterHeaderClass method, indicating the interface with which the
header is associated:
initialization
InvRegistry.RegisterInterface(TypeInfo(IMyWebService)); {register the interface}
InvRegistry.RegisterHeaderClass(TypeInfo(IMyWebService), TMyHeaderClass); {and the header}
end.
You can limit the header to a subset of the methods on the interface by subsequent
calls to the RegisterHeaderMethod method.
Note
The implementation section’s uses clause must include the InvokeRegistry unit so
that the call to the InvRegistry function is defined.

Once you have registered your header class with the invocation registry, its
description is added to WSDL documents when you publish your Web Service. For
information about publishing Web Services, see “Generating WSDL documents for a
Web Service application” on page 38-19.
Note
This registration of your header class with the invocation registry is in addition to the
registration of that class with the remotable type registry.
Creating custom exception classes for Web Services
When your Web Service application raises an exception in the course of trying to
execute a SOAP request, it automatically encodes information about that exception in
a SOAP fault packet, which it returns instead of the results of the method call. The
client application then raises the exception.
By default, the client application raises a generic exception of type
ERemotableExceptionwith the information from the SOAP fault packet. You can
transmit additional, application-specific information by deriving an
ERemotableException descendant. The values of any published properties you add to
the exception class are included in the SOAP fault packet so that the client can raise
an equivalent exception.
To use an ERemotableException descendant, you must register it with the remotable
type registry. Thus, in the unit that defines your ERemotableException descendant, you
must add the InvokeRegistry unit to the uses clause and add a call to the
RegisterXSClass method of the object that the global RemTypeRegistry function
returns.
Using Web Services
38-19
Writing servers that support Web Services
If the client also defines and registers your ERemotableException descendant, then
when it receives the SOAP fault packet, it automatically raises an instance of the
appropriate exception class, with all properties set to the values in the SOAP fault
packet.

To allow clients to import information about your ERemotableException descendant,
you must register it with the invocation registry as well as the remotable type
registry. Add a call to the RegisterException method of the object that the global
InvRegistry function returns.
Generating WSDL documents for a Web Service application
To allow client applications to know what Web Services your application makes
available, you can publish a WSDL document that describes your invokable
interfaces and indicates how to call them.
To publish a WSDL document that describes your Web Service, include a
TWSDLHTMLPublish component in your Web Module. (The SOAP Server
Application wizard adds this component by default.) TWSDLHTMLPublish is an
auto-dispatching component, which means it automatically responds to incoming
messages that request a list of WSDL documents for your Web Service. Use the
WebDispatch property to specify the path information of the URL that clients must
use to access the list of WSDL documents. The Web browser can then request the list
of WSDL documents by specifying an URL that is made up of the location of the
server application followed by the path in the WebDispatch property. This URL looks
something like the following:
/>Tip
If you want to use a physical WSDL file instead, you can display the WSDL
document in your Web browser and then save it to generate a WSDL document file.
Note
In addition to the WSDL document, the THWSDLHTMLPublish also generates a WS-
Inspection document to describe the service for automated tools. The URL for this
document looks something like the following:
/>It is not necessary to publish the WSDL document from the same application that
implements your Web Service. To create an application that simply publishes the
WSDL document, omit the code that implements and registers the implementation
objects and only include the code that defines and registers invokable interfaces,
remotable classes that represent complex types, and any remotable exceptions.

By default, when you publish a WSDL document, it indicates that the services are
available at the same URL as the one where you published the WSDL document (but
with a different path). If you are deploying multiple versions of your Web Service
application, or if you are publishing the WSDL document from a different
application than the one that implements the Web Service, you will need to change
the WSDL document so that it includes updated information on where to locate the
Web Service.
38-20
Developer’ s Guide
Writing clients for Web Services
To change the URL, use the WSDL administrator. The first step is to enable the
administrator. You do this by setting the AdminEnabled property of the
TWSDLHTMLPublish component to true. Then, when you use your browser to
display the list of WSDL documents, it includes a button to administer them as well.
Use the WSDL administrator to specify the locations (URLs) where you have
deployed your Web Service application.
Writing clients for Web Services
You can write clients that access Web Services that you have written, or any other
Web Service that is defined in a WSDL document. There are three steps to writing an
application that is the client of a Web Service:
• Importing the definitions from a WSDL document.
• Obtaining an invokable interface and calling it to invoke the Web Service.
• Processing the headers of the SOAP messages that pass between the client and the
server.
Importing WSDL documents
Before you can use a Web Service, your application must define and register the
invokable interfaces and types that are included in the Web Service application. To
obtain these definitions, you can import a WSDL document (or XML file) that defines
the service. The WSDL importer creates a unit that defines and registers the
interfaces, headers, and types you need to use. For details on using the WSDL

importer, see “Using the WSDL importer” on page 38-13.
Calling invokable interfaces
To call an invokable interface, your client application must include any definitions of
the invokable interfaces and any remotable classes that implement complex types.
If the server is written in Delphi, you can use the same units that the server
application uses to define and register these interfaces and classes instead of the files
generated by importing a WSDL file. Be sure that the unit uses the same namespace
URI and SOAPAction header when it registers invokable interfaces. These values can
be explicitly specified in the code that registers the interfaces, or it can be
automatically generated. If it is automatically generated, the unit that defines the
interfaces must have the same name in both client and server, and both client and
server must define the global AppNameSpacePrefix variable to have the same value.
Once you have the definition of the invokable interface, there are two ways you can
obtain an instance to call:
• If you imported a WSDL document, the importer automatically generates a global
function that returns the interface, which you can then call.
• You can use a remote interfaced object.
Using Web Services
38-21
Writing clients for Web Services
Obtaining an invokable interface from the generated function
The WSDL importer automatically generates a function from which you can obtain
the invokable interfaces you imported. For example, if you imported a WSDL
document that defined an invokable interface named IServerInterface, the generated
unit would include the following global function:
function GetIServerInterface(UseWSDL: Boolean; Addr: string): IServerInterface;
The generated function takes two parameters: UseWSDL and Addr. UseWSDL
indicates whether to look up the location of the server from a WSDL document (true),
or whether the client application supplies the URL for the server (false).
When UseWSDL is false, Addr is the URL for the Web Service. When UseWSDL is

true, Addr is the URL of a WSDL document that describes the Web Service you are
calling. If you supply an empty string, this defaults to the document you imported.
This second approach is best if you expect that the URL for the Web Service may
change, or that details such as the namespace or SOAP Action header may change.
Using this second approach, this information is looked up dynamically at the time
your application makes the method call.
Note
The generated function uses an internal remote interfaced object to implement the
invokable interface. If you are using this function and find you need to access that
underlying remote interfaced object, you can obtain an IRIOAccess interface from the
invokable interface, and use that to access the remote interfaced object:
var
Interf: IServerInterface;
RIOAccess: IRIOAccess;
X: THTTPRIO;
begin
Intrf := GetIServerInterface(True,
' />RIOAccess := Intrf as IRIOAccess;
X := RIOAccess.RIO as THTTPRIO;
Using a remote interfaced object
If you do not use the global function to obtain the invokable interface you want to
call, you can create an instance of THTTPRio for the desired interface:
X := THTTPRio.Create(nil);
Note
It is important that you do not explicitly destroy the THTTPRio instance. If it is
created without an Owner (as in the previous line of code), it automatically frees itself
when its interface is released. If it is created with an Owner, the Owner is responsible
for freeing the THTTPRio instance.
38-22
Developer’ s Guide

Writing clients for Web Services
Once you have an instance of THTTPRio, provide it with the information it needs to
identify the server interface and locate the server. There are two ways to supply this
information:
• If you do not expect the URL for the Web Service or the namespaces and soap
Action headers it requires to change, you can simply specify the URL for the Web
Service you want to access. THTTPRio uses this URL to look up the definition of
the interface, plus any namespace and header information, based on the
information in the invocation registry. Specify the URL by setting the URL
property to the location of the server:
X.URL := ' />• If you want to look up the URL, namespace, or Soap Action header from the
WSDL document dynamically at runtime, you can use the WSDLLocation, Service,
and Port properties, and it will extract the necessary information from the WSDL
document:
X.WSDLLocation := 'Cryptography.wsdl';
X.Service := 'Cryptography';
X.Port := 'SoapEncodeDecode';
After specifying how to locate the server and identify the interface, you can obtain an
interface pointer for the invokable interface from the THTTPRio object. You obtain
this interface pointer using the as operator. Simply cast the THTTPRio instance to the
invokable interface:
InterfaceVariable := X as IEncodeDecode;
Code := InterfaceVariable.EncodeValue(5);
When you obtain the interface pointer, THTTPRio creates a vtable for the associated
interface dynamically in memory, enabling you to make interface calls.
THTTPRio relies on the invocation registry to obtain information about the invokable
interface. If the client application does not have an invocation registry, or if the
invokable interface is not registered, THTTPRio can’t build its in-memory vtable.
Warning
If you assign the interface you obtain from THTTPRio to a global variable, you must

change that assignment to nil before shutting down your application. For example, if
InterfaceVariable in the previous code sample is a global variable, rather than stack
variable, you must release the interface before the THTTPRio object is freed.
Typically, this code goes in the OnDestroy event handler of the form or data module:
procedure TForm1.FormDestroy(Sender: TObject);
begin
InterfaceVariable := nil;
end;
The reason you must reassign a global interface variable to nil is because THTTPRio
builds its vtable dynamically in memory. That vtable must still be present when the
interface is released. If you do not release the interface along with the form or data
module, it is released when the global variable is freed on shutdown. The memory
for global variables may be freed after the form or data module that contains the
THTTPRio object, in which case the vtable will not be available when the interface is
released.
Using Web Services
38-23
Writing clients for Web Services
Processing headers in client applications
If the Web Service application you are calling expects your client to include any
headers in its requests or if its response messages include special headers, your client
application needs the definitions of the header classes that correspond to these
headers. When you import a WSDL document that describes the Web Service
application, the importer automatically generates code to declare these header
classes and register them with the remotable type registry. If the server is written in
Delphi, you can use the same units that the server application uses to define and
register these header classes instead of the files generated by importing a WSDL file.
Be sure that the unit uses the same namespace URI and SOAPAction header when it
registers invokable interfaces. These values can be explicitly specified in the code that
registers the interfaces, or it can be automatically generated. If it is automatically

generated, the unit that defines the interfaces must have the same name in both client
and server, and both client and server must define the global AppSpacePrefix variable
to have the same value.
Note
For more information about header classes, see “Defining and using SOAP headers”
on page 38-16.
As with a server, client applications use the ISOAPHeaders interface to access
incoming headers and add outgoing headers. The remote interfaced object that you
use to call invokable interfaces implements the ISOAPHeaders interface. However,
you can’t obtain an ISOAPHeaders interface directly from the remote interfaced
object. This is because when you try to obtain an interface directly from a remote
interfaced object, it generates an in-memory vtable, assuming that the interface is an
invokable interface. Thus, you must obtain the ISOAPHeaders interface from the
invokable interface rather than from the remote interfaced object:
var
Service: IMyService;
Hdr: TAuthHeader;
Val: Double;
begin
Service := HTTPRIO1 as IService;
Hdr := TAUthHeader.Create;
try
Hdr.Name := 'Frank Borland';
Hdr.Password := 'SuperDelphi';
(Service as ISOAPHeaders).Send(Hdr); { add the header to outgoing message }
Val := Service.GetQuote('BORL'); { invoke the service }
finally
Hdr.Free;
end;
end;

38-24
Developer’ s Guide
Working with sockets
39-1
Chapter
39
Chapter39
Working with sockets
This chapter describes the socket components that let you create an application that
can communicate with other systems using TCP/IP and related protocols. Using
sockets, you can read and write over connections to other machines without
worrying about the details of the underlying networking software. Sockets provide
connections based on the TCP/IP protocol, but are sufficiently general to work with
related protocols such as User Datagram Protocol (UDP), Xerox Network System
(XNS), Digital’s DECnet, or Novell’s IPX/SPX family.
Using sockets, you can write network servers or client applications that read from
and write to other systems. A server or client application is usually dedicated to a
single service such as Hypertext Transfer Protocol (HTTP) or File Transfer Protocol
(FTP). Using server sockets, an application that provides one of these services can
link to client applications that want to use that service. Client sockets allow an
application that uses one of these services to link to server applications that provide
the service.
Implementing services
Sockets provide one of the pieces you need to write network servers or client
applications. For many services, such as HTTP or FTP, third party servers are readily
available. Some are even bundled with the operating system, so that there is no need
to write one yourself. However, when you want more control over the way the
service is implemented, a tighter integration between your application and the
network communication, or when no server is available for the particular service you
need, then you may want to create your own server or client application. For

example, when working with distributed data sets, you may want to write a layer to
communicate with databases on other systems.
39-2
Developer’ s Guide
Implementing services
Understanding service protocols
Before you can write a network server or client, you must understand the service that
your application is providing or using. Many services have standard protocols that
your network application must support. If you are writing a network application for
a standard service such as HTTP, FTP, or even finger or time, you must first
understand the protocols used to communicate with other systems. See the
documentation on the particular service you are providing or using.
If you are providing a new service for an application that communicates with other
systems, the first step is designing the communication protocol for the servers and
clients of this service. What messages are sent? How are these messages coordinated?
How is the information encoded?
Communicating with applications
Often, your network server or client application provides a layer between the
networking software and an application that uses the service. For example, an HTTP
server sits between the Internet and a Web server application that provides content
and responds to HTTP request messages.
Sockets provide the interface between your network server or client application and
the networking software. You must provide the interface between your application
and the clients that use it. You can copy the API of a standard third party server (such
as Apache), or you can design and publish your own API.
Services and ports
Most standard services are associated, by convention, with specific port numbers. We
will discuss port numbers in greater detail later. For now, consider the port number a
numeric code for the service.
If you are implementing a standard service for use in cross-platform applications,

Linux socket objects provide methods for you to look up the port number for the
service. If you are providing a new service, you can specify the associated port
number in the /etc/services file (or its equivalent for your particular Linux
distribution). See your Linux documentation for more information.
Working with sockets
39-3
Types of socket connections
Types of socket connections
Socket connections can be divided into three basic types, which reflect how the
connection was initiated and what the local socket is connected to. These are
•Client connections.
• Listening connections.
• Server connections.
Once the connection to a client socket is completed, the server connection is
indistinguishable from a client connection. Both end points have the same
capabilities and receive the same types of events. Only the listening connection is
fundamentally different, as it has only a single endpoint.
Client connections
Client connections connect a client socket on the local system to a server socket on a
remote system. Client connections are initiated by the client socket. First, the client
socket must describe the server socket to which it wishes to connect. The client socket
then looks up the server socket and, when it locates the server, requests a connection.
The server socket may not complete the connection right away. Server sockets
maintain a queue of client requests, and complete connections as they find time.
When the server socket accepts the client connection, it sends the client socket a full
description of the server socket to which it is connecting, and the connection is
completed by the client.
Listening connections
Server sockets do not locate clients. Instead, they form passive “half connections”
that listen for client requests. Server sockets associate a queue with their listening

connections; the queue records client connection requests as they come in. When the
server socket accepts a client connection request, it forms a new socket to connect to
the client, so that the listening connection can remain open to accept other client
requests.
Server connections
Server connections are formed by server sockets when a listening socket accepts a
client request. A description of the server socket that completes the connection to the
client is sent to the client when the server accepts the connection. The connection is
established when the client socket receives this description and completes the
connection.
39-4
Developer’ s Guide
Describing sockets
Describing sockets
Sockets let your network application communicate with other systems over the
network. Each socket can be viewed as an endpoint in a network connection. It has an
address that specifies:
• The system on which it is running.
• The types of interfaces it understands.
• The port it is using for the connection.
A full description of a socket connection includes the addresses of the sockets on both
ends of the connection. You can describe the address of each socket endpoint by
supplying both the IP address or host and the port number.
Before you can make a socket connection, you must fully describe the sockets that
form its endpoints. Some of the information is available from the system your
application is running on. For instance, you do not need to describe the local IP
address of a client socket—this information is available from the operating system.
The information you must provide depends on the type of socket you are working
with. Client sockets must describe the server they want to connect to. Listening
server sockets must describe the port that represents the service they provide.

Describing the host
The host is the system that is running the application that contains the socket. You
can describe the host for a socket by giving its IP address, which is a string of four
numeric (byte) values in the standard Internet dot notation, such as
123.197.1.2
A single system may support more than one IP address.
IP addresses are often difficult to remember and easy to mistype. An alternative is to
use the host name. Host names are aliases for the IP address that you often see in
Uniform Resource Locators (URLs). They are strings containing a domain name and
service, such as

Most Intranets provide host names for the IP addresses of systems on the Internet.
You can learn the host name associated with any IP address (if one already exists) by
executing the following command from a command prompt:
nslookup IPADDRESS
where IPADDRESS is the IP address you’re interested in. If your local IP address
doesn’t have a host name and you decide you want one, contact your network
administrator. It is common for computers to refer to themselves with the name
localhost and the IP number 127.0.0.1.
Working with sockets
39-5
Describing sockets
Server sockets do not need to specify a host. The local IP address can be read from the
system. If the local system supports more than one IP address, server sockets will
listen for client requests on all IP addresses simultaneously. When a server socket
accepts a connection, the client socket provides the remote IP address.
Client sockets must specify the remote host by providing either its host name or IP
address.
Choosing between a host name and an IP address
Most applications use the host name to specify a system. Host names are easier to

remember, and easier to check for typographical errors. Further, servers can change
the system or IP address that is associated with a particular host name. Using a host
name allows the client socket to find the abstract site represented by the host name,
even when it has moved to a new IP address.
If the host name is unknown, the client socket must specify the server system using
its IP address. Specifying the server system by giving the IP address is faster. When
you provide the host name, the socket must search for the IP address associated with
the host name, before it can locate the server system.
Using ports
While the IP address provides enough information to find the system on the other
end of a socket connection, you also need a port number on that system. Without port
numbers, a system could only form a single connection at a time. Port numbers are
unique identifiers that enable a single system to host multiple connections
simultaneously, by giving each connection a separate port number.
Earlier, we described port numbers as numeric codes for the services implemented
by network applications. This is actually just a convention that allows listening server
connections to make themselves available on a fixed port number so that they can be
found by client sockets. Server sockets listen on the port number associated with the
service they provide. When they accept a connection to a client socket, they create a
separate socket connection that uses a different, arbitrary, port number. This way, the
listening connection can continue to listen on the port number associated with the
service.
Client sockets use an arbitrary local port number, as there is no need for them to be
found by other sockets. They specify the port number of the server socket to which
they want to connect so that they can find the server application. Often, this port
number is specified indirectly, by naming the desired service.
39-6
Developer’ s Guide
Using socket components
Using socket components

The Internet palette page includes three socket components that allow your network
application to form connections to other machines, and that allow you to read and
write information over that connection. These are:
• TcpServer
• TcpClient
• UdpSocket
Associated with each of these socket components are socket objects, which represent
the endpoint of an actual socket connection. The socket components use the socket
objects to encapsulate the socket server calls, so that your application does not need
to be concerned with the details of establishing the connection or managing the
socket messages.
If you want to customize the details of the connections that the socket components
make on your behalf, you can use the properties, events, and methods of the socket
objects.
Getting information about the connection
After completing the connection to a client or server socket, you can use the client or
server socket object associated with your socket component to obtain information
about the connection. Use the LocalHost and LocalPort properties to determine the
address and port number used by the local client or server socket, or use the
RemoteHost and RemotePort properties to determine the address and port number
used by the remote client or server socket. Use the GetSocketAddr method to build a
valid socket address based on the host name and port number. You can use the
LookupPort method to look up the port number. Use the LookupProtocol method to
look up the protocol number. Use the LookupHostName method to look up the host
name based on the host machine’s IP address.
To view network traffic in and out of the socket, use the BytesSent and BytesReceived
properties.
Using client sockets
Add a TcpClient or UdpSocket component to your form or data module to turn your
application into a TCP/IP or UDP client. Client sockets allow you to specify the

server socket you want to connect to, and the service you want that server to provide.
Once you have described the desired connection, you can use the client socket
component to complete the connection to the server.
Each client socket component uses a single client socket object to represent the client
endpoint in a connection.
Working with sockets
39-7
Using socket components
Specifying the desired server
Client socket components have a number of properties that allow you to specify the
server system and port to which you want to connect. Use the RemoteHost property to
specify the remote host server by either its host name or IP address.
In addition to the server system, you must specify the port on the server system that
your client socket will connect to. You can use the RemotePort property to specify the
server port number directly or indirectly by naming the target service.
Forming the connection
Once you have set the properties of your client socket component to describe the
server you want to connect to, you can form the connection at runtime by calling the
Open method. If you want your application to form the connection automatically
when it starts up, set the Active property to True at design time, using the Object
Inspector.
Getting information about the connection
After completing the connection to a server socket, you can use the client socket
object associated with your client socket component to obtain information about the
connection. Use the LocalHost and LocalPort properties to determine the address and
port number used by the client and server sockets to form the end points of the
connection. You can use the Handle property to obtain a handle to the socket
connection to use when making socket calls.
Closing the connection
When you have finished communicating with a server application over the socket

connection, you can shut down the connection by calling the Close method. The
connection may also be closed from the server end. If that is the case, you will receive
notification in an OnDisconnect event.
Using server sockets
Add a server socket component (TcpServer or UdpSocket) to your form or data module
to turn your application into an IP server. Server sockets allow you to specify the
service you are providing or the port you want to use to listen for client requests. You
can use the server socket component to listen for and accept client connection
requests.
Each server socket component uses a single server socket object to represent the
server endpoint in a listening connection. It also uses a server client socket object for
the server endpoint of each active connection to a client socket that the server accepts.
39-8
Developer’ s Guide
Responding to socket events
Specifying the port
Before your server socket can listen to client requests, you must specify the port that
your server will listen on. You can specify this port using the LocalPort property. If
your server application is providing a standard service that is associated by
convention with a specific port number, you can also specify the service name using
the LocalPort property. It is a good idea to use the service name instead of a port
number, because it is easy to introduce typographical errors when specifying the port
number.
Listening for client requests
Once you have set the port number of your server socket component, you can form a
listening connection at runtime by calling the Open method. If you want your
application to form the listening connection automatically when it starts up, set the
Active property to True at design time, using the Object Inspector.
Connecting to clients
A listening server socket component automatically accepts client connection requests

when they are received. You receive notification every time this occurs in an
OnAccept event.
Closing server connections
When you want to shut down the listening connection, call the Close method or set
the Active property to False. This shuts down all open connections to client
applications, cancels any pending connections that have not been accepted, and then
shuts down the listening connection so that your server socket component does not
accept any new connections.
When TCP clients shut down their individual connections to your server socket, you
are informed by an OnDisconnect event.
Responding to socket events
When writing applications that use sockets, you can write or read to the socket
anywhere in the program. You can write to the socket using the SendBuf, SendStream,
or Sendln methods in your program after the socket has been opened. You can read
from the socket using the similarly-named methods ReceiveBuf and Receiveln. The
OnSend and OnReceive events are triggered every time something is written or read
from the socket. They can be used for filtering. Every time you read or write, a read
or write event is triggered.
Both client sockets and server sockets generate error events when they receive error
messages from the connection.
Socket components also receive two events in the course of opening and completing
a connection. If your application needs to influence how the opening of the socket
proceeds, you must use the SendBuf and ReceiveBuf methods to respond to these
client events or server events.
Working with sockets
39-9
Responding to socket events
Error events
Client and server sockets generate OnError events when they receive error messages
from the connection. You can write an OnError event handler to respond to these

error messages. The event handler is passed information about
• What socket object received the error notification.
• What the socket was trying to do when the error occurred.
• The error code that was provided by the error message.
You can respond to the error in the event handler, and change the error code to 0 to
prevent the socket from raising an exception.
Client events
When a client socket opens a connection, the following events occur:
• The socket is set up and initialized for event notification.
•An OnCreateHandle event occurs after the server and server socket is created. At
this point, the socket object available through the Handle property can provide
information about the server or client socket that will form the other end of the
connection. This is the first chance to obtain the actual port used for the
connection, which may differ from the port of the listening sockets that accepted
the connection.
• The connection request is accepted by the server and completed by the client
socket.
• When the connection is established, the OnConnect notification event occurs.
Server events
Server socket components form two types of connections: listening connections and
connections to client applications. The server socket receives events during the
formation of each of these connections.
Events when listening
Just before the listening connection is formed, the OnListening event occurs. You can
use its Handle property to make changes to the socket before it is opened for listing.
For example, if you want to restrict the IP addresses the server uses for listening, you
would do that in an OnListening event handler.
39-10
Developer’ s Guide
Reading and writing over socket connections

Events with client connections
When a server socket accepts a client connection request, the following events occur:
•An OnAccept event occurs, passing in the new TTcpClient object to the event
handler. This is the first point when you can use the properties of TTcpClient to
obtain information about the server endpoint of the connection to a client.
•If BlockMode is bmThreadBlocking an OnGetThread event occurs. If you want to
provide your own customized descendant of TServerSocketThread, you can create
one in an OnGetThread event handler, and that will be used instead of
TServerSocketThread. If you want to perform any initialization of the thread, or
make any socket API calls before the thread starts reading or writing over the
connection, you should use the OnGetThread event handler for these tasks as well.
• The client completes the connection and an OnAccept event occurs. With a non-
blocking server, you may want to start reading or writing over the socket
connection at this point.
Reading and writing over socket connections
The reason you form socket connections to other machines is so that you can read or
write information over those connections. What information you read or write, or
when you read it or write it, depends on the service associated with the socket
connection.
Reading and writing over sockets can occur asynchronously, so that it does not block
the execution of other code in your network application. This is called a non-blocking
connection. You can also form blocking connections, where your application waits
for the reading or writing to be completed before executing the next line of code.
Non-blocking connections
Non-blocking connections read and write asynchronously, so that the transfer of data
does not block the execution of other code in you network application. To create a
non-blocking connection for client or server sockets, set the BlockMode property to
bmNonBlocking.
When the connection is non-blocking, reading and writing events inform your socket
when the socket on the other end of the connection tries to read or write information.

Working with sockets
39-11
Reading and writing over socket connections
Reading and writing events
Non-blocking sockets generate reading and writing events when they need to read or
write over the connection. You can respond to these notifications in an OnReceive or
OnSend event handler.
The socket object associated with the socket connection is provided as a parameter to
the read or write event handlers. This socket object provides a number of methods to
allow you to read or write over the connection.
To read from the socket connection, use the ReceiveBuf or Receiveln method. To write
to the socket connection, use the SendBuf, SendStream, or Sendln method.
Blocking connections
When the connection is blocking, your socket must initiate reading or writing over
the connection. It cannot wait passively for a notification from the socket connection.
Use a blocking socket when your end of the connection is in charge of when reading
and writing takes place.
For client or server sockets, set the BlockMode property to bmBlocking to form a
blocking connection. Depending on what else your client application does, you may
want to create a new execution thread for reading or writing, so that your application
can continue executing code on other threads while it waits for the reading or writing
over the connection to be completed.
For server sockets, set the BlockMode property to bmBlocking or bmThreadBlocking to
form a blocking connection. Because blocking connections hold up the execution of
all other code while the socket waits for information to be written or read over the
connection, server socket components always spawn a new execution thread for
every client connection when the BlockMode is bmThreadBlocking. When the BlockMode
is bmBlocking, program execution is blocked until a new connection is established.
39-12
Developer’ s Guide

Developing COM-based applications
Part
IV
Part IV
Developing COM-based applications
The chapters in “Developing COM-based applications” present concepts necessary
for building COM-based applications, including Automation controllers,
Automation servers, ActiveX controls, and COM+ applications.

Overview of COM technologies
40-1
Chapter
40
Chapter40
Overview of COM technologies
Delphi provides wizards and classes to make it easy to implement applications based
on the Component Object Model (COM) from Microsoft. With these wizards, you can
create COM-based classes and components to use within applications or you can
create fully functional COM clients or servers that implement COM objects,
Automation servers (including Active Server Objects), ActiveX controls, or
ActiveForms.
Note
COM components such as those on the ActiveX, COM+, and Servers tabs of the
Component palette are not available for use in CLX applications. This technology is
for use on Windows only and is not cross-platform.
COM is a language-independent software component model that enables interaction
between software components and applications running on a Windows platform.
The key aspect of COM is that it enables communication between components,
between applications, and between clients and servers through clearly defined
interfaces. Interfaces provide a way for clients to ask a COM component which

features it supports at runtime. To provide additional features for your component,
you simply add an additional interface for those features.
Applications can access the interfaces of COM components that exist on the same
computer as the application or that exist on another computer on the network using a
mechanism called Distributed COM (DCOM). For more information on clients,
servers, and interfaces see, “Parts of a COM application,” on page 40-3.
This chapter provides a conceptual overview of the underlying technology on which
Automation and ActiveX controls are built. Later chapters provide details on creating
Automation objects and ActiveX controls in Delphi.
40-2
Developer’ s Guide
Overview of COM technologies
COM as a specification and implementation
COM is both a specification and an implementation. The COM specification defines
how objects are created and how they communicate with each other. According to
this specification, COM objects can be written in different languages, run in different
process spaces and on different platforms. As long as the objects adhere to the
written specification, they can communicate. This allows you to integrate legacy code
as a component with new components implemented in object-oriented languages.
The COM implementation is built into the Win32 subsystem, which provides a
number of core services that support the written specification. The COM library
contains a set of standard interfaces that define the core functionality of a COM
object, and a small set of API functions designed for the purpose of creating and
managing COM objects.
When you use Delphi wizards and VCL objects in your application, you are using
Delphi’s implementation of the COM specification. In addition, Delphi provides
some wrappers for COM services for those features that it does not implement
directly (such as Active Documents). You can find these wrappers defined in the
ComObj unit and the API definitions in the AxCtrls unit.
Note

Delphi’s interfaces and language follow the COM specification. Delphi implements
objects conforming to the COM spec using a set of classes called the Delphi ActiveX
framework (DAX). These classes are found in the AxCtrls, OleCtrls, and OleServer
units. In addition, the Delphi interface to the COM API is in ActiveX.pas and
ComSvcs.pas.
COM extensions
As COM has evolved, it has been extended beyond the basic COM services. COM
serves as the basis for other technologies such as Automation, ActiveX controls,
Active Documents, and Active Directories. For details on COM extensions, see
“COM extensions” on page 40-10.
In addition, when working in a large, distributed environment, you can create
transactional COM objects. Prior to Windows 2000, these objects were not
architecturally part of COM, but rather ran in the Microsoft Transaction Server (MTS)
environment. With the advent of Windows 2000, this support is integrated into
COM+. Transactional objects are described in detail in Chapter 46, “Creating MTS or
COM+ objects.”
Delphi provides wizards to easily implement applications that incorporate the above
technologies in the Delphi environment. For details, see “Implementing COM objects
with wizards” on page 40-19.

×