程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 用lpadmin打印多種內容形式

用lpadmin打印多種內容形式

編輯:關於JAVA

概述

設置一個能夠處理多種內容形式的打印服務器,似乎並不是一個困難的任務--實際上也不難,只要考慮一下第三方軟件。當你決定只用lpadmin來做時,困難就來了。Unix系統管理專家Errol Fouquet 和Robert Krumm 通過本文指導你用一個經檢驗過的方法,來設置一個打印服務器,使其能夠成功地處理純文本、PostScript、可打印二進制碼(pcl,rtl)等內容形式的文件。

作為UNIX系統管理員在與雇主簽約時,雇主要求他們在給客戶提供的服務中,要有一項是打印與繪圖的技術支持。一個特殊的客戶,他的打印環境相當復雜,包括八台36英寸HP繪圖儀,一台24英寸HP繪圖儀,大約20台HP DeskJet 1600c繪圖儀,以及大約20台HP 3si/4si/5si 打印機。所有的設備運行LPD,有PostScript 驅動程序,作為網絡打印機使用TCP/IP協議來訪問。打印機網卡有HP JetDirect 和XCD XJet 卡各占一半。

我們在一台Sun Ultra Enterprise 450 上運行Zeh Graphic Systems 的 ZPS繪圖軟件,來支持幾個輸出多種圖形格式的應用程序。我們還要支持從幾個其他的應用發出的LPD命令,以及用戶發自Netscape應用程序的打印,還有用戶在命令行下發出的打印命令。在我們的環境中,打印客戶幾乎都是SUN的服務器和工作站,數目有近200個。我們還有一台Windows NT 服務器,運行Citrix Winframe,也是一個打印客戶。

通過Zeh軟件繪圖的應用程序使用Ultra 450 作為緩沖池,除此以外,所有其他的打印請求都從客戶直接傳送到網絡打印機。從功能上講,這種方式工作得很好,能夠打印所有我們需要的內容形式,包括:文本,PostScript,和可打印二進制文件(pcl 和 rtl)。問題是這種設置帶來一個管理惡夢。像GIF 或 JPEG這樣龐大而又不可接受的二進制文件,經常會浪費大量的紙張,而我們又沒有簡單有效的辦法來確定打印請求是從那裡發出的。我們只知道大樓內的一台工作站或是服務器,正在向打印機發送有害的工作任務。不幸的是,標題頁並不是一個選擇,因為用戶不願浪費紙張(反語,哈哈?)。

我們曾經試圖寫一個 shell script程序,讓它掃描大樓內所有的機器,並把行為報告給特定的打印機。用這些信息我們就可以執行Cancel命令。但是這個方法異常緩慢,效率低下。

客戶自己的技術策略顯示,解決辦法就是為UNIX環境寫一個打 衿鞒絛颍遣呗員舊砻揮形庵峙渲錳峁┫附凇A硗猓罱蒘print Paranet做的NOMAN(network operations management網絡操作管理)評估也認為,應該開發一個打印服務器程序來滿足客戶的需求。

我們知道一個打印服務器是正確的選擇。如果我們能夠設置好它,所有的打印請求都可以從一台機器上管理,這會極大地簡化整個過程。 但是這又非常困難,我們難以接受。

嘗試一:試驗和錯誤

最初,我們想建立一個標准的Solaris打印緩沖。我們指定一台測試機器作為測試打印服務器,取名 nolsn099 (一台運行Solaris 2.6的Ultra 1) ,並開始幾個測試。開始用來測試的打印機是一台HP 1600c,在 NIS/DNS環境中稱為no1316p。

對每一種服務器設置,客戶機用命令行 lpadmin -p no1316p -s nolsn099!no1316p 設置來訪問打印機/繪圖儀。

服務器設置1:

lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T PS \

-I PostScript -v /dev/null -i /usr/lib/lp/model/netstandard

結果:客戶機能夠打印 PostScript和二進制文件,但是文本文件會出現樓梯效果。

服務器設置2:

lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T unknown \

-I any -v /dev/null -i /usr/lib/lp/model/netstandard

結果:客戶機能夠打印文本文件,但是 PostScript和二進制文件打印了成垃圾。

服務器設置3:

lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T PS -I text \

-v /dev/null -i /usr/lib/lp/model/netstandard

結果:客戶機能夠打印文本文件和 PostScript文件,但是rtl和pcl文件打印了成垃圾。

服務器設置4:

lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T unknown \
-I PostScript,text,simple -v /dev/null \
-i /usr/lib/lp/model/netstandard
lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T unknown \
-I any,PostScript,simple -v /dev/null \
-i /usr/lib/lp/model/netstandard
lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T PS \
-I any -v /dev/null -i /usr/lib/lp/model/netstandard
lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T unknown \
-I text,simple -v /dev/null
-i /usr/lib/lp/model/netstandard
lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T hplaser \
-I text,simple -v /dev/null
-i /usr/lib/lp/model/netstandard

結果:以上幾種設置,客戶機能夠打印 PostScript和二進制文件,但是文本文件會出現樓梯效果。

服務器設置5:

lpadmin -p no1316p -o protocol=bsd,dest=no1316p -T PS \

-I any -v /dev/null -i /usr/lib/lp/model/netstandard

結果:客戶機能夠打印文本文件和 PostScript文件,但是rtl和pcl文件打印成垃圾。

我們試驗了幾種組合,但是不能成功地打印所有的三種格式。lpadmin的幫助文檔建議可以使用多個 -T選項。我們認為真正需要的是 -T unknown,PS選項,但不幸的是,lpadmin 不允許 unknown 同其他的選項同時出現。

我們得出結論:使用 Solaris lpadmin 提供的標准選項,我們可以設置打印機來處理:

只有文本文件

文本和PostScript

PostScript和可打印二進制文件(pcl和rtl)

下一步我們打電話到SUN的軟件支持部門。很幸運我們找到一個能干的技術支持人員,他給了我們一個看起來可行的方案。盡管他承認這是一個平庸的方法,但他確認它能行。方案包括在打印服務器上為每台打印機設立兩個打印隊列,然後應用兩個打印緩沖。第一個設備起過濾器的作用,然後將其輸出定向到網絡打印機。(我們采用printname printname-r的命名規則)  

以下是具體步驟:

第一步:在服務器上建立過濾設備  

$ lpadmin -p no1316p -v /dev/null -i /usr/lib/lp/model/standard
$ enable no1316p
$ accept no1316p

第二步:編輯新創建的界面描述文件(/etc/lp/interfaces/no1316p)  

找到以 case $TERM in 開頭的 case 語句

對 *) 條件,注釋掉包含 FILTER=${LPCAT} 的一行

插入一行 FILTER=/bin/unix2dos | lp -s -d no1316p-r

第三步:建立網絡服務器(no1316p-r)  

$ lpadmin -p no1316p-r -o protocol=bsd,dest=no1316p -v /dev/null \
-i /usr/lib/lp/model/netstandard
$ enable no1316p-r
$ accept no1316p-r

注:沒有指定 -T -I 選項,使用缺省的 "unknown" " any"

完成以上步驟後,似乎打印機正常工作了。命令unix2dos修正了文本文件的樓梯現象,而且我們也能打印PostScript, pcl, 和 rtl 文件。我們幾乎准備慶祝了,這時我們注意到pcl和rtl 文件的打印質量極其糟糕。命令unix2dos 搞壞了二進制格式!

我們又打回電話給SUN。這一次我們同幾位SUN的工程師開了一個電話會議,報告我們的需求和發現。他們建議使用一個lpadmin命令(我們曾經使用過)來設置打印機。當我告訴他們這會導致文本文件出現樓梯效果時,其中兩個工程師心照不宣地歎息了一聲。他們答應查一下。同時,我們也繼續尋找答案。

嘗試二:紅色磁帶

接下來,我們試著使用Hewlett-Packard的 JetAdmin 軟件--SUN的推薦方案。我們設置一台機器作為打印服務器,然後安裝JetAdmin軟件。棒極了。我們能夠完美無缺地打印這三種文件。我們能夠設置客戶機,以這台服務器做打印緩沖;而且軟件提供了信息,用來管理不必要的打印作業。我們找到了解決方案!錯了,我們被告知不能替換XCD卡。

還沒有得到SUN公司的反饋信息,我們選擇重新試驗"double spooling"雙緩沖的方案

嘗試三:重試雙緩沖

雙緩沖方案已經接近成功,我們不能完全放棄它。只是unix2dos的限制妨礙成功。如果我們能檢查輸入文件,只對非二進制文件執行unix2dos,那就成了。我們寫了一個簡單的Perl程序(unix2dos.pl)來做這些:

#!/opt/bin/perl
# open standard input
open(FOO, "-");
# test if binary
if ( -B FOO) {
while () {
print $_;
}
}
# if not binary.. perform unix2dos filtering
else {
while () {
s/\n/\r\n/; print;
}
}
close(FOO);

界面文件中的那一行改成如下:

FILTER=/opt/utils/unix2dos.pl | lp -s -d no1316p-r

可以了。我們可以毫無問題地打印這三種文件了。不幸,由於雙重緩沖,在 no1316p-r 中的打印作業不再具有有意義的名字和所有者了。例如,當一個客戶打印一個文件,比如/etc/passwd;在打印服務器上執行lpq -Pno1316p ,會有以下結果:

$ lpq -Pno1316p
Rank Owner Job File(s) Total Size
active dlister 313 /etc/passwd 522 bytes

但是當no1316p過濾了這個作業,並把它重定向到 lp -s -dno1316p-r後,在打印服務器上執行lpq -Pno1316p-r ,我們會有以下結果:

$ lpq -Pno1316p-r
Rank Owner Job File(s) Total Size
active lp 1629 1629-1 536 bytes

沒有恰當指定的文件名和所有者,用戶不能跟蹤在打印隊列裡的文件,管理員也不能從隊列中刪除打印作業。

嘗試4:找一個折衷  

因為我們已經成功地打印這三種文件,現在我們需要的只是網絡打印機隊列中的有意義的信息。我們知道,當打印作業在過濾隊列(如no1316p)中排隊時,原始的文件名和用戶名是可用的。我們必須找出一個辦法,保存這些信息,並把它們與在實際的網絡打印機隊列(如no1316-r)中排隊的打印作業對應起來。

我們知道,當一個作業通過過濾隊列時,lp子系統會返回我們感興趣的信息。所以顯而易見,我們應該能夠通過環境變量利用這些信息。我們感興趣的變量可以用在過濾隊列的界面描述文件中:${request_id}, ${user_name},${files}, 和 ${flist}。但是我們仍然面臨一個問題:把這些信息同實際的網絡打印機隊列的lpq聯系起來。我們需要一種手段,記錄那些進入過濾隊列的請求;還需要一個方法,把網絡打印機隊列中的各個項映射回初始的信息。

我們最終采用的策略是,將輸入過濾到一個臨時文件,文件名中包含初始的${request_id}。然後重定向該臨時文件的lp,現在網絡打印機隊列的lpq 信息中以文件名的形式包含了初始的${request_id} 。只剩下log文件了。我們進一步修改過濾隊列的界面描述文件,在if [ -z "${FILTER}" ]後加上以下程序:

# write current request_id user_name and flist to logfile
# if the flist variable is null, we are printing a single file,
# therefore echo ${files}
# else echo ${flist}
if [ "$flist" = "" ];
then
echo "${request_id} ${user_name} ${files}" \
$gt; $gt; /var/spool/lp/save_dir/logs/request.log
else
echo "${request_id} ${user_name} ${flist}" \
$gt; $gt; /var/spool/lp/save_dir/logs/request.log
fi

我們把創建臨時文件的工作並入unix2dos.pl程序中。新的程序稱為lp.pl:

#!/opt/bin/perl
# open standard input
open(FOO, "-");
# create temp file for writing
open(OUT, "$#@62;/var/spool/lp/save_dir/tmp/$ARGV[0].$$");
# if input stream is binary do not filter
if ( -B FOO) {
while () {
print OUT $_;
}
}
# else filter the line unix2dos style
else {
while () {
s/\n/\r\n/; print OUT;
}
}
close(FOO);
close(OUT);
# send print request
system("/bin/lp -s -d $ARGV[1] /var/spool/lp/save_dir/tmp/$ARGV[0].$$");

下一步,我們向lp.pl傳遞兩個參數:${request_id}, 和網絡打印機。這個程序生成一個名字為:

${request_id}."進程的pid號"的過濾後的臨時文件,並lp這個臨時文件。然後,我們把過濾隊列界面文件中的:

FILTER=/opt/utils/unix2dos.pl | lp -s -d no1316p-r

這一行,替換成:

FILTER="/var/spool/lp/save_dir/sbin/lp.pl ${request_id} no1316p-r"

讓我們總結一下到了現在會發生什麼:

用戶(dlister)從客戶機器發送一個lp作業:lp -d no1316p /var/adm/messages

打印服務器接受該作業,通過過濾隊列處理這個請求

過濾隊列記錄當前的作業號(${request_id}),用戶(dlister),以及文件名(/var/adm/messages)

輸入送到lp.pl程序,該程序創建一個臨時文件,並利用網絡打印機隊列執行一個lp命令。

到此,如果在網絡打印機上執行lpq,結果會如下:

$ lpq -Pno1316p-r
Rank Owner Job File(s) Total Size
active lp 1629 /var/spool/lp/save_dir/tmp/no1316p-1625.2974 536 bytes

現在,我們只需要一個程序來索引log文件,找到no1316p-1625,然後返回初始的所有者和文件名。我們寫了如下程序:

#!/bin/ksh
typeset -i N
typeset -i N2
# set N2 equal to the default number of fields per log file entry
N2=3
if [ $# -ne 1 ]
then
echo "usage: $0 network_printer_queue"
exit 1
fi
echo "Rank Owner Job File(s) Total Size"
/usr/ucb/lpq -P $1 | grep bytes | while read line
do
RANK=`echo $line | awk "{print $1}"`
JOB=`echo $line | awk "{print $3}"`
SIZE=`echo $line | awk "{print $5}"`
TEMP=`echo $line | awk "{print $4}"`
GREPSTUFF=`basename $TEMP | awk -F. "{print $1}"`
OWNER=`grep -w $GREPSTUFF /var/spool/lp/save_dir/logs/request.log \
| awk "{print $2}"`
# count the number of fields in the log file: 3 means a single file
# printed more than
# 3 means that several files were sent at once.
N=`grep -w $GREPSTUFF /var/spool/lp/save_dir/logs/request.log \
| awk "{print NF}"`
if [ $N -gt 3 ]; then
FILE=`grep -w $GREPSTUFF /var/spool/lp/save_dir/logs/request.log \
| awk "{print \\$$N2}"`
echo "$RANK $OWNER $JOB $FILE $SIZE bytes"
N2=N2+1;
else
N2=3
FILE=`grep -w $GREPSTUFF /var/spool/lp/save_dir/logs/request.log \
| awk "{print $3}"`
echo "$RANK $OWNER $JOB $FILE $SIZE bytes"
fi
done

這段程序只要一個參數:打印服務器隊列的名字。在我們的例子中,我們只需要輸入 $ lpq.ksh no1316p-r 就可以顯示以下結果:

Rank Owner Job File(s) Total Size

active dlister 1629 /var/adm/messages 536 bytes

用這段程序,就可以給用戶提供用來跟蹤他們的打印作業的信息,打印服務支持人員可以在打印服務器上更好地管理打印作業。

清尾:

最後,我們需要一個手段來刪除在/var/spool/lp/save_dir/tmp中創建的臨時文件。我們注意到:一旦一個打印作業通過lp子系統成功執行,在/var/spool/lp/logs/requests.log文件中會出現一項 T filename。

為清除臨時文件,我們寫了一個程序稱為cleanup.ksh:

#!/bin/ksh
cd /var/spool/lp/save_dir/tmp
unalias ls
# our temp files are all begin with "no"
if [ -f no* ];
then
for i in `ls no*`
do
grep "^T $i" /var/spool/lp/logs/requests $#@62; /dev/null 2$#@62;&1
if [ $? -eq 0 ];
then
rm -f $i
fi
done
fi

我們在打印服務器上設置一個corn作業,每小時運行一次以上程序。

結論

我們完成了最初的目標,盡管該解決辦法可以進一步精煉:

通過一個中央服務器進行緩沖

使用單一的打印機名,三種內容形式

(文本,PostScript,pcl/rtl)的文件都可以正確打印

能夠在整個過程中跟蹤打印請求

能生成有意義的lpq信息

集中並簡化打印環境

沒有任何額外花費就完成了任務

另外,我們相信本文描述的改進完全可以融合到Solaris 2.6的打印子系統中,使用戶不再需要第三方的軟件和硬件解決方案。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved