![]() |
ActivePerl User Guide |
![]() |
ActivePerl-faq8 - General programming
General programming questions about ActivePerl
There are several Win32 Registry functions provided with ActivePerl. Check the win32mod document provided with ActivePerl.
If you don't understand how the Registry works, remember that a Registry key is like a directory, and a Registry value is like a file. There are several top level keys, and these are kind of like drives.
If you really don't fully understand the Registry, it's probably in your best interest not to mess around with it.
Named pipes are a interprocess communcations mechanism, mainly used with Microsoft operating systems (like Win32 platforms). A named pipe can be addressed just like a file.
The name of a named pipe is a UNC (Universal Naming Convention) name, and
looks like \\servername\pipe\pipename. servername
is the
name of the server you're connecting to, or .
for the current
computer. pipe
is a constant, and pipename
is the name
of the pipe, such as sql for Microsoft SQL Server.
You can use open(),
close(),
read(),
and print()
on a named pipe just like a file. However, you can't
use sysread()
or syswrite()
on one, because they
aren't really files.
There's a program called Win32Pipe on the CPAN archive that can be used to create a named pipe.
If you're starting from scratch, and you have a TCP/IP infrastructure, consider using sockets rather than named pipes for your IPC mechanism.
There are several examples of socket scripts that are distributed with ActivePerl. They're in the eg subdirectory of your perl directory.
See How do I write a sockets server in Perl for Win32? for information about sockets servers.
Early versions of Perl for Win32 didn't allow you to read or write to a socket as if it were a filehandle. The current versions fully support this, and you shouldn't worry about it too much. If the version that you're using doesn't work well, get the latest build from ActiveState (see Where is the ActivePerl interpreter available?).
You don't have to specify USE_SOCKETS_AS_FILEHANDLES
when
building Perl for Win32 to get sockets to work like filehandles. It doesn't hurt,
but it's not necessary.
There's an example of a socket server, TCP-SERVER, in the eg directory of your perl directory. In general, information on socket programming for UNIX is applicable to ActivePerl. See especially the perlipc page of the documentation.
If you need to develop a server that can service multiple clients at once, take a look at the IO::Select module. This module allows you to write servers that can manage open connections from multiple clients. Individual requests on a connection are queued up, so if your server can provide quick responses, this approach may work well for you. Here's an example, adapted from Erik Olson's Programming with Perl Modules (one of the volumes in O'Reilly's Win32 Perl Resource Kit):
use IO::Socket; use IO::Select; # Create a socket to listen on. # my $listener = IO::Socket::INET->new( LocalPort => 8008, Listen => 5, Reuse => 1 ); die "Can't create socket for listening: $!" unless $listener; print "Listening for connections on port 8008\n"; my $readable = IO::Select->new; # Create a new IO::Select object $readable->add($listener); # Add the listener to it while(1) { # Get a list of sockets that are ready to talk to us. # my ($ready) = IO::Select->select($readable, undef, undef, undef); foreach my $s (@$ready) { # Is it a new connection? # if($s == $listener) { # Accept the connection and add it to our readable list. # my $new_sock = $listener->accept; $readable->add($new_sock) if $new_sock; print $new_sock "Welcome!\r\n"; } else { # It's an established connection my $buf = <$s>; # Try to read a line # Was there anyone on the other end? # if( defined $buf ) { # If they said goodbye, close the socket. If not, # echo what they said to us. # if ($buf =~ /goodbye/i) { print $s "See you later!\n"; $readable->remove($s); $s->close; } else { print $s "You said: $buf\n"; } } else { # The client disconnected. $readable->remove($s); $s->close; print STDERR "Client Connection closed\n"; } } } }
For more information, see the IO::Socket and IO::Select documentation. It is also possible to write a multithreaded server using ActivePerl, if threads are enabled in the version of Perl you are using. However, threading is still somewhat experimental in Perl 5.005, so use this feature with caution.
See the Net::FTP module. Net::FTP is part of the libnet bundle, which is available from CPAN, and can be installed using the Perl Package Manager (PPM).
Aldo Calpini has developed a ActivePerl extension to do FTP and HTTP using the WININET library. It's in alpha testing and is available on his web page at http://dada.perl.it/
The libwww-perl bundle (LWP) is a collection of modules for WWW access in Perl. LWP is available from CPAN in source form, or you can install it using the Perl Package Manager (PPM). LWP may also be included with future binary releases of Perl.
Aldo Calpini has developed a ActivePerl extension to do FTP and HTTP using the WININET library. It's in alpha testing and is available on his web page at http://dada.perl.it/
There's an extension called Win32::NetAdmin distributed with ActivePerl. It has a pretty low-level interface, but it is very possible to manage users and groups with this module.
Serial ports can be opened just like files in ActivePerl. To open COM1, just do this:
open( PORT, "+>COM1" ) or die "Can't open COM1: $!";
You should be able to read from and write to the file handle using the
standard I/O functions (read() and print()),
but not the system
functions (sysread() and syswrite()).
It has been noted (but not tested) that modems that use the Hayes command set require a carriage return (\r) rather than a line feed (\n) at the end of the command.
It does, in fact, work. However, people tend to use it incorrectly and get bad results. To check for all the subdirectories in a directory, try code like this:
$path = shift; $path = "." unless $path; opendir( DIR, $path ) or die "Can't open $path: $!"; while ( $entry = readdir( DIR ) ) { $type = ( -d "$path\\$entry" ) ? "dir" : "file"; # $path is crucial! print "$type\t$entry\n"; } closedir( DIR );
It's a common mistake to leave out the $path
from the -d
check. If you do this, perl thinks you're talking about files in the current
directory. Since the dirs don't -e
in your current directory, they
definitely don't -d
. Exceptions are . and ..,
which exist in every directory.
On Win32 platforms, there's a big difference between text files and binary files. For text files, the \r\n characters are translated into \n when read from disk, and the ^Z character is read as an end-of-file marker. For binary files, no such translation is used.
Although this works great for text files, it really messes things up when you're trying to read and write binary files. If the read or write does not abort prematurely because a ^Z was found in the file, you will almost definitely get incorrect bytes in the file due to \n -> \r\n translation.
The problem is that ActivePerl, and the C runtime library it uses, open file in text mode by default. For each file handle you use in Perl for binary data, you need to specify that the file handle is in binary mode. Fortunately, there's a function, binmode, that does just that. See the perlfunc documentation file for details.
This script copies one binary file to another. Note its use of binmode to set the mode of the file handle.
open( INFILE, "<$infile" ); open( OUTFILE, ">$outfile" ); binmode( INFILE ); binmode( OUTFILE ); # crucial for binary files! while ( read( INFILE, $buffer, 1024 ) ) { print OUTFILE $buffer; } close( INFILE ); close( OUTFILE );
Win32 platforms use the '\' character as a delimiter for paths in a file name (C:\like\this). However, Perl uses the '\' character as an escape code, to symbolize a special character like the line feed character (\n) or the tab character (\t).
So, if you try and open a file like this:
open( MYFILE, "C:\temp\newfile.txt" );
you'll get an error. One solution is to replace each '\' with a double-'\', to show that you really mean to use that character, not an escape:
open( MYFILE, "C:\\temp\\newfile.txt" );
Another solution is to use non-interpolating single quote strings, which lets Perl know not to use any special characters:
open( MYFILE, 'C:\temp\newfile.txt' );
Finally, you can also use the / character to separate directory components in pathnames. You must avoid using this in calls to external programs, because some programs tend to treat / as the option-prefix instead of directory separator. However, ActivePerl (and in fact, all of the Win32 API) understands that / is a directory separator, so using / allows you to more easily port scripts between UNIX and Win32:
open( MYFILE, '/temp/newfile.txt' );
See the perlop documentation page for more information on the differences between single quotes (') and double quotes (``).
This is a weird error that occurs when your string terminator is on the last line of your script. With a script like:
print <<"END"; The snake is old, and his skin is cold. END
perl is looking for the word END on a line by itself, followed by a line-feed character (\n). If the END is the last line of your script, you have to remember to hit <Enter> after the word END, so that Perl can recognize it as the string terminator.
Most UNIX text editors will do this automatically. Most Windows text editors won't. Thus the problem.
Note that this can also cause a problem with Perl formats, since these are terminated with a single . on a line by itself. However, it's much more rare, since programmers often specify the format for output at the top rather than at the bottom of a file.
This FAQ was originally assembled and maintained by Evangelo Prodromou. It has been revised and updated by Brian Jepson of O'Reilly & Associates, David Grove, David Dmytryshyn and David Sparks of ActiveState.
This FAQ is in the public domain. If you use it, however, please ensure that you give credit to the original authors.
ActivePerl FAQ - General programming |