perl网络编程小记(-)

当perl脚本开始执行时,默认地打开3个文件句柄:STDOUT,STDIN,STDERR

STDOUT(standard outpu)是默认的输出文件句柄.发送给这个文件句柄的
数据在用户指定的输出设备上显示,通常是脚本运行的命令窗口。

STDIN(standard input)是默认输入的文件句柄,从这句柄读取的数据取自
用户选择输入设备,通常是键盘.

STDERR(即,standard error)用于错误消息,诊断,调式和其他类似的偶发输出。

$line = <>;  #一次读一行
@line = <>;  #读取所有的数据


$bytes = read(FILEHANDLE,$buffer,$lenght,[,$offset])
$bytes = sysread(FILEHANDLE,$buffer,$length,[,$offset])


read()函数和sysread()函数从指定文件句柄中读取任意的数据。
读取的长度可以达$length字节,所读的数据被置于$buffer中。
两个函数都返回实际读取的字节数,如果是文件尾侧则返回数字。

read()和sysread()的主要区别是read()使用标准的I/O缓冲而sysread()不用。
这就意味着read()直到读取所需的实际字节数或读取文件文件尾才返回。
相反,sysread()函数返回部分数据,它确保至少返回1个字节,但是如果它不能
从文件句柄立即读取所需的字节数,则它将会返回它能读取的内容。



$bytes=syswrite(FILEHANDLE,$data[,$lenght [,$offset]])
syswrite()函数是一个写文件句柄的选择,可以更多地控制写的过程。
它的参数是一个文件句柄和一标量值(变量或字符串文字)。它将数据写文件句柄,返回成功
写入的字节数。默认地,syswrite()尝试写$data的整个内容,从字符串首字符开始.可以通过
提供可选的$length$offset来改变syswrite()的上述行为,在这种情况下,syswrite()
将从$offset指定位置开始写$length.


$previou=select(FILEHANDLE);
select()函数用于改变print()的默认输出文件句柄.它将文件句柄名设置为默认值,返回前面的默认
名. select()函数是一个具有四个参数的版本,用于多路复用.


$! 根据上下文返回的错误

eof()函数,用于显示地测试条句柄的EOF条件


行尾
  在unix系统上,行以字符(LF,ASCII表中的八进制的\012)结尾;
  在Macintosh系统上,行以回车字符(CR,八进制的\015)结尾;
  在Windows/DOS系统上决定换行以两个字符结尾,一个是回车/换行对(CRLF,或者八进制的\015,\012)
  多数面向行的网络服务器也使用CRLF换行符终止。

  perl提供了一个检查并改变行尾字符的方法.全局变量$/包含用来指行尾的当前字符或字符序列.
  默认地,该变量在UNIX系统设置为\012,在Macintosh系统上设置\015,在Windows AND DOS系统上
  设置为\015 \012.

  而面向行的<>输入函数将从指定的句柄读取数据,直到它遇到包含在$/中的行尾字符,然后它返回
  附有行尾的字符序列的文件本行。chomp()函数根据$/的当前值在文件字符串的尾部查找行尾的字符
  序列并删除之。

  binmode()函数 关闭字符转换
  binmode(FILEHANDLE,[,$disciplie])
  binmode()函数为文件句柄打开二进制模式,并取消字符转换。该函数应该在文件句柄打开之后在对
  文件句柄做任何I/O操作之前被调用。


  open(FILEHANDLE,$mode,$path);

  模式    描述
  <       打开文件用于读
  >       截取文件长度为0并打开用于写
  >>      打开文件用于添,不截断
  +>      截断文件,然后打开用于读/写
  <+      打开文件用于读/写,不截断


sysopen(FILEHANDLE,$filename,$mode[,$perms]);
sysopen()函数打开由$filename指定的文件,使用了$mode指定的I/O模式.如果文件不存在,
并且$mode指定该文件应该创建,则可选项$perms的值明新创建文件的许可位。

常量        描述
O_RDONLY    打开用于只读
O_WRONLY    打开用于只写
O_RDWR      打开用于读/写
O_EXCL      和O_CREATE组合使用时,文件不存在时创建文件,文件存在时失败
O_TRUNC     如果文件已存在,将其截断为长度0
O_APPEND    以添加模式打开文件(同等于open()的">>")
O_NOCITY    如果文件为终端设备,打开它并且不允许它成为进程的控制终端
O_NONBLOCK  以无阻塞模式打开文件
O_SYSNC     以同步方式打开文件,阻塞所有的写操作直到完成数据的物理写



缓冲和阻塞
  当对文件句柄调用print()和syswrite()时,实际的输出操作并不是立即发生。如果对文件写,
  系统必须等待书写头到达到磁盘驱动上的合适位置,并等待旋转磁盘将写的对应位置带到书写头下面来。

缓冲区在概念上是循环的FIFO(先进先出)数据结构。当写入的数据超出缓冲内存区的尾部时,操作系统仅仅
在缓冲区的开头写入新的数据。操作系统在综的每个I/O缓冲区中维护两个指针。写指针指向新数据进入的缓冲
区的地方。读指针所指的位置处的数据被从缓冲区中移出,写到下一目的地。



两种方法能够解决stdio缓冲问题.一种方法是为文件句柄打开"autoflush"模式。"autoflush"模式
只用于输出操作。当激活autoflush模式时,每次调用print()时perl都会告诉stdio将文件句柄的
缓冲区中的内容送出。
为了打开autoflush模式,应将特殊变量$|设为true值。autoflush模式影响当前选择的文件句柄,
因此为一特定的文件句柄选择前面所选的文件句柄(使用select()).

my $previous=select(FH);
$|=1;
select($previous);

select((select(FH),$|=1)[0])

另一种避免stdio缓冲的问题的方法是使用sysread()调用和syswrite()调用。这两个调用绕过了
stdio库直接进入操作系统I/O调用。这两个调用的一个重要的有点就是可以和其他的低层I/O调用
(例如参数的select()调用)很好相互操作,可以和高级的技术(例如无阻塞I/O)很好的相互操作。




传递和存储文件句柄

有时你需要检查一标量看其是否包含一信有效的文件句柄.fileno()函数可以满足这个需要;

$integer=fileno(FILEHANDLE);

fileno()函数以字符串形式,typeglob形式或typeglob引用形式接受文件句柄。如果文件句柄有效,
则fileno()返回文件句柄的文件描述符(file descriptor).文件描述符是个小整数,唯一标识操作
系统的文件句柄.一般地,STDIN,STDOUT,STDERR分别对就描述符012(如果你关闭重新打开它们则可以
以改变其描述符)。其他文件句柄具有大于3的描述符。



错误检测

use Errno qw(EACCES ENOENT);

my $resutl = open(FH,"/etc/passwd1");
if(!$resutl)  #oops,something went wrong
{
 if($! == EACCES)
 {
    warn "You do not have permission to open the file.\n";
 }
 elsif($! == ENOENT)
 {
    warn "File or directory not found.\n";
 }
 else
 {
    warn "Some other error occurred: $!\n";
 }
}


IO::Handle 模块和IO::File模块

#!/usr/bin/perl
#打开一个文件,统计文件的行数
use strict;
use warnings;
use IO::File;

my $file = shift;
my $counter = 0;
my $fh = IO::File->new($file) or die "Cant open $file:$!\n";
while(defined(my $file = $fh->getline()))
{
   $counter++;
}

STDOUT->print("Counted $counter lines\n");


IO::File->new($filename [,$mode [,$perms]])
new()方法是IO::File的主要构造函数.它是open()和sysopen()的统一替代物。
例如:将打开指定文件用于添:
$fh=IO::File->new(">darkstar,txt");

$fh=IO::File->new_tmpfile();
new_tmpfile()构造函数被调用时不需要参数,它创建一个临时文件并打开用于读和写。
在UNIX系统上,该文件是匿名的,意味着它对文件系统不可见。当撤销IO::File对象时,这
个文件和它的全部内容将自动删除。这个构造对存储大量的临时文件很有用。
$resutl=$fh->close;

$result=$fh->open($file [,$mode [,$perms]]);
可以使用open()方法对指定的谁的重新打开 一个文件句柄对象.输入的参数和new()相同。方法
的结果指示打开操作是否成功完成。
这个方法主要用来重新打开标准的文件句柄STDOUT,STDIN,STDERR.
STDOUT->open(">log.txt") or die "Cant reopen STDOUT:$!";
对print()的调用现在将写入文件log.txt

$result=$fh->print(@args);
$result=$fh->printf($fmt,@args);


$bytes=$fh->write($data[,$length [,$offset]]);
$bytes=$fh->syswrite($data[, $length [,$offset]]);

print(),printf()和syswrite()三个方法的工作机制和它们的内置对应函数完全一样。
例如,print()接收一系列数据项,将它们写入文件句柄的对象,并当成功写入时返回true.

write() and read()相反,将字节流写入文件句柄对象并返回成功写入的字节数。


$lines=$fh->getline;
@linges=$fh->getlines;
$bytes=$fh->read($buffer,$legal[,$offset])
$bytes=$fh->sysread($buffer,$length[,$offset])
getline()和getlines()两个方法一起代替了<>运算符。getline()从文件句柄对象读取一行
并返回它,对村量下下文和列表上下文其行为一样。getlines()方法在列表上下文中和<>的行为
一样,返回所有能获得的行一个列表。getline)在文件尾将返回undef;

$previous=$fh->autoflush([$boolean])
autoflush()方法获取或设置文件句柄对象的autoflush模式。无参数调用时,它打开autoflush.
以单一布尔参数被调用时,它将autoflush设置指定状态。两种情况下,autoflush()都返回autoflush
状态的前一个值。
$boolean=$fh->opened;
如果文件句柄对象是肖有效的则opened()方法返回true.它造价于:
defined filno($fh);
$boolean=$fh->eof;

如果下次对文件句柄对象读取操作将返回EOF,则该方法返回true;

 $fh->flush;
 flush()方法立即"涌出"缓冲在文件句柄对象中的任何数据。如果文件句柄用于写,则将其缓冲
 的数据写向磁盘(或者管道,网络)。如果文件句柄用于读,则丢弃缓冲区中的任意数据,强制下
 一次从磁盘读取。

 $boolean=$fh->block([$boolean])
 blocking()方法作为文件句柄打开和关闭阻塞模式。

$fh->clearerr;
$boolean=$fh->error;
如果你希望执行一系列I/O操作并且只在完成之后检查错误的状态,则用这两个方法会很方便。
如果在文件句柄被创建以来或在最后一次调用clearerr()以来发生了任何错误,则error()
将返回true.clearerr()方法清除该错误标志。



-----------------------------------------------------
进程,管道和信号
-----------------------------------------------------


进程

perl支持两种类型的多任务。一种类型基于传统的UNIX多进程模型,允许当前进程通过fork()
函数复制它本身。一个进程做一项任务,另一个进程做另一个项任务。
另一种基于现代更轻便"线程"。将所有的任务保持在单一进程内容。然而,一个单一程序可以具有
多个执行的线程在其中运行,每一线程都独立其他线程而运行。

perl的fork()函数不带参数并且返回一个数值型结果码。当调用fork()时,它生成一个当前进程的
精确拷贝.称为子进程的这个拷贝共享所有变量,文件句柄(包括标准I/O缓冲区中的数据)和基他
数据结的所有当前值。事实上,这个复制的过程甚至具有调用fork()的内存。

调用fork()之后,父进程和子进程都检查函数的返回值。在父进程中,fork()返回子进程的PID。
在子进程中,fork()返回数值0.代码如果发现它是父进程就会开始做一件事情,如果它是子进程
就会做另一件事情。

$pid=fork();
派生一个新进程。在父进程中返回子进程的PID,在子进程中返回0.发生错误时(例如没有足够的
内存派生子进程),返回undef,并将$!设置为适当的错误消息。

如在调用fork()之后父进程和子进程希望相互通信,它们可以通过管道来完成或者通过共享内存
来完成。对于简单的消息,父进程和子进程可以使用kill()函数来给相互的PID发送信号。父进程
从fork()的结果代码中获取了子进程的PID,而子进程通过调用getppid()来获取父进程的PID。
一个进程可以通过检查$$特殊变量来获取它自己的PID.

$pid = getppid();
返回父进程的PID,每个perl脚本都具有父进程,甚至那些直接从命令运行的perl脚本也有父进程
(它们的父进程是shell进程)

$$
$$变量保存当前进程的PID。它可读但不能改变。


如果子进程愿意,它本身也可以调用fork()创建孙子进程。原始进程父进程也可以再次调用fork()
创建子进程,其子进程和孙子进程也都可以。以这种方式,perl脚本可以创建一个进程的整个部落。
这个部落的每个成员属于相同的进程组(process group)

每个进程都有一个唯一的ID,通常和共享的祖先的进程ID相同。该值可以通过调用getpgrp()获得:
$processid=getpgrp([$pid]);
对于$pid指定的进程,getpgrp()函数返回它的进程组ID,如果没有指定PID,则返回当前进程的进程组。
#!/usr/bin/perl
use strict;
use warnings;

print "PID=$$\n";

my $child = fork();
die "Cant fork:$!\n" unless defined $child;

if($child > 0)
{
   print "Parent process: PID=$$, child=$child\n";
}
else
{
   #child process
   my $ppid=getppid();
   print "Child process: PID=$$, Parent=$ppid\n";
}
~


system()函数和exec()函数
perl的另一种运行子进程方法使用system().system()将另一个程序作为子进程运行,等待它的完成,
然后返回。如果运行成功,system()返回结果码0,反之,如果程序不能开始运行就返回-1,如果程序
错误终止则返回程序的终止状态。

$status=system('command and aguments');
$status=system('command','and','arguments');
system()函数将一个命令作为子进程执行并等待它终止。命令及其参数可以作为一个单一字符串指定,
或者作为一个列表指定,该列表包含命令及其参数,但都作为独立的元素。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值