Next Previous Contents

11. 如何列印到网路印表机

Lpd 的一个特性便是可以透过网路将报表列印到实体连接在其它机器上的印表机. 只要仔细地组合 filter 命令稿和相关的工具程序, 你就可以让 lpr 得以透通地 (transparently) 列印到各种网路上的印表机.

11.1 列印至 Unix/lpd

要让硬件的机器能够使用你的印表机列印, 你必须将硬件机器列名在 /etc/hosts.equiv 或是 /etc/hosts.lpd 文档之中. (要注意 hosts.equiv 还有其它很多作用; 如果你要将一部机器列在这儿, 请确定你知道你在做什么). 你也可以利用 rs 属性来限定其它机器上的某些特定使用者才能使用你的印表机. 请看 lpd 的线上手卌以取得这方面的信息.

lpd

要列印到另一部机器, 你要在 /etc/printcap 中加上这样的记录,

# REMOTE djet500
lp|dj|deskjet:\
        :sd=/var/spool/lpd/dj:\
        :rm=machine.out.there.com:\
        :rp=printername:\
        :lp=/dev/null:\
        :sh:
请注意在本地的机器还是要有一个由 lpd 管理的列印暂存器目录. 如果硬件的机器离线或是忙不过来, 列印工作会留在本地的暂存区中直到送出去为止.

rlpr

你也可以用 rlpr 将列印工作直接送到硬件机器的伫列中, 省下设定 lpd 的麻烦. 假如你偶尔才要列印到其它不同的印表机, 这个方法就最有用. 引一段 rlpr 的声明:

rlpr 利用 TCP/IP 将列印工作送到网路上任何位置的 lpd 伺服器.

与 lpr 不同的是, 你列印来源端的机器 *不需要* 明确地知道硬件的印表机, (例如透过 /etc/printcap) 因此有相当大的弹性, 管理的负担也比较轻.

rlpr 可以用在任何使用传统 lpr 的地方, 而且和传统的 BSD lpr 兼容.

rlpr 最大的好处在于可以 *从任何地方列印到任何地方* 而不用管列印来源端的系统设定. 它可以像传统的 lpr 做为一个 filter, 而让在硬件机器上执行的客户端像 netscape, xemacs 等能够轻易地列印报表到你本地的机器.

你可以在 Metalab 找到 rlpr.

11.2 列印到 Win95, WinNT, LanManager, 或 Samba 上的印表机

在 Printing to Windows mini-HOWTO 中有比这儿更多的信息.

透过 smbclient 这个程序 (samba 套件的一部份) 可以将 lpd 伫列导向到架构在 TCP/IP 之上的 SMB 列印服务. Samba 包含了一个命令稿 smbprint 来做这件事. 简单地说, 替这样的印表机在列印暂存器工作目录 (spool directory) 中加上设定档, 然后将 if 设为 smbprint 命令稿.

/etc/printcap 中的记录看起来应该像这个样子:

lp|remote-smbprinter:\
    :lp=/dev/null:sh:\
    :sd=/var/spool/lpd/lp:\
    :if=/usr/local/sbin/smbprint:

你应该阅读一下 smbprint 命令稿中的说明以得到更多相关的信息.

你也可以不管 lpd, 直接用 smbclient 将文档送到 SMB 列印服务. 请参照线上手卌.

11.3 列印到 NetWare 上的印表机

ncpfs 套件中包含了一个名为 nprint 的工具程序, 它提供如同 smbprint 一般的功能, 只不过适用的对象是 Netware. 你可以在 Metalab 取得 ncpfs. 下面是从 0.16 版的 LSM 中节录出来的:

With ncpfs you can mount volumes of your netware server under Linux. You can also print to netware print queues and spool netware print queues to the Linux printing system. You need kernel 1.2.x or 1.3.54 and above. ncpfs does NOT work with any 1.3.x kernel below 1.3.54.

利用 ncpfs, 你可以在 Linux 下挂上你的 netware 伺服器上的目录. 你也可以列印到 netware 的列印伫列以及将 netware 的列印伫列排存(spool) 到 Linux 的列印系统. 你需要 1.2.x 或 1.3.54 以上(含 1.3.54) 的核心. ncpfs 无法在 1.3.54 以前的任何一版 1.3.x 核心下运作.

要使 nprint 透过 lpd 运作, 你要写个小小的 shell script 将 stdin 列印到 Netware 上的印表机, 并设成 lpd 列印伫列的 if. 你可能会有:

sub2|remote-NWprinter:\
        :lp=/dev/null:sh:\
        :sd=/var/spool/lpd/sub2:\
        :if=/var/spool/lpd/nprint-script:
nprint-script 看起来可能大致上像:
#! /bin/sh
# You should try the guest account with no password first!
/usr/local/bin/nprint -S net -U name -P passwd -q printq-name -

11.4 列印到 EtherTalk (Apple) 上的印表机

netatalk 套件包含了像 nprintsmbclient 的东西. 其他人已经写下了使用 Apple 网路列印的程序, 远比我所能写的好得多; 请参阅 Linux Netatalk-HOWTO.

11.5 列印到 HP 或其它的以太网路(ethernet) 印表机

有些 HP 和其它厂牌的印表机提供了可以直接用 lpd 列印的以太网路界面. 你应该遵照印表机或其网路界面所附的指示, 但是通常这种印表机上 "跑" 的是 lpd, 而且提供一到多个你可以使用的伫列. 举例来说, 一部 HP 可能可以用这样的 printcap:

lj-5|remote-hplj:\
        :lp=/dev/null:sh:\
        :sd=/var/spool/lpd/lj-5:\
        :rm=printer.name.com:rp=raw:

具有 Jet Direct 界面的 HP Laserjet 印表机通常支持两个内建的 lpd 伫列 - "raw" 接受 PCL (可能也接受 Postscript), 以及 "text" 接受单纯的 ascii (而且会自动地克服阶梯效应). 如果你有的是 JetDirect Plus3 三埠的界面, 伫列的名称则为 "raw1", "text2" 等等.

注意 ISS 公司己经找到某一类的过量攻击(denial of service attacks) 可以导致 HP Jetdirect 界面当掉. 大部份是在 98 年的秋天开始被发现的.

在一个大型的环境, 特别是个有些印表机不支持 PostScript 的大型环境中, 架设一部专门的列印伺服器, 让所有的机器都列印到这部伺服器并让所有的 ghostscript 工作都在这部伺服器上面执行可能会有用.

这样子也可以让你的 Linux 做为印表机的排存伺服器(spool server), 如此一来你的网路使用者便可以快一点完成他们的列印工作然后继续手边的事情, 而不必等待印表机印完先前别人所送出的报表. 如果你有无法调整的旧型 HP Laserjets; 也可以这样做以降低印表机壅塞的机率.

要这样做, 先在你的 linux 机器上设定一个列印伫列指到配有以太网路界面 HP LJ (如前所述). 现在将所有在你区域网路上的客户端设定指到这个 Linux 伫列 (如前面范例中的 lj-5).

有些 HP 网路印表机似乎不理会客户端送出的标题页(banner page) 设定. 你可以关掉它们内部自行产生的标题页, 用 telnet 连接到印表机, 按两下 return 键, 打入 "banner: 0", 接著打入 "quit". 还有其它可以调整的设定也是用这个方式; 打入 "?" 可以看到它们的表列.

你可以用 HP 的 WebJet 软件来控制全部的设定. 这套软件是以 daemon 的方式执行, 接受在指定埠号上的 http 连线需求(http request). 它提供 http 表格(form) 及 Java applets 来控制网路上的 HP 印表机. 理论上, 它也可以控制 Unix 的印表机伫列, 但是这得使用极不安全的的 rexec 服务. 我不建议使用这个功能.

列印到比较旧的 HP 印表机

有些印表机 (或是将印表机连上网路的装置) 只支持很阳春的 TCP 连线. 在这一类中较著名的便是早期的 JetDirect (包括一些 JetDirectEx) 界面卡. 基本上, 要列印到这类的印表机, 你必须建立到印表机上某个特定埠 (典型是在 9100, 或是三埠机种的 9100, 9101 和 9102) 的 TCP 连接, 然后将你的报表送进去. LPRng (如果你正在读这一段, 你真的该改用它) 内建支持将列印工作送到任意的 TCP 埠, 但是 BSD 的 lpd 就不是这么简单了. 我们可以用 Perl 来实做, 或是用其它的方式:

#!/usr/bin/perl
# Thanks to Dan McLaughlin for writing the original version of this
# script (And to Jim W. Jones for sitting next to Dan when writing me
# for help ;)

$fileName = @ARGV[0];

open(IN,"$fileName") || die "Can't open file $fileName";

$dpi300     = "\x1B*t300R";
$dosCr      = "\x1B&k3G";
$ends = "\x0A";

$port =  9100 unless $port;
$them = "bach.sr.hp.com" unless $them;

$AF_INET = 2;
$SOCK_STREAM = 1;
$SIG{'INT'} = 'dokill';
$sockaddr = 'S n a4 x8';

chop($hostname = `hostname`);
($name,$aliases,$proto) = getprotobyname('tcp');
($name,$aliases,$port) = getservbyname($port,'tcp')
    unless $port =~ /^\d+$/;;
($name,$aliases,$type,$len,$thisaddr) =
        gethostbyname($hostname);
($name,$aliases,$type,$len,$thataddr) = gethostbyname($them);
$this = pack($sockaddr, $AF_INET, 0, $thisaddr);
$that = pack($sockaddr, $AF_INET, $port, $thataddr);

if (socket(S, $AF_INET, $SOCK_STREAM, $proto)) {
#    print "socket ok\n";
}
else {
    die $!;
}
# Give the socket an address.
if (bind(S, $this)) {
#    print "bind ok\n";
}
else {
    die $!;
}

# Call up the server.

if (connect(S,$that)) {
#    print "connect ok\n";
}
else {
    die $!;
}

# Set socket to be command buffered.

select(S); $| = 1; select(STDOUT);

#    print S "@PJL ECHO Hi $hostname! $ends";
#    print S "@PJL OPMSG DISPLAY=\"Job $whoami\" $ends";
#    print S $dpi300;

# Avoid deadlock by forking.

if($child = fork) {
    print S $dosCr;
    print S $TimesNewR;

    while (<IN>) {
        print S;
    }
    sleep 3;
    do dokill();
} else {
    while(<S>) {
        print;
    }
}

sub dokill {
    kill 9,$child if $child;
}

11.6 替硬件印表机执行 if

lpd 一个不寻常的地方在于如果是硬件印表机, if 不会被执行. 如果你发现你需要执行 if, 你可以设定双重伫列(double queue) 并重新伫列报表. 举个例子, 看一下这个 printcap:

lj-5:\
        :lp=/dev/null:sh:\
        :sd=/var/spool/lpd/lj-5:\
        :if=/usr/lib/lpd/filter-lj-5:
lj-5-remote:lp=/dev/null:sh:rm=printer.name.com:\
        :rp=raw:sd=/var/spool/lpd/lj-5-raw:
和相关的 filter-lj-5 命令稿(script):
#!/bin/sh
gs <options> -q -dSAFER -sOutputFile=- - | \
        lpr -Plj-5-remote -U$5

只有在 lpr 以监控程序(daemon) 模式执行的时候, -U 选项才有作用, 这个选项会正确地设定第二重伫列中的送件人姓名. 你可能应该用更可靠的方法取得送件人姓名, 因为有些时候它并不是第五个参数. 请参照 printcap 的线上手卌.

11.7 从 Windows 列印

利用 SAMBA 套件可以直接支持以 SMB 协定从 Windows (或许 OS/2) 客户端列印到 Linux 伺服器, 这个套件同时也支持将你的 Linux 文档系统分享给 Windows 客户端.

Samba 包含了相当完整的文件, 也有一份很不错的 Samba FAQ 涵盖到这方面的内容. 你可以在 Linux 上设置 magic filter 然后以 PostScript 列印, 或是在每一部 Windows 机器上安装印表机专用的驱动程序然后为他们设定一个不用任何 filter 的伫列. 使用 Windows 驱动程序有些时候会有比较好的输出, 但是如果有很多部 Windows 机器, 管理者就比较麻烦. 所以先试试看 PostScript 吧!

11.8 从 Apple 列印

Netatalk 支持由 Apple 客户端透过 EtherTalk 列印. 请参照 Netatalk HOWTO Page 以取得更进一步的信息.

11.9 从 Netware 列印

ncpfs 套件含有一个叫作 pserver 的监控程序(daemon) 可以提供服务给 NetWare 的列印伫列. 据我所瞭解, 这个系统必须搭配 Bindery-based 的 NetWare, 像是 2.x, 3.x, 或是使用 bindery 存取的 4.x 版本.

要取得更进一步关于 ncpfs 和其 pserver 程序的信息, 请参照 ncpfs 的 FTP 站.


Next Previous Contents