Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

(Ebook - Pdf) Kick Ass Delphi Programming

.pdf
Скачиваний:
284
Добавлен:
17.08.2013
Размер:
5.02 Mб
Скачать

blocking mode. In this case, blocking means that the application is waiting for a response from a remote computer—a response that may never come. Unable to proceed or respond to input until it receives a response, a blocked application often appears “dead” to the user.

Under Unix, this type of operation poses little problem. Even if an application blocks, the pre-emptive nature of Unix allows other applications to operate normally. Windows 3.1, in contrast, implements only cooperative multitasking. Executing a blocking Winsock operation would lock the brakes on your Windows system.

To allow Windows to continue to execute in a blocking situation, Winsock replaces each blocking functions with a pseudo-blocking asynchronous equivalent. Instead of blocking, these routines enter a polling loop while waiting for the network event to complete. These non-blocking routines are identified by the WSAAsync prefix before the name. For example,

WSAAsyncGetHostByName is the asynchronous version of gethostbyname.

Typically, an Internet host identifies itself over the network with a unique address in the form of a dotted decimal number quadruple such as 127.0.0.1. (Note that this is the special loopback address that you can use to test your Winsock applications on a non-networked machine.) Although highly convenient for computers, these addresses hold little appeal for humans. To reconcile this problem, a system was implemented that allows the creation of a unique human-readable name for each Internet address. For example, the name slipper109.iaccess.za is equivalent to the Internet address 196.7.7.109.

To resolve a host name, enter the name in RESOLVER’s Host edit control. After you press the Resolve button in the Name Resolution group box, RESOLVER assigns the name that you gave in the Host.Text control to the Hostname property. Then the property calls TWSocket.SetRemote HostName. Listing 4.7 shows how WSock handles this. If the NameReqd string is empty, SetRemoteHostName reports the error and exits. Otherwise, StrpCopy is used to convert FRemoteName from a Pascal string to an ASCII string.

Listing 4.7 Mapping a host name to its Internet address

procedure TWSocket.SetRemoteHostName(NameReqd : String); var

P : Pointer; IPAddress : LongInt; IAddr : TIN_ADDR; begin

FRemoteName := NameReqd;

if Length(FRemoteName) = 0 then begin

FStatus := Failure;

MessageDlg('No host name given!', mtError,[mbOk],0); Exit;

end;

PostInfo('Resolving host'); StrPCopy(FpHostName, FRemoteName);

{ check what type of address has been entered } IPAddress := inet_addr(FpHostName);

if IPAddress <>INADDR_NONE then {this is a dotted address} begin

FAddress := IPAddr; P := addr(IPAddress); case AddrType of

AFINET : FHost := GetHostByAddr(P, 4, AF_INET);

end; end

else {no, it looks like a human readable hostname} begin

FAddress := HostAddr;

FHost

:= GetHostByName(FpHostName);

end;

 

if FHost = NIL then begin{Unknown host, so aborting…} if OkToDisplayErrors then

MessageDlg('Unknown host', mtError,[mbOk],0); FStatus := Failure;

Exit;

end;

PostInfo('Host found'); FStatus := Success;

Move(FHost^.h_addr_list^, Fh_addr, SizeOf(FHost^.h_addr_list^)); if FAddress = HostAddr then

begin SetUpAddress;

FRemoteName := StrPas(inet_ntoa(FSockAddress.sin_addr)); end

else

if FAddress = IPAddr then begin

FRemoteName := StrPas(FHost^.h_name); PostInfo('Host found…');

end;

end;

Next, the SetRemoteHostName method checks whether the string already contains a numeric Internet address using the inet_addr function. If not, the method assumes that the string contains a host name and calls the gethostbyname function to resolve it to an IP address. If the host name is not present in the local hosts file, gethostbyname looks for the name in a foreign hosts file elsewhere on the network.

If the name is not found, the lookup process times out and sets the private property FHost, which is a pHostent structure, to NIL. Then, SetRemoteHostName posts an error message, sets the FStatus flag to Failure, and exits back to the calling application. If the IP address is found, however, the gethostbyname function returns a pointer to FHost, which contains the IP address. The SetUpAddress procedure then extracts the IP address from the FHost structure. Finally, SetRemoteHostName sends back the dotted address as a Pascal string using the following statement:

FRemoteName := StrPas(inet_ntoa(FSockAddress.sin_addr));

Products | Contact Us | About Us | Privacy | Ad Info | Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.

All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Kick Ass Delphi Programming

Go!

Keyword

(Publisher: The Coriolis Group)

Author(s): Don Taylor, Jim Mischel, John Penman, Terence Goggin

ISBN: 1576100448

Publication Date: 09/01/96

Search this book:

Go!

-----------

The inet_ntoa function converts the returned IP address to an ASCII string in dotted format. The StrPas function finishes the conversion to a Pascal string. The address information for the socket is placed in FSockAddress, where it will later be used to set up a connection with a host machine. Setting the Hostname property writes the IP address to the IPName edit control, as shown in Figure 4.4.

FIGURE 4.4 RESOLVER after resolving a host name.

What’s Your Name?

RESOLVER can also derive the name of a host from its numeric Internet address. The process begins when you enter an address into the IPName edit control, as shown in Figure 4.5. When you click the Resolve button, RESOLVER passes the address string in IPName.Text to the

SetRemoteHostName method via the Hostname property.

FIGURE 4.5 A dotted IP address ready to resolve.

As before, the SetRemoteHostName method uses the inet_addr function to check whether the string is in valid Internet address form. Before calling this function, however, the method assigns the address of the IPAddress string to a pointer, P, which gethostbyaddr requires as one of its parameters.

If inet_addr returns a result other than INADDR_NONE (meaning that the string is a numeric Internet address), SetRemoteHostName calls gethostbyaddr. Like the call to gethostbyname, this call may also block. If gethostbyaddr is successful, it returns a pointer to the pHostent structure. If no corresponding name is found for the IP address, FHost is set to NIL and SetRemoteHostName reports the error, sets the FStatus flag, and exits. The Hostname property writes the host name obtained, using the statement below, back to the Host edit control:

FRemoteName := StrPas(FHost^.h_name);

Getting the Name Asynchronously

Using the blocking lookup functions gethostbyname and gethostbyaddr is fairly straightforward. Employing the asynchronous versions of these functions, WSAAyncGetHostByName and WSAAsyncGetHostByAddr, is a little more complex. To understand the asynchronous process, let’s go through the steps of calling WSAAsyncGetHostByName from the RESOLVER program.

First, change the CallType property from Blocking to NonBlocking by selecting the NonBlocking radio button in the TypeOfLookup group box as shown in Figure 4.6. Pressing the Resolve button now assigns the name to the AsyncHostName property and passes it to the SetAsyncHostName procedure as shown in Listing 4.8.

FIGURE 4.6 Changing from blocking to non-blocking.

Listing 4.8 Resolving the host name.

procedure TWSocket.SetAsyncHostName(ReqdHostName : String); var

Size : PInteger; P : Pointer;

IPAddress : TIn_addr;

SAddress: array[0..31] of char; sa : Tin_addr;

begin

FAsyncRemoteName := ReqdHostName;

if Length(FAsyncRemoteName) = 0 then begin

FStatus := Failure;

MessageDlg('No host name given!', mtError,[mbOk],0); Exit;

end;

StrPcopy(SAddress, FAsyncRemoteName); IPAddress.s_addr := inet_addr(SAddress);

if IPAddress.s_addr <> INADDR_NONE then {this is a dotted address} begin

FAddress := IPAddr; FAsyncType := AsyncAddr;

if IPAddress.s_addr <> 0 then

FTaskHandle := WSAAsyncGetHostByAddr(FAsyncHWND, ASYNC_EVENT, pChar(@IPAddress), 4, PF_INET,

@FAsyncBuff, SizeOf(FAsyncBuff)); if FTaskHandle = 0 then

begin MessageDlg(WSAErrorMsg,mtError,[mbOk], 0); FStatus := Failure;

if FNoOfBlockingTasks > 0 then dec(FNoOfBlockingTasks);

Exit;

end else FStatus := Success; end

else {no, it looks like a human readable hostname} begin

FAddress := HostAddr; FAsyncType := AsyncName; Inc(FNoOfBlockingTasks);

FTaskHandle := WSAAsyncGetHostByName(FAsyncHWND, ASYNC_EVENT, @FpHostName, @FAsyncBuff, MAXGETHOSTSTRUCT);

if FTaskHandle = 0 then begin

MessageDlg(WSAErrorMsg,mtError,[mbOk], 0); FStatus := Failure;

if FNoOfBlockingTasks > 0 then dec(FNoOfBlockingTasks);

Exit;

end else FStatus := Success; end;

end;

SetAsyncHostName calls the WSAAsyncGetHostByName procedure with five important arguments. FASyncHWND is a handle to the window in which the asynchronous function will post its message on completion of the lookup operation. This window handle is initialized in the

TWSocket.Create constructor by a call to AllocateHWND with AsyncOperation as its procedural parameter. ASYNC_EVENT is the event notification constant used by WSAAsyncGetHostByName. FAsyncBuff is an array of characters that holds the result of the operation. Finally, MAXGETHOSTSTRUCT is a Winsock constant representing the maximum size of the FAsyncBuff buffer. The WSAAsyncGetHostByName procedure returns the task number of the call as a TaskHandle type that is assigned to FTaskHandle.

WSAAyncGetHostByName returns immediately with a value of 0 if the call was unsuccessful or greater than 0 if successful. However, a non-zero value for FTaskhandle means only that the call to WSAAyncGetHostByName succeeded, not that the subsequent lookup operation (which continues to execute in the background) will be successful.

When the lookup does complete, the Winsock DLL triggers a ASYNC_EVENT event, notifying the AsyncOperation procedure that it should examine the ASYNC_EVENT message, as shown in Listing 4.9.

Products | Contact Us | About Us | Privacy | Ad Info | Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.

All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

Go!

Keyword

To access the contents, click the chapter and section titles.

Kick Ass Delphi Programming

(Publisher: The Coriolis Group)

Author(s): Don Taylor, Jim Mischel, John Penman, Terence Goggin

ISBN: 1576100448

Publication Date: 09/01/96

Search this book:

Go!

-----------

Listing 4.9 The AsyncOperation procedure

procedure TWSocket.AsyncOperation(var Mess : TMessage); var

MsgErr : Word; begin

if Mess.Msg = ASYNC_EVENT then begin

MsgErr := WSAGetAsyncError(Mess.lparam);

if (MsgErr <> 0) and (StrLen(FpHostName) > 0) then begin

FStatus := Failure; MessageDlg(WSAErrorMsg,mtError,[mbOk], 0); Exit;

end else begin

FStatus := Success;

PostInfo('WSAAsync operation succeeded!'); case FAsyncType of

AsyncName, AsyncAddr : begin

FHost := pHostent(@FAsyncBuff); if FHost = NIL then

begin{Unknown host, so aborting…} if OkToDisplayErrors then

MessageDlg('Unknown host', mtError,[mbOk],0); FStatus := Failure;

Exit;

end;

case FAddress of IPAddr :

begin

Move(FHost^.h_addr_list^, Fh_addr, SizeOf(FHost^.h_addr_list^));

FAsyncRemoteName := StrPas(FHost^.h_name);

end; HostAddr : begin

Move(FHost^.h_addr_list^, Fh_addr, SizeOf(FHost^.h_addr_list^));

SetUpAddress;

FAsyncRemoteName:= StrPas(inet_ntoa(FSockAddress.sin_addr));

end;

end;{case}

AsyncChange;

end; AsyncServ : begin

FServ := pServent(@FAsyncBuff); if FServ = NIL then

begin { No service available } MessageDlg(WSAErrorMsg, mtError,[mbOk],0); FStatus := Failure;

Exit;

end;

FAsyncPort := IntToStr(ntohs(FServ^.s_port)); AsyncChange;

end; AsyncPort : begin

FServ := pServent(@FAsyncBuff); if FServ = NIL then

begin { No service available } MessageDlg(WSAErrorMsg, mtError,[mbOk],0); FStatus := Failure;

Exit;

end;

FAsyncService := StrPas(FServ^.s_name); AsyncChange;

end; AsyncProtoName :

begin

FProto := pProtoEnt(@FAsyncBuff); if FProto = NIL then

begin

MessageDlg(WSAErrorMsg, mtError,[mbOk],0); FStatus := Failure;

Exit;

end;

FAsyncProtoNo := IntToStr(FProto^.p_proto); AsyncChange;

end; AsyncProtoNumber : begin

FProto := pProtoEnt(@FAsyncBuff); if FProto = NIL then

begin

MessageDlg(WSAErrorMsg, mtError,[mbOk],0); FStatus := Failure;

Exit;

end;

FAsyncProtocol := StrPas(FProto^.p_name); AsyncChange;

end;

end; {case}

if FNoOfBlockingTasks > 0 then dec(FNoOfBlockingTasks);

end;

end;

end;

The WSAGetAsyncError macro checks the Mess variable. If it indicates that an error occurred, AsyncOperation calls WSAErrorMsg to display the cause of the error, then exits with the FStatus flag set to Failure. If no error has occurred, we parse the FAsyncType variable.

When we called WSAAyncGetHostByName, we set the FAsyncType to AsyncName to indicate that we were performing an asynchronous name lookup. The case statement now branches based on the value of FAsyncType to the AsyncName clause. There, the character array FAsyncBuff, containing the result of the lookup, is typecast to a pHostent structure and stored in FHost. The address structure for the resolved host is read by SetUpAddress to get the corresponding IP address. AsyncChange calls GetAsyncHostName to return the IP address back to RESOLVER.

Products | Contact Us | About Us | Privacy | Ad Info | Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.

All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Kick Ass Delphi Programming

Go!

Keyword

(Publisher: The Coriolis Group)

Author(s): Don Taylor, Jim Mischel, John Penman, Terence Goggin

ISBN: 1576100448

Publication Date: 09/01/96

Search this book:

Go!

-----------

Who’s at This Address?

To further illustrate the use of asynchronous mode, we’ll examine how the WSAAyncGetHostByAddr function (shown in Listing 4.8) retrieves a host name when given only an Internet address. To use this function in the RESOLVER application, set the CallType property to NonBlocking in the TypeOfLookUp group box, and enter an Internet address in the IPName edit control.

As before, we assign the name to the AsyncHostName property for handling by the TWSocket.SetAsyncHostName method. If the name we passed is an empty string, SetAsyncHostName sets the FStatus flag to Failure, posts an error message, and exits. After establishing that the FAsync RemoteName is not empty, we call the inet_addr function to determine whether the string is a dotted decimal Internet address or host name. A return value different than INADDR_NONE indicates the string is in Internet address format.

This string is then passed to WSAAyncGetHostByAddr to get the host information for the Internet address. A successful call to WSAAync GetHostByAddr sets the FTaskHandle to a number greater than zero, but doesn’t ensure that we will get a valid result from WSAAyncGetHostByAddr on completion. The method exits back to the RESOLVER application, and the lookup continues in the background.

When the lookup operation completes, the Winsock DLL posts a message to WSock by triggering the ASYNC_EVENT event. This trigger wakes up the TWSocket.AsyncOperation method, which examines the Mess variable. If Mess contains an error, the AsyncOperation method calls WSAErrorMsg to determine the error, sets the FStatus flag to Failure, and exits.

If the Mess variable contains no error, a case statement parses FAsyncType. In this example, FAsyncType has the value AsyncAddr, so the same portion of code executes that handled the AsyncName case. Next, we parse FAddress to execute the section of code that handles the result of WSAAyncGetHostByAddr. This setting is automatically determined by the SetAsyncHostName method by using the result of the inet_addr operation. That is, FAddress is set to IPAddr when a dotted decimal address is found, otherwise it is set to HostAddr for a host name. The host name is then extracted by the following code: