为何pylsp无响应?已启动TCP服务但请求无返回
问题描述
通过命令pylsp --verbose --tcp --host 127.0.0.1 --port 9999启动pylsp服务后,使用以下Python代码连接并发送initialize请求,但未收到任何响应:
import json import socket def send_request(request): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.connect(('127.0.0.1', 9999)) # 假设LSP服务运行在本地9999端口 request_str = json.dumps(request) # 发送请求长度,随后发送请求本身 sock.sendall((len(request_str).to_bytes(4, byteorder='little')) + request_str.encode('utf-8')) # 读取响应长度(前4字节),然后读取响应 response_length = int.from_bytes(sock.recv(4), byteorder='little') reponse = sock.recv(response_length).decode('utf-8') response = json.loads(reponse) return response # 初始化LSP会话 initialize_request = { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "processId": 12345, # 任意进程ID "rootPath": "/path/to/my/repo", "capabilities": {}, # 为简化,发送空能力集 } } response = send_request(definition_request) print("Definition:", response)
通过netstat确认端口状态为LISTEN:
tcp4 0 0 127.0.0.1.9999 *.* LISTEN
尝试用telnet发送相同请求,依然无响应:
telnet 127.0.0.1 9999 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "processId": 12345, "rootPath": "/path/to/my/repo", "capabilities": {} } }
请问遗漏了什么?
问题排查与解决
你遗漏了以下几个关键细节:
1. Python代码中的变量名错误
代码最后调用send_request(definition_request),但你定义的请求变量是initialize_request,这里存在笔误。这个错误会直接导致代码抛出NameError,根本没发送出正确的请求。
2. LSP TCP传输格式不符合规范
LSP(语言服务器协议)的TCP传输要求使用HTTP风格的Content-Length头部来标记消息边界,而不是直接发送二进制的长度前缀。你当前的代码直接发送4字节小端长度,这不符合LSP规范,pylsp无法识别这种格式,因此不会处理你的请求。
正确的LSP消息格式是:
Content-Length: <消息字节长度>\r\n \r\n <JSON格式的请求内容>
修正后的Python发送函数应该是这样:
def send_request(request): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.connect(('127.0.0.1', 9999)) request_str = json.dumps(request) # 构建符合LSP规范的消息头部 header = f"Content-Length: {len(request_str)}\r\n\r\n" # 发送头部+请求内容 sock.sendall(header.encode('utf-8') + request_str.encode('utf-8')) # 读取响应,先解析Content-Length response_header = b"" while b"\r\n\r\n" not in response_header: response_header += sock.recv(1) # 提取Content-Length的值 length_line = [line for line in response_header.decode('utf-8').split('\r\n') if line.startswith('Content-Length')][0] response_length = int(length_line.split(': ')[1]) # 读取响应内容 response_body = sock.recv(response_length).decode('utf-8') response = json.loads(response_body) return response
同时要修正变量名错误:
response = send_request(initialize_request) print("Initialize Response:", response)
3. Telnet请求未遵循LSP格式
你用telnet发送请求时,只输入了JSON内容,但没有添加Content-Length头部,服务器无法确定消息何时结束,会一直等待完整的请求。正确的telnet发送方式应该是先输入头部,再空两行,然后输入JSON:
telnet 127.0.0.1 9999 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Content-Length: 178 { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "processId": 12345, "rootPath": "/path/to/my/repo", "capabilities": {} } }
(注意:Content-Length的值要和你发送的JSON的字节长度一致,上面的178是示例值,需要根据实际JSON内容计算)
内容的提问来源于stack exchange,提问作者Exploring
相关产品推荐
相关产品推荐

