PHP客户端连接Jupyter Server ZMQ无响应问题求助
无法通过PHP ZMQ脚本与Jupyter Server建立连接并获取响应
我尝试用PHP脚本发送ZMQ消息与Jupyter Server通信,但连接无法正常建立,也无法获取响应。
我的Jupyter Notebook配置文件~/.jupyter/jupyter_notebook_config.py内容如下:
c.NotebookApp.ip = '127.0.0.1' c.NotebookApp.port = 9992 c.Session.key = b'00f2400c-bea977d0c80f0' c.ConnectionFileMixin.shell_port = 37971 c.ConnectionFileMixin.iopub_port = 36612 c.ConnectionFileMixin.control_port = 51091 c.ConnectionFileMixin.hb_port = 55613 c.NotebookApp.token = '12345' c.ConnectionFileMixin.ip = '0.0.0.0' c.KernelManager.autorestart = True
用于连接的PHP脚本:
<?php // Load the ZMQ extension $context = new ZMQContext(); // Create a new socket of type Request (REQ) $socket = $context->getSocket(ZMQ::SOCKET_REQ); // Connect to the server $socket->connect("tcp://127.0.0.1:55613"); for ($request = 0; $request < 10; $request++) { echo "Sending request $request...\n"; // Command to send. $socket->send("Heartbeat"); // Get the reply. $reply = $socket->recv(); echo "Received reply $request: [$reply]\n"; }
启动Notebook后运行该PHP脚本,服务器无任何响应返回,脚本仅输出Sending request 0...,之后一直卡在等待回复的状态。
问题分析与解决方案
1. 核心错误:连接了错误的端口
你当前连接的55613是Jupyter的心跳端口(hb_port),这个端口仅用于Jupyter内核与服务器之间的存活检测,不处理外部REQ-REP请求,也不会返回任何响应,这是脚本卡住的直接原因。
2. 选择正确的通信端口
要与Jupyter内核进行有效通信,应该连接shell_port(37971)或control_port(51091):
- shell_port:用于执行代码、查询内核状态等常规交互操作
- control_port:用于发送控制类命令(如中断内核、重启内核)
3. 遵循Jupyter ZMQ通信协议
即使连接了正确的端口,直接发送"Heartbeat"字符串也无法被Jupyter识别——Jupyter的ZMQ通信遵循Jupyter Messaging Protocol,所有消息必须是符合规范的JSON结构,且需要通过配置的Session.key进行加密签名。
简化测试脚本(跳过签名,验证连接)
如果只是想验证ZMQ连接是否正常,可以先临时关闭消息签名:
- 修改
jupyter_notebook_config.py,注释掉c.Session.key配置项 - 重启Jupyter Notebook
使用以下脚本连接shell_port,发送内核信息查询命令:
<?php $context = new ZMQContext(); $socket = $context->getSocket(ZMQ::SOCKET_REQ); // 连接shell端口 $socket->connect("tcp://127.0.0.1:37971"); // 构造符合Jupyter协议的消息结构 $msg = [ 'header' => [ 'msg_id' => uniqid(), 'username' => 'php-client', 'session' => uniqid(), 'msg_type' => 'kernel_info_request', 'version' => '5.3' ], 'parent_header' => [], 'metadata' => [], 'content' => [] ]; // Jupyter消息需要分帧发送:签名、分隔符、各字段JSON $socket->sendMulti([ '', // 无签名时传空字符串 '<IDS|MSG>', json_encode($msg['header']), json_encode($msg['parent_header']), json_encode($msg['metadata']), json_encode($msg['content']) ]); // 接收多帧响应并解析内容 $responseFrames = $socket->recvMulti(); $content = json_decode($responseFrames[5], true); print_r($content);
其他注意事项
- 确保PHP的ZMQ扩展版本与Jupyter使用的ZMQ版本兼容
- 检查本地防火墙/端口占用情况,确保目标端口可正常访问
- 如果需要完整加密通信,需实现Jupyter的HMAC签名逻辑,用配置的
Session.key对消息内容进行签名
内容的提问来源于stack exchange,提问作者techwoman
相关产品推荐
相关产品推荐

