ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

IPP协议与CUPS实战:实现跨平台网络打印与排错

IPP协议与CUPS实战:实现跨平台网络打印与排错 简介《IPP网络打印协议》源码包是一份基于HTTP/1.1实现的标准网络打印协议参考代码主要面向打印服务开发者、系统集成工程师以及想从实际工程案例理解网络协议机制的学习者。压缩包共32个文件大小约35KB核心为8个C源文件和5个头文件配有Makefile与README用于构建和阅读另有svn-base等版本管理辅助文件整体精简、结构清晰。目前已有3847人学习/浏览说明它在协议学习与二次开发场景中具有较高参考价值。源码按协议解析、HTTP传输、连接管理、打印机状态查询与作业控制等模块展开覆盖IPP报文编码、请求/响应状态机、错误处理以及HTTPS安全接入等关键实现通过阅读和调试这套代码能直观理解从客户端提交打印作业到打印机返回状态信息的完整交互流程为自定义打印服务、客户端开发或打印系统集成提供可复用的实现框架。1. IPP一台打印机让 Windows、Linux、macOS 都能正常打出来一台打印机Windows 能打Mac 打不了Linux 用户干脆躺平这种局面在混合办公里太常见了。IPPInternet Printing Protocol互联网打印协议把打印机抽象成 HTTP 资源——一个 URL、一个端口 631就能让不同操作系统的客户端走同一套标准流程完成打印。无论是想把旧打印机变成共享资源还是调和 Windows 与 macOS 并存的办公环境IPP 都是眼下最值得试的解法。这篇拆解先从协议的请求-响应模型讲起再给出一套可照抄的 CUPS 部署、参数调优与排错流程。2. IPP 协议本身一个作业就是一组 HTTP 请求不是裸投递2.1 为什么选 IPP 而不是 LPR、SMB、RAW三个老协议的硬伤先聊 LPR。它出自 RFC 1179监听 515 端口当年设计是给几十台终端共享一台激光打印机用的。它的最大问题是没有“打印机能力协商”这个抽象A5 纸、双面、彩色这些参数在 LPR 里传不干净打印任务中途也无法查询状态更别说取消。你只能把数据推过去剩下的靠祈祷。SMB 打印共享是 Windows 域里的老牌方案日常用得最多但跨平台体验很难受。SMB 依赖 139/445 端口企业防火墙经常只放行 80/443把打印共享直接挡在外面。更麻烦的是Windows 安全更新和身份验证策略一调整共享打印机就会出各种奇怪错误近两年不少人遇到的 0x0000011b 打印连接故障就源于系统更新对 SMB 打印通道的收紧重装驱动、删注册表都只能算是补救。SMB 的另一个短板是没有统一的设备描述格式打印机型号变了客户端驱动就得跟着换。再来是 RAW 打印常说的 9100 端口直连。它可靠、简单在标签打印机、POS 小票机上依然是主流但它是纯单向通道作业有没有被接受、打印机卡没卡纸、墨粉还够不够全部没有回读信息。运维人员想远程判断打印队列状态基本无从下手。IPP 的设计思路完全不一样。它把打印行为定义为 HTTP 上的作业操作默认走 TCP 631 端口使用 POST 方法携带结构化的 IPP 请求。打印机在 IPP 里是一个 URI 资源比如ipp://192.168.1.20:631/printers/lab001这个 URI 能查询属性、能提交作业、能取消作业、还能报告状态。它既保留了 HTTP 的成熟体系——认证、加密、代理、缓存都能复用又补上了 LPR 和 RAW 缺失的反馈机制。协议默认端口作业状态回读能力协商典型痛点LPR/LPD515弱无参数无法完整传递跨厂商兼容差SMB 打印共享139/445一般依赖驱动跨平台差安全更新易引发故障RAWJetDirect9100无无无法感知打印机故障IPP631也可走 80/443完整有IPP Everywhere证书配置稍有门槛2.2 打印任务的完整生命周期四类必须熟悉的 IPP 操作IPP 把一次打印拆成多个可寻址的操作。最常见的四类是Get-Printer-Attributes、Print-Job、Get-Job-Attributes、Cancel-Job。前两个负责发现打印机并提交任务后两个负责跟踪和清理任务。理解了这个模型你在写脚本时就不会把 IPP 当成一条裸管道。典型的流程是这样客户端先向打印机的 URI 发送Get-Printer-Attributes拿到打印机当前状态、支持纸张规格、是否接受新作业等能力信息然后调用Print-Job把文档和打印选项一起交给服务端任务被接受后会返回一个作业 ID客户端用Get-Job-Attributes轮询作业状态直到状态变成completed如果中途发现参数错了可以用Cancel-Job终止。动手验证之前先装好工具集。下面用两台机器做演示打印服务器 IP 为 10.0.0.5队列名为 lab001。# Ubuntu/Debian 上安装 CUPS 客户端工具集 sudo apt update sudo apt install -y cups cups-clientcups包提供服务端cups-client提供ipptool、lp、lpstat等命令行工具。ipptool是排查协议问题时最顺手的工具后面第六部分还会重点用到。接下来用一条验证命令查看远程打印机的全部能力# ipptool 直接把二进制请求打包发出去返回人类可读结果 ipptool -tv ipp://10.0.0.5:631/printers/lab001 EOF { OPERATION Get-Printer-Attributes GROUP operation-attributes-tag ATTR charset attributes-charset utf-8 ATTR naturalLanguage attributes-natural-language en ATTR uri printer-uri $uri } EOF这里-tv表示输出更详细的文本结果$uri是ipptool自动替换的变量值就是命令行里的ipp://10.0.0.5:631/printers/lab001。能看到printer-state、printer-is-accepting-jobs、media-supported等属性说明服务端 IPP 响应正常。2.3 IPP 属性模型写代码前你要认得的属性名和值IPP 的属性区分三类打印机属性、作业模板属性、作业状态属性。打印机属性描述设备当前状态和能力比如printer-state作业模板属性描述提交作业时的选项比如纸张、双面、色彩作业状态属性描述某个具体作业的运行情况比如job-state、job-state-reasons。初学 IPP 时最容易搞混的是sides和media这类属性的取值格式。它们用固定字符串表示大小写敏感写错一个字母服务端就报client-error-attributes-or-values-not-supported。我列出实战中最常用的几个属性含义常见取值printer-state打印机整体状态3idle4processing5stoppedprinter-is-accepting-jobs是否接收新任务true/falsemedia纸张规格iso_a4_210x297mm、na_letter_8.5x11insides单双面one-sided、two-sided-long-edge、two-sided-short-edgeprint-color-mode色彩模式color、monochromejob-state作业状态3pending、4processing、6completed、7canceled、9abortedjob-state文档里的数字有九种但实际运行中只需关注 3、4、6、7、9 这几个。job-state5的 stopped 状态在作业级不常用更多是打印机整机状态。从这套属性模型可以看出IPP 天生是面向设备和软件协同设计的软件先问设备能做什么再传对应的参数而不是像 SMB 打印共享那样完全依赖客户端安装的驱动去猜设备能力。3. 把打印机变成 IPP 服务器从 CUPS 安装到多端添加3.1 安装 CUPS 并确认服务在监听 631CUPSCommon Unix Printing System是目前主流 Linux 发行版默认的打印系统它既是打印调度器又是一个原生 IPP 服务端。部署前先确认服务状态# 安装并启动 CUPS sudo apt update sudo apt install -y cups sudo systemctl enable --now cups sudo systemctl status cups --no-pagerenable --now让 CUPS 开机自启并立即运行。安装完成后用ss确认端口监听# 查看 631 端口是否已经在监听 ss -ltnp | grep 631如果看不到监听结果多半是 CUPS 没起来看systemctl status cups的日志输出。能监听到后再用浏览器打开http://127.0.0.1:631你会看到一个管理界面这是后续配置队列的辅助入口。Ubuntu 上默认cupsd.conf只监听本机回环地址局域网里其他电脑无法直接访问。要改成监听所有网卡需要调整配置或使用下面的cupsctl命令这在 3.2 里一起处理。3.2 添加打印机队列driverless 与大权添加队列时最常见的做法是用lpadmin。下面假设打印机本身支持网络打印IP 为 192.168.1.20占用标准 RAW 端口 9100# 添加名为 lab001 的打印队列 sudo lpadmin -p lab001 -E \ -v socket://192.168.1.20:9100 \ -m everywhere \ -D Lab 001 HP LaserJet -L 204 Room参数解释-p lab001指定队列名客户端连接时这个名称会出现在 URI 里-E表示添加后立即启用-v socket://192.168.1.20:9100告诉 CUPS 要把作业发给哪台设备-m everywhere是 CUPS 的通用 IPP Everywhere 驱动让 CUPS 自行完成格式转换对多数普通打印机都能工作-D和-L分别填备注和位置这些文本会体现在 IPP 的printer-info和printer-location属性里。打完这条命令后立刻验证队列是否正确生成lpstat -p lab001 -l-l打印详细信息能看到设备 URI、驱动、是否启用。接着放开网络访问# 允许其他机器访问打印队列常见做法之一 sudo cupsctl --share-printers --remote-any--share-printers让队列允许共享--remote-any放开地址限制允许任意客户端访问。如果只想允许某个网段要编辑/etc/cups/cupsd.conf在Location /printers段里写上Allow from规则这部分在第四章访问控制小节展开。3.3 Windows 7/10/11 添加 IPP 打印机Windows 端添加 IPP 打印机的路径很统一。以 Windows 10 为例设置 → 设备 → 打印机和扫描仪 → 添加打印机等到出现“我需要的打印机不在列表中”时点击它选择“使用 TCP/IP 地址或主机名添加打印机”设备类型选“IPP”地址填http://10.0.0.5:631/printers/lab001之后按提示选择或直接使用系统自带驱动。Windows 7 也支持这套流程控制面板 → 设备和打印机 → 添加打印机 → “使用 TCP/IP 地址或主机名添加打印机”在“设备类型”里直接选“Internet 打印协议”地址同样填完整 URL。注意不要在地址栏只填 IP那样 Windows 会尝试走 RAW 9100与目标端口不符。驱动部分有个常见做法现代喷墨和激光打印机大多支持 PCL6 或 PostScriptWindows 会自动提取打印机信息如果列表里没有对应型号可以选“Microsoft”分类下的“Microsoft IPP Class Driver”这也是我一般先试的项能少装一堆厂商工具。3.4 Linux 和 macOS一条命令的事Linux 客户端安装 CUPS 后同样用lpadmin添加# 在 Linux 客户端上添加远程 IPP 队列 sudo lpadmin -p lab001-remote -E \ -v ipp://10.0.0.5:631/printers/lab001 \ -m everywhere lpstat -p lab001-remote这里设备 URI 直接用ipp://协议开头不再经过 socket 中转。-m everywhere在客户端本地也适用CUPS 会按 IPP 的能力协商机制去询问服务端而不是死守一份本地驱动。macOS 用户更省事系统设置 → 打印机与扫描仪 → 添加打印机 → 点击“IP”图标协议选 IPP地址填10.0.0.5队列填printers/lab001系统会自动完成初始化。4. IPP 参数调优作业默认值、访问控制与 HTTPS 加密4.1 队列默认值纸张、双面、色彩一次配齐队列创建后把单位里最常用的作业参数设为默认值能省掉用户每次打印都要改设置的步骤。lpadmin的-o参数可以直接写作业模板属性# 设置默认 A4、双面、黑白 sudo lpadmin -p lab001 \ -o mediaiso_a4_210x297mm \ -o sidestwo-sided-long-edge -o print-color-modemonochromeiso_a4_210x297mm是 IPP 标准里的 A4 表达方式不能简写成A4否则不同版本的 CUPS 解释可能不一致。two-sided-long-edge表示沿长边翻页适合竖直装订的文档横向翻页用two-sided-short-edge。print-color-modemonochrome强制黑白可以避免有人误选彩色然后抱怨耗材消耗太快。用户单次打印时仍能覆盖默认值比如用lp -d lab001 -o sidesone-sided 简历.pdf强制单面。队列默认值只在用户不做选择时生效优先级低于作业级参数。如果要在作业提交时临时调整尺寸也可以直接写-o mediaA4但更稳的还是写标准名避免被 CUPS 的 PPD 映射到奇怪的尺寸。4.2 访问控制限制谁有权限向 631 发作业CUPS 的 IPP 接口默认是允许任意客户端提交作业的前提是队列能被访问。内网环境还好但如果打印机服务器暴露在更大的网络里最好做一层限制。修改/etc/cups/cupsd.confLocation /printers Order allow,deny Allow from 192.168.10.0/24 Allow from 127.0.0.1 Deny from all /LocationLocation /printers管的是所有打印队列的公共入口。Allow from 192.168.10.0/24只放行办公室网段其他来源一律拒绝。这里的Order allow,deny表示先执行允许规则再执行拒绝规则最终效果是仅允许明确列出的网段。改完配置后重启 CUPSsudo systemctl restart cups注意如果你前面用了sudo cupsctl --remote-any它会写入一份宽松配置到cupsd.conf手动加限制前要确认两处不冲突。我的习惯是以手写cupsd.conf为准cupsctl只用于一次性调试。除了 IP 限制还可以限制操作系统用户。CUPS 的本地用户认证与系统账号打通在Location /printers/lab001内加Require user admin就只允许系统组里的用户访问该队列。但 Windows 客户端不会默认提示输入 Linux 账号实际使用中 IP 白名单更常见用户认证更多用于管理页面。4.3 IPP over HTTPS自签名与信任链处理IPP 默认是明文传输的作业数据和认证信息都能在网络上被截获。局域网内感观不明显但打印机数据里经常夹带文档内容建议启用 IPP over HTTPS也就是用ipps://代替ipp://。CUPS 启动时会自动生成自签名证书默认路径在/etc/cups/ssl/或者由cupsd.conf指定。如果你要替换成自己的证书先生成密钥和证书文件# 生成自签名证书有效期一年 sudo openssl req -x509 -newkey rsa:2048 -nodes \ -keyout /etc/cups/ssl/lab001.key \ -out /etc/cups/ssl/lab001.crt \ -days 365 -subj /CN10.0.0.5然后在cupsd.conf里配置DefaultEncryption RequiredDefaultEncryption Required表示所有请求都强制走加密通道客户端用ipp://访问也会被服务端拒绝必须改用ipps://。这样做的代价是自签名证书不被 Windows 直接信任客户端首次连接会报证书错误。处理自签名证书的常见做法是把lab001.crt导到客户端设备在 Windows 上双击安装到“受信任的根证书颁发机构”macOS 上加入系统钥匙串并把信任级别设为始终信任。内网小团队这样够用如果面向更广用户建议给 CUPS 签一张内网 CA 签发的证书再把 CA 根证书下发给所有客户端比逐台装自签名要省事得多。5. IPP 避坑记录四个打印失败现象根因和解决办法5.1 现象 1Windows 报“无法连接”CUPS 日志里没有任何请求现象客户端添加打印机时提示无法连接服务端lpstat -p lab001显示队列正常但 CUPS 访问日志没有任何来自客户端的记录。原因最常见的是 CUPS 只监听了 127.0.0.1或者防火墙没放行 631 端口。客户端 telnet 一下就知道# 在客户端测端口连通性 telnet 10.0.0.5 631如果卡在 Connecting就是网络层没通如果能进入命令行但打印还是失败则要看 CUPS 是否监听了所有网卡。解决在服务端执行sudo cupsctl --share-printers --remote-any然后ss -ltnp | grep 631确认监听地址从127.0.0.1变成了0.0.0.0。如果还有防火墙放行 TCP 631。这一步做完绝大多数“连不上”就消失了。5.2 现象 2作业一直 processing但打印机不出纸现象任务提交成功Windows 队列显示“正在打印”服务端lpstat -p lab001也显示 processing但打印机一点反应都没有。原因设备 URI 写错了。很多人把-v socket://192.168.1.20:9100里的 IP 填成打印机管理页面的 IP而不是数据端口的 IP或者打印机休眠后响应慢CUPS 重试超时。也有部分情况是驱动类型选错文档数据格式发过去打印机不认识表现为状态 processing 但始终不送纸。解决先看lpstat -p lab001 -l输出的 Device URI和打印机厂商规格里的 IP 对比重点确认端口是 9100 还是别的。再用telnet 192.168.1.20 9100验证端口通不通。队列本身没问题的话把-m everywhere换回打印机官方 PPD重新生成队列重启 CUPS 后再测一次。通常这个组合能解决 80% 的“假打印”问题。5.3 现象 3打印出来全是乱码或一整张纸只打了几行二进制码现象作业显示 completed但纸面上全是异物字符有些打印机还会连续吐纸每张只有零散几行。原因这是典型的驱动与设备语言不匹配。打印机实际只说 PCL6CUPS 端却配了 PostScript 驱动或者反之。IPP 服务端只是按队列配置把数据转成目标格式设备收到不认识的格式就会把原始字节当文本打出来。解决先查打印机支持的语言然后重新选驱动。lpinfo -m | grep -i laserjet列出本机可用驱动lpinfo -v列出可用设备接口。用官方 PPD 重建队列是最稳妥的路径如果暂时找不到合适驱动-m everywhere配合print-color-mode这类标准参数也能把 CUPS 的通用转换能力用起来。乱码问题解决后建议直接打一张测试页验证lp -d lab001 /usr/share/cups/data/testprint5.4 现象 4IPP over HTTPS 证书不受信任客户端拒绝提交现象把协议从ipp://换成ipps://后Windows 添加时直接弹“证书不受信任”或者每次连接都要确认打印任务无法自动完成。原因自签名证书不包含在客户端根证书存储里Windows 的 IPP 客户端不认识签发者于是拒绝建立安全通道。这是 HTTPS 协议的预期行为不是 CUPS 的 bug。解决把 CUPS 证书的.crt文件复制到 Windows在“管理证书”里导入“受信任的根证书颁发机构”。macOS 则导入钥匙串并把“信任”设为“始终信任”。两个系统都完成后用ipps://地址重新添加打印机。注意证书 CN 要和访问 IP 一致否则即便装了根证书主机名校验依然会失败。IP 地址变了就重新签一张这是我踩过最硬的坑。6. 用 ipptool 和 tcpdump 做最后一步验证6.1 一次性掏出打印机所有能力每次交付新队列前我习惯先用 ipptool 把打印机能力完整拉一遍确认printer-state为 idle、printer-is-accepting-jobs为 true、media-supported里包含目标的纸张规格ipptool -tv ipp://10.0.0.5:631/printers/lab001 EOF { OPERATION Get-Printer-Attributes GROUP operation-attributes-tag ATTR charset attributes-charset utf-8 ATTR naturalLanguage attributes-natural-language en ATTR uri printer-uri $uri } EOF返回结果里重点看printer-state是否为 3。如果是 5stopped说明队列被挂起需要到打印机面板或 CUPS 管理页恢复。media-supported会列出所有纸张规格客户端出现的“没有可用纸张”问题就是这里的支持列表和驱动默认值不匹配造成的。6.2 抓包确认 IPP 请求结构如果 ipptool 都异常或者你想确认客户端到底发来了什么内容用 tcpdump 抓 631 端口sudo tcpdump -i eth0 -A -s0 tcp port 631客户端发起一次打印观察数据包里的 POST 请求行和响应状态码。IPP 协议响应状态码以000开头是成功比如000 successful-ok如果出现400打头的是client-error-bad-request说明请求体本身格式有问题多半是属性名拼写错误或类型不对。此时对照第四节表格里的标准属性名排查即可。如果打印任务已经走ipps://加密tcpdump 看不到明文内容只能看到 TLS 握手流量。这时先按 5.4 的方法把证书问题解决再回到明文 IPP 或直接信任 ipptool 的结果。从那以后我每次交付新打印队列前都强制自己走一遍同样的流程lpstat -p lab001 -l确认队列和 URIipptool拉一遍设备属性lp -d lab001提交一份真实文档最后确认 Windows 和 macOS 两台客户端各打一页。前三步都用命令行完成逻辑清晰可复现比在图形界面里反复点“下一步”要快得多。希望这份 IPP 实战拆解能帮你在部署网络打印时少走弯路。本文还有配套的精品资源点击获取
返回列表