Building Socket Applications
Delphi 7 ships with two sets of TCP components—Indy socket components (IdTCPClient and IdTCPServer) and native Borland components—which are also available in Kylix and are hosted in the Internet page of the Component palette. The Borland components, TcpClient and TcpServer, were probably developed to replace the ClientSocket and ServerSocket components available in past versions of Delphi. However, now that the ClientSocket and ServerSocket components have been declared obsolete (although they are still available), Borland suggests using the corresponding Indy components instead.
Foundations of Socket Programming
To understand the behavior of the socket components, you need to be confident with several terms related to the Internet in general and with sockets in particular. The heart of the Internet is the Transmission Control Protocol/Internet Protocol (TCP/IP), a combination of two separate protocols that work together to provide connections over the Internet (and that can also provide connection over a private intranet). In brief, IP is responsible for defining and routing the datagrams (Internet transmission units) and specifying the addressing scheme. TCP is responsible for higher-level transport services.
Configuring a Local Network: IP Addresses
If you have a local network available, you'll be able to test the following programs on it; otherwise, you can use the same computer as both client and server. In this case, as I've done in the examples, use the address 127.0.0.1 (or localhost), which is invariably the address of the current computer. If your network is complex, ask your network administrator to set up proper IP addresses for you. If you want to set up a simple network with a couple of spare computers, you can set up the IP address yourself; it's a 32-bit number usually represented with each of its four components (called octets) separated by dots. These numbers have a complex logic underlying them, and the first octet indicates the class of the address.
Specific IP addresses are reserved for unregistered internal networks. Internet routers ignore these address ranges, so you can freely do your tests without interfering with an actual network. For example, the "free" IP address range 192.168.0.0 through 192.168.0.255 can be used for experiments on a network of fewer than 255 machines.
TCP Ports
Each TCP connection takes place though a port, which is represented by a 16-bit number. The IP address and the TCP port together specify an Internet connection, or a socket. Different processes running on the same machine cannot use the same socket (the same port).
Some TCP ports have a standard usage for specific high-level protocols and services. In other words, you should use those port numbers when implementing those services and stay away from them in any other case. Here is a short list:
| Protocol | Port |
|---|---|
| HTTP (Hypertext Transfer Protocol) | 80 |
| FTP (File Transfer Protocol) | 21 |
| SMTP (Simple Mail Transfer Protocol) | 25 |
| POP3 (Post Office Protocol, version 3) | 110 |
| Telnet | 23 |
Working with HTTP
Handling mail messages is certainly interesting, and mail protocols are probably still the most widespread Internet protocols. The other popular protocol is HTTP, which is used by web servers and web browsers. I'll devote the rest of this chapter to this protocol (along with a discussion of HTML); the following two chapters also discuss it.
On the client side of the Web, the main activity is browsing—reading HTML files. Besides building a custom browser, you can embed the Internet Explorer ActiveX control within your program("From COM to COM+"). You can also directly activate the browser installed on the user's computer—for example, opening an HTML page by calling the ShellExecute method (defined in the ShellApi unit):
ShellExecute (Handle, 'open', FileName, '', '', sw_ShowNormal);
Grabbing HTTP Content
As an example of the use of the HTTP protocols, I've written a specific search application. The program hooks onto the Google website, searches for a keyword, and retrieves the first 100 sites found. Instead of showing the resulting HTML file, the program parses it to extract only the URLs of the related sites to a list box. The description of these sites is kept in a separate string list and is displayed as you click a list-box item. So, the program demonstrates two techniques at once: retrieving a web page and parsing its HTML code.
To demonstrate how you should work with blocking connections, such as those used by Indy, I've implemented the program using a background thread for the processing. This approach also gives you the advantage of being able to start multiple searches at once. The thread class used by the WebFind application receives as input a URL to look for, strUrl.
The class has two output procedures, AddToList and ShowStatus, to be called inside the Synchronize method. The code of these two methods sends some results or some feedback to the main form, respectively adding a line to the list box and changing the status bar's SimpleText property. The key method of the thread is Execute. Before we look at it, however, here is how the thread is activated by the main form:
const
strSearch = 'http://www.google.com/search?as_q=';
procedure TForm1.BtnFindClick(Sender: TObject);
var
FindThread: TFindWebThread;
begin
// create suspended, set initial values, and start
FindThread := TFindWebThread.Create (True);
FindThread.FreeOnTerminate := True;
// grab the first 100 entries
FindThread.strUrl := strSearch + EditSearch.Text +'&num=100';
FindThread.Resume;
end;
The URL string is made of the main address of the search engine, followed by some parameters. The first, as_q, indicates the words you are looking for. The second, num=100, indicates the number of sites to retrieve; you cannot use numbers at will but are limited to a few alternatives, with 100 being the largest possible value.
Delphi's HTML Producer Components
Delphi's HTML producer components (on the Internet page of the Component Palette) can be used to generate the HTML files and particularly to turn a database table into an HTML table. Many developers believe that the use of these components makes sense only when writing a web server extension. Although they were introduced for this purpose and are part of the WebBroker technology, you can still use three out of the five producer components in any application in which you must generate a static HTML file.
Before looking at the HtmlProd example, which demonstrates the use of these HTML producer components, let me summarize their role:
-
The simplest HTML producer component is the PageProducer, which manipulates an HTML file in which you've embedded special tags. The HTML can be stored in an external file or an internal string list. The advantage of this approach is that you can generate such a file using the HTML editor you prefer. At run time, the PageProducer converts the special tags to HTML code, giving you a straightforward method for modifying sections of an HTML document. The special tags have the basic format <#tagname>, but you can also supply named parameters within the tag. You'll process the tags in the OnTag event handler of the PageProducer.
-
The DataSetPageProducer extends the PageProducer by automatically replacing tags corresponding to field names of a connected data source.
-
The DataSetTableProducer component is generally useful for displaying the contents of a table, query, or other dataset. The idea is to produce an HTML table from a dataset, in a simple yet flexible way. The component has a nice preview, so you can see how the HTML output will look in a browser directly at design time.
-
The QueryTableProducer and the SQLQueryTableProducer components are similar to the DataSetTableProducer, but they are specifically tailored for building parametric queries (for the BDE or dbExpress, respectively) based on input from an HTML search form.
Dynamic Web Pages
When you browse a website, you generally download static pages—HTML-format text files—from the web server to your client computer. As a web developer, you can create these pages manually, but for most businesses, it makes more sense to build the static pages from information in a database (a SQL server, a series of files, and so on). Using this approach, you're basically generating a snapshot of the data in HTML format, which is reasonable if the data isn't subject to frequent changes.
An Overview of CGI
CGI is a standard protocol for communication between the client browser and the web server. It's not a particularly efficient protocol, but it is widely used and is not platform specific. This protocol allows the browser both to ask for and to send data, and it is based on the standard command-line input and output of an application (usually a console application). When the server detects a page request for the CGI application, it launches the application, passes command-line data from the page request to the application, and then sends the application's standard output back to the client computer.
You can use many tools and languages to write CGI applications, and Delphi is only one of them. Despite the obvious limitation that your web server must be an Intel-based Windows or Linux system, you can build some fairly sophisticated CGI programs in Delphi and Kylix. CGI is a low-level technique, because it uses the standard command-line input and output along with environment variables to receive information from the web server and pass it back.
To build a CGI program without using support classes, you can create a Delphi console application, remove the typical project source code, and replace it with the following statements:
program CgiDate;
{$APPTYPE CONSOLE}
uses SysUtils;
begin
writeln ('content-type: text/html');
writeln;
writeln ('');
writeln ('Time at this site');
writeln ('');
writeln ('Time at this site
');
writeln ('
');
writeln (''
);
writeln (FormatDateTime('"Today is " dddd, mmmm d, yyyy,' +
'"
and the time is" hh:mm:ss AM/PM', Now));
writeln ('');
writeln ('
');
writeln ('Page generated by CgiDate.exe');
Delphi's WebBroker Technology
The CGI code snippet I've shown you demonstrates the plain, direct approach to this protocol. I could have provided similar low-level examples for ISAPI or Apache modules, but in Delphi it's more interesting to use the WebBroker technology. This comprises a class hierarchy within VCL and CLX (built to simplify server-side development on the Web) and a specific type of data modules called WebModules. Both the Enterprise Studio and Professional editions of Delphi include this framework (as opposed to the more advanced and newer WebSnap framework, which is available only in the Enterprise Studio version).
program Project2;
{$APPTYPE CONSOLE}
uses
WebBroker,
CGIApp,
Unit1 in 'Unit1.pas' {WebModule1: TWebModule};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TWebModule1, WebModule1);
A Graphical Web Hit Counter
The server-side applications you've built up to now were based only on text. Of course, you can easily add references to existing graphics files. What's more interesting, however, is to build server-side programs capable of generating graphics that change over time.
A typical example is a page hit counter. To write a web counter, you save the current number of hits to a file and then read and increase the value every time the counter program is called. To return this information, all you need is HTML text with the number of hits. The code is straightforward:
procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
nHit: Integer;
LogFile: Text;
LogFileName: string;
begin
LogFileName := 'WebCont.log';
System.Assign (LogFile, LogFileName);
try
// read if the file exists
if FileExists (LogFileName) then
begin
Reset (LogFile);
Readln (LogFile, nHit);
Inc (nHit);
end
else
nHit := 0;
// saves the new data
Rewrite (LogFile);
Writeln (LogFile, nHit);
finally
Close (LogFile);
end;
Response.Content := IntToStr (nHit);
end;
Application.Run;
end.
writeln ('');
end.
No comments:
Post a Comment