背景
手上有一个HP DeskJet 2332 打印扫描一体机,当初为了孩子上网课买的。家里有个打印机还是很方便的,同时扫描仪也偶尔会用一用,比如扫描证件等。
但是打印机这东西比较大,放哪里是个大问题,放哪里都占地方,而且容易吃灰。
前面介绍过我的AIO家庭服务器,于是我决定将打印机和服务器放一起,再通过网络共享出来。说干就干。
由于ESXi本身不支持打印机,所以只能将打印机交给其中一台虚拟机来管理并共享。首先我就想到了群晖,但从DSM 6.2开始打印机共享服务就停止支持。实测DSM7.1共享打印机确实无法使用,所以现在剩下的选择就是OpenWRT和Windows。下面我们就看看OpenWRT共享打印机怎么样吧。
相关协议
工欲善其事,必先利其器。所以在工作之前,我们先了解一下网络打印机相关协议。
网络打印协议
LPD/TCP/515
LPD是“行式打印机后台程序”协议的缩写,该协议监听TCP 515端口,可以通过CLI使用“lpr”进行访问。为了打印,客户端需要发送一个作业控制文件和包含要打印的数据文件。
IPP/TCP/631
IPP是基于HTTP的扩展协议,因此它继承了HTTP协议所有的安全功能,如基本身份验证和SSL/TLS加密。要提交打印作业,用户需要发送HTTP POST请求到IPP服务器,该服务器监听TCP 631端口,任何人都知道CUPS是IPP协议的一个实现,它是许多Linux发行版和macOS X中的默认打印系统。
HP Jetdirect - Socket/TCP/9100
也被称为“raw printing”,因为它使用TCP 9100端口进行网络打印操作,通常在CUPS和Windows系统中使用。与LPD,IPP和SMB协议需要使用打印机控制语言才能执行打印操作相比,通过9100端口发送的所有数据都由打印设备直接处理,并直接将打印结果反馈到客户端,包括状态和错误消息。因此我们可以通过该方法来直接访问打印机控制语言的结果!
SMB/TCP/445
SMB(服务器信息块)是应用层网络协议,通常在Windows上使用。该协议监听TCP 445端口,经常用于网络中的共享文件和打印机。
打印机控制语言
SNMP/UDP/161
SNMP-“简单网络管理协议”,该协议监听UDP 161端口,用于管理网络组件。
PJL
PJL是“Printer Job Language”的简称,该控制语言可用于操纵常规设置,也可以永久更改。在许多控制语言中,供应商往往只支持PJL控制语言中的部分命令,并根据打印机的需要自行添加专有的功能。
页面描述语言 - PDL
PostScript - PS
众所周知,该页面描述语言由Adobe发明,并被广泛用于PDL。PS的能力远不止于定义文档的外观和处理矢量图形。
PCL
PCL是各种供应商和设备都支持的极简页面描述语言,该页面描述语言不直接访问底层文件系统。
零配置网络
我觉得有必要介绍一个新概念。
零配置网络 (Zero-configuration networking),也就是不需要手动干预或特殊配置,就可以使用相关的网络服务。
我们在设置打印机共享时,需要在协议和软件等方面考虑到对零配置网络的支持,让客户端可以简单而直接地使用该打印机。
准备工作
我们将在OpenWRT上设置打印机并通过网络共享,在此之前我们需要做一些准备工作。
macOS共享打印机
首先将打印机连接到macOS上,通过‘HP Easy Start.app’安装好驱动和‘HP Easy Scan’,测试好打印与扫描功能。然后在网络上共享此打印机。
在OpenWRT上运行以下命令获取打印机设置参数等信息,后面将用到。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| ubus call umdns update
ubus call umdns browse
...
"_ipp._tcp": {
"HP DeskJet 2300 series @ MacMini": {
"txt": "txtvers=1",
"txt": "qtotal=1",
"txt": "rp=printers/HP_DeskJet_2300_series",
"txt": "ty=DeskJet 2300 series",
"txt": "adminurl=https://MacMini.local.:631/printers/HP_DeskJet_2300_series",
"txt": "note=MacMini",
"txt": "priority=0",
"txt": "product=(HP Deskjet 2300 series)",
"txt": "pdl=application/octet-stream,application/pdf,application/postscript,image/jpeg,image/png,image/pwg-raster",
"txt": "UUID=013924c6-107f-3d35-76ac-899ec841334f",
"txt": "TLS=1.2",
"txt": "Color=T",
"txt": "Scan=T",
"txt": "printer-state=3",
"txt": "printer-type=0x480900E",
"port": 631
}
},
"_ipps._tcp": {
"HP DeskJet 2300 series @ MacMini": {
"txt": "txtvers=1",
"txt": "qtotal=1",
"txt": "rp=printers/HP_DeskJet_2300_series",
"txt": "ty=DeskJet 2300 series",
"txt": "adminurl=https://MacMini.local.:631/printers/HP_DeskJet_2300_series",
"txt": "note=MacMini",
"txt": "priority=0",
"txt": "product=(HP Deskjet 2300 series)",
"txt": "pdl=application/octet-stream,application/pdf,application/postscript,image/jpeg,image/png,image/pwg-raster",
"txt": "UUID=013924c6-107f-3d35-76ac-899ec841334f",
"txt": "TLS=1.2",
"txt": "Color=T",
"txt": "Scan=T",
"txt": "printer-state=3",
"txt": "printer-type=0x480900E",
"port": 631
}
},
...
|
由此可看出,macOS通过IPP协议共享此打印机,端口为TCP/631。测试发现在Windows下,也可以直接发现该打印机,无需繁琐的设置。我们在OpenWRT下共享打印的目标也是如此。
Windows共享打印机
打开 控制面板 - 硬件和声音 - 查看设备和打印机 - 右键选中的打印机 - 打印机属性 - 共享
使用umdns和avahi均无法发现此打印机,这完全不符合我们的需求。忽略Windows打印机共享吧,我们就参照macOS设置来共享网络打印机。
OpenWRT 连接打印机
现在我们可以把打印机连接到OpenWRT了,如果你的OpenWRT使用的是物理机,直接把打印机连接到USB接口即可。如果你使用的是ESXi虚拟机,还需要做好USB设备直通。
把打印机连接到ESXi主机,然后ssh进入ESXi主机
1
2
3
4
5
6
7
8
| # 查看USB设备,确认打印机已经连接
lsusb
# 查看usbarbitrator的状态
chkconfig usbarbitrator --list
# 启动usbarbitrator服务
/etc/init.d/usbarbitrator start
|
直通USB打印机给OpenWRT虚拟机,ESXi - 虚拟机 - OpenWRT - 编辑 - 添加其他设备 - USB设备
打印机共享
p910nd是OpenWRT默认的打印机管理服务,使用Jetdirect/AppSocket - TCP/9100协议。
安装p910nd
1
| opkg install luci-app-p910nd-zh-cn kmod-usb-printer
|
刷新luci,点击 服务 - ‘p910nd - Printer Server’,接下来就可以配置打印机了。
==> 警告:首次使用p910nd,不要使用luci配置界面,生成的配置文件有乱码。或者,自己手动修改乱码部分。
配置 - part1
连接USB打印机
1
2
3
4
5
6
| # 查看打印机是否正常接入
dmesg | grep "USB.*printer"
[ 412.684910] usblp 1-1:1.1: usblp0: USB Bidirectional printer dev 2 if 1 alt 0 proto 2 vid 0x03F0 pid 0x3654
# 查看打印机路径,一般都是/dev/usb/lp0
ls /dev/usb/lp*
|
配置p910nd
- 勾选
- 设置一栏填写刚刚找到的打印机路径,一般都是/dev/usb/lp0
- 接口这里不用管,设置了也是乱码,等会直接编译配置文件
- 默认9100,也可以使用9101等
- 双向模式
保存并应用,然后手动修改配置文件
1
2
3
4
5
6
7
8
9
10
11
12
| vim /etc/config/p910nd
config p910nd
option enabled '1'
option device '/dev/usb/lp0'
option bind '10.10.10.1'
option port '0'
option runas_root '0'
option bidirectional '1'
# 重载p910nd
/etc/init.d/p910nd reload
|
接下来,我们在macOS或Windows中就可以通过IP地址添加当前打印机了,然后打印测试页,确认打印机已经工作正常。
配置 - part2 - mDNS
虽然已经可以通过IP添加打印机,但是这样很不方便,每台机器都需要手动添加IP地址和协议等,对专业人士来说没什么,但对一般用户来说,这还是有些困难的。设置不当的话,打印机还不能正常工作。
p910nd支持mDNS,之前我们做准备工作时获取到的打印机信息这里就要用上了,但p910nd支持的参数比较少,多余的全添加到’mdns_mdl’里面吧。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| vim /etc/config/p910nd
config p910nd
option enabled '1'
option device '/dev/usb/lp0'
option bind '10.10.10.1'
option port '0'
option bidirectional '1'
option runas_root '0'
option mdns '1'
# Human-readable location
option mdns_note 'iHome'
# Human-readable printer make and model
option mdns_ty 'DeskJet 2300 series'
# Post-Script product string, including parenthesis
option mdns_product '(HP Deskjet 2300 series)'
# IEEE-1284 Device ID MANUFACTURER/MFG string
option mdns_mfg ''
# IEEE-1284 Device ID MODEL/MDL string
option mdns_mdl 'HP DeskJet 2332,txtvers=1,qtotal=1,priority=0,Color=T,Scan=T,printer-type=0x480900E,pdl=application/octet-stream,application/pdf,application/postscript,image/jpeg,image/png,image/pwg-raster'
# IEEE-1284 Device ID COMMAND SET/CMD string
option mdns_cmd ''
|
这里,我们还需要手动修复一下p910nd打印机名称显示问题
重启umdns和p910nd服务
1
2
| /etc/init.d/p910nd restart
/etc/init.d/umdns restart
|
现在我们不需要任何配置就可以直接看到此网络打印机了,无须设置,直接点击添加打印机就可以使用了。
如果你的p910nd配置更改过多次,可能还需要清除本地mDNS缓存,不然会出现多个打印机,把人搞糊涂。
1
2
3
4
5
| # macOS
sudo killall -HUP mDNSResponder
# OpenWRT
/etc/init.d/umdns restart
|
扫描仪共享
关于sane
在给OpenWRT安装sane之前,我们需要了解一下sane的工作方式,及其与p910nd之间的关系。首先sane和其他服务差不多,加载usb相关驱动,然后为客户端提供服务。但这里有一点需要特别注意的是,sane和p910nd操作的是同一台usb打印机,所以当sane启动时打印机是无法工作的。通过查看/usr/sbin/saned
我们会发现,真正的/usr/lib/sane/saned
在工作完成后需要恢复打印机的驱动。
所以我们不但要安装saned,同时也需要xinetd来管理sane服务。当有网络连接时启动saned,此时打印机功能失效,等待扫描仪工作结束,saned自动退出,再恢复打印机功能。
如果设置不当,在使用扫描仪之后打印机将失效。 所以,这里提供一条恢复打印机的命令,调试时可以用到。
1
2
3
4
5
6
7
| rmmod usblp && modprobe usblp
# 确认打印机是否已经恢复,一旦发现问题,立即使用以上命令恢复打印机
ls /dev/usb/lp0
# 查看saned是否在后台,如果在后台,打印机功能失效
ps aux | grep saned
|
安装sane
除了‘sane-daemon’外,这里还需要使用xinet来管理sane服务,当有软件网络连接时,启动sane服务。
1
| opkg install sane-daemon sane-frontends xinetd
|
安装扫描仪驱动
OpenWRT提供的扫描仪驱动较多,这里必不需要安装整个‘sane-backends-all’包,选择自己的扫描仪驱动即可。
1
2
3
4
5
6
7
8
9
10
11
12
| # 查找所有扫描仪驱动
opkg list sane-*
opkg list *-sane
# OpenWRT中sane驱动可能有两种命名格式,都看一下
# HP DeskJet 2300 series
opkg install hplip-sane
# 测试驱动是否正确
scanimage -L
device `hpaio:/usb/DeskJet_2300_series?serial=CN291420M6' is a Hewlett-Packard DeskJet_2300_series all-in-one
|
测试扫描仪
设置Access List - 扫描仪白名单
1
| echo "10.10.10.0/24" >> /etc/sane.d/saned.conf
|
手动模式启动saned
1
| saned -l -e -b 10.10.10.1 -p 6566 -u root -d 5 -o
|
注意: 一定要以root用户运行,否则saned无法访问驱动。好吧,这本是一个用户权限问题,直接用root用户解决。
1
2
| Wed May 10 11:02:49 2023 daemon.err saned[21441]: io/hpmud/musb.c 595: invalid usb_open: Permission denied
Wed May 10 11:02:49 2023 daemon.err saned[21441]: io/hpmud/musb.c 1151: unable to open hp:/usb/DeskJet_2300_series?serial=CN291420M6
|
使用Windows/SANEWin或其他客户端软件连接测试扫描仪
** 扫描结束后,以上窗口会自动关闭,但主窗口还在,与saned的连接也还在,一定要手动关闭主窗口,否则saned不会退出。**
==> 默认设置的DPI扫描效果很差,建议设置到300或更高。
好了,到此扫描仪已经算是正常工作了,接下来我们只需要配置好xinetd。
配置saned服务
1
2
3
4
5
6
7
8
9
10
11
12
| vim /etc/xinetd.d/sane-port
service sane-port
{
disable = no
socket_type = stream
port = 6566
wait = no
user = root
group = scanner
server = /usr/sbin/saned
}
|
关于Windows
快到结尾了,如果你按照我的操作执行,你会发现macOS已经可以正常发现和使用打印机,但Windows却不可以。
打开设备和打印机,你会发现一堆乱七八糟的设备,唯独却没有我们的打印机。但通过IP地址却能够添加和使用OpenWRT共享的打印机。这说明Windows是支持p910nd的网络共享协议,只是不支持mDNS的网络发现协议。
那这样就好办了。
- 方法一:打开Windows的mDNS。打开管理员的Power Shell或CMD,运行以下代码并重启
1
| REG ADD "HKLM\Software\Policies\Microsoft\Windows NT\DNSClient" /V "EnableMulticast" /D "1" /T REG_DWORD /F
|
此方法只适用于Windows 10较新的版本,似乎其mDNS服务有些小问题。
- 方法二,禁用Windows自带mDNS,再安装Bonjour。这里就不详述了。
好吧,对于Windows来说,似乎没有做到零配置啊。有点小遗憾,但好在用Windows的人比较多,随便问一下就知道怎么添加打印机了。
结束语
接近结束时,我偶然又发现一个新物种VirtualHere,将USB设备通过网络共享,就好像它们在本地使用一样。我原来把打印机连接在服务器上主要就是因为其放在桌上占地方,如果能够远程连接USB设备,那直接使用HP的驱动和软件不是更好?
下次再试试VirtualHere吧。
参考