Win32 子进程在退出之前不会刷新标准输出

问题描述 投票:0回答:1

我开始用 C 语言(在 Windows 上)为我的语言编写 vscode 的 LSP 扩展。当作为子进程生成时,我无法让极其简单的 C 程序刷新标准输出(vscode 就是这样做的)。当我直接从命令行运行相同的程序时,它按预期工作。我有一个简单的 python 脚本来模拟 lsp 协议,我在这里看到的行为与在 vscode 下运行时的行为相同。

这是我可以用来模拟错误的最简单的 C 程序。 (我有一个 C++ 程序,它与

std::cout
和朋友的行为方式相同)

#include <windows.h>
#include <stdio.h>

int main() {
    char buffer[1024];
    // Infinite loop to continuously listen for LSP requests
    // without the loop it works fine. 
    while (1) {

        if (fgets(buffer, 1024, stdin) == NULL) {
            break;
        }

        const char* contentOffset = buffer + 16; // read content value (16 is the size of "Content-Length:"

        char* pEnd;
        size_t len = strtoll(contentOffset, &pEnd, 10) + 1;

        fgets(buffer, 1024, stdin); // read empty line

        // Read the JSON body based on Content-Length
        fgets(buffer, (int32) len, stdin);

        // Process the incoming JSON body (simple echo back for testing)
        // Echo the same JSON body back with the appropriate LSP header
        printf("Content-Length: %d\r\n\r\n%s", (int32_t)len - 1, buffer); // I've also tried fprintf and the windows apis as well, same effect
        // Flush stdout to ensure the message is sent immediately (this seems to have no effect)
        fflush(stdout);
    }
    return 0;
}

这是一个简单的Python脚本来模拟lsp


import subprocess
import time

# Start the C program
process = subprocess.Popen(
    ["path/to/exe"],  
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    universal_newlines=True,  # Ensure text mode
)

# Function to send LSP request and read response
def send_lsp_request(json_request):
    content_length = len(json_request)

    # Send the LSP-style request
    lsp_message = f"Content-Length: {content_length}\r\n\r\n{json_request}"
    process.stdin.write(lsp_message)
    process.stdin.flush()

    # Allow some time for the C program to respond
    time.sleep(0.1)

    # Read and print the response from stdout
    response = process.stdout.read(1024)
    return response

# Example LSP request
json_request = '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {}}'
print('sent')
# Send a request to the C LSP server and print the response
response = send_lsp_request(json_request)
print("Response from C program:\n", response)

我希望程序在这两种情况下表现相同。相反,当使用 python 脚本运行时,它会打印

sent
,然后永远挂起,等待进程将某些内容放入
stdout
,但这种情况永远不会发生。

如果我删除 C 程序中的

while
循环,我们会得到我们期望的输出,但我实际上无法做到这一点,因为程序需要继续侦听更多消息。

我不知道为什么会发生这种情况。我读过一些关于继承句柄的内容,但我无法控制 vscode 对此的处理方式,如果 vscode 提供的 stdio 传输没有为此做正确的事情,我会感到惊讶。我没有其他硬件来判断这是否是 Windows 独有的问题。

任何见解都令人难以置信。

c winapi vscode-extensions
1个回答
0
投票

process.stdout.read(1024)
显然等待 1024 字节(或 EOF)。我找不到它的文档,但我可以演示它:

$ perl -Mv5.14 -e'say "hi"; sleep( 3 );' | cat
<3 second pause due to lack of flushing>
hi

$ perl -Mv5.14 -e'say "hi"; STDOUT->flush; sleep( 3 );' | cat
hi
<3 second pause>

$ perl -Mv5.14 -e'say "hi"; STDOUT->flush; sleep( 3 );' |
   python3 -c 'import sys; print(sys.stdin.read(10), end="");'
<3 second pause>
hi

抱歉,我不太了解 Python,无法提供解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.