为什么我没有收到FCGI_END_REQUEST记录?

3

我目前遇到了终止FastCGI请求的问题。当前我拥有的代码如下:

use std::os::unix::net::{UnixStream};
use std::io::{Read, Write};
use std::str;

fn main() {
    const FCGI_VERSION_1: u8    = 1;

    const FCGI_BEGIN_REQUEST:u8 = 1;
    const FCGI_END_REQUEST: u8  = 3;
    const FCGI_STDIN: u8        = 5;
    const FCGI_STDOUT: u8       = 6;
    const FCGI_STDERR: u8       = 7;

    const FCGI_RESPONDER: u16  = 1;

    const FCGI_PARAMS: u8 = 4;

    let socket_path = "/run/php-fpm/php-fpm.sock";

    let mut socket = match UnixStream::connect(socket_path) {
        Ok(sock) => sock,
        Err(e) => {
            println!("Couldn't connect: {e:?}");
            return
        }
    };

    let requestId: u16 = 1;

    let role: u16 = FCGI_RESPONDER;

    let beginRequest = vec![
       // FCGI_Header
       FCGI_VERSION_1, FCGI_BEGIN_REQUEST,
       (requestId >> 8) as u8, (requestId & 0xFF) as u8,
       0x00, 0x08, // This is the size of `FCGI_BeginRequestBody`
       0, 0,
       // FCGI_BeginRequestBody
       (role >> 8) as u8, (role & 0xFF) as u8,
       0, // Flags
       0, 0, 0, 0, 0, // Reserved
    ];

    socket.write_all(&beginRequest).unwrap();

    // write the FCGI_PARAMS

    let param1_name = "SCRIPT_FILENAME".as_bytes();
    let param1_value = "/var/www/public/index.php".as_bytes();
    let lengths1 = [ param1_name.len() as u8, param1_value.len() as u8 ];
    let params1_len: u16 = (param1_name.len() + param1_value.len() + lengths1.len()) as u16;

    let param2_name = b"REQUEST_METHOD";
    let param2_value = b"GET";
    let lengths2 = [ param2_name.len() as u8, param2_value.len() as u8 ];
    let params2_len: u16 = (param2_name.len() + param2_value.len() + lengths2.len()) as u16;

    let params_len = params1_len + params2_len;
    let paramsRequest = vec![
       FCGI_VERSION_1, FCGI_PARAMS,
       (requestId >> 8) as u8, (requestId & 0xFF) as u8,
       (params_len >> 8) as u8, (params_len & 0xFF) as u8,
       0, 0,
    ];
    socket.write_all (&paramsRequest).unwrap();
    socket.write_all (&lengths1).unwrap();
    socket.write_all (param1_name).unwrap();
    socket.write_all (param1_value).unwrap();
    socket.write_all (&lengths2).unwrap();
    socket.write_all (param2_name).unwrap();
    socket.write_all (param2_value).unwrap();

    // get the response
    let requestHeader = vec![
       FCGI_VERSION_1, FCGI_STDIN,
       (requestId >> 8) as u8, (requestId & 0xFF) as u8,
       0, 0,
       0, 0,
    ];

    socket.write_all(&requestHeader).unwrap();

    // read the response
    let mut responseHeader = [0u8; 8];
    socket.read_exact (&mut responseHeader).unwrap();


    // read the padding
    let mut pad = vec![0; responseHeader[7] as usize];

    socket.read_exact (&mut pad).unwrap();

    // read the body
    let responseLength = ((responseHeader[4] as usize) << 8) | (responseHeader[5] as usize);

    let mut responseBody = Vec::new();

    responseBody.resize (responseLength, 0);

    socket.read_exact (&mut responseBody).unwrap();

    println!("Output: {:?}", std::str::from_utf8(&responseBody));
}

我的代码(简而言之)是使用php-fpm服务向.php文件发出FastCGI请求。这段代码运行良好(到一定程度...),实际上我得到了预期的输出,如下所示:

Ok("X-Powered-By: PHP/8.1.11\r\nContent-type: text/html; charset=UTF-8\r\n\r\nFirst file")

顺便说一下,我的php文件只有以下内容:
<?php

echo "First file";

?>

到目前为止,一切都很好。但现在我想要做的是接收记录FCGI_END_REQUEST。为此,根据之前问题的答案(由我提出,像这样),我需要制作一个循环并读取FCGI_STDIN的所有内容,直到我收到记录FCGI_END_REQUEST。如果我理解有误,请告诉我,我认为应该这么做:

let mut output: String = String::new();

loop {
    // get the response
    let requestHeader = vec![
    FCGI_VERSION_1, FCGI_STDOUT,
    (requestId >> 8) as u8, (requestId & 0xFF) as u8,
    0, 0,
    0, 0,
    ];

    socket.write_all(&requestHeader).unwrap();

    // read the response
    let mut responseHeader = [0u8; 8];
    socket.read_exact (&mut responseHeader).unwrap();

    if responseHeader[1] != FCGI_STDOUT && responseHeader[1] != FCGI_STDERR{
        if responseHeader[1] == FCGI_END_REQUEST {
            println!("FCGI_END_REQUEST");
            break;
        } else {
            println!("NOT FCGI_END_REQUEST");
            break;
        }
    }

    // read the padding
    let mut pad = vec![0; responseHeader[7] as usize];

    socket.read_exact (&mut pad).unwrap();

    // read the body
    let responseLength = ((responseHeader[4] as usize) << 8) | (responseHeader[5] as usize);

    let mut responseBody = Vec::new();

    responseBody.resize (responseLength, 0);

    let format = format!("{}", String::from_utf8_lossy(&responseBody));

    output.push_str(format.as_str());
}


println!("Output: {:?}", output);

这段代码替换了我之前展示的从“获取响应”注释到文件结尾的所有第一段代码。我的做法是循环读取FCGI_STDIN,当遇到除FCGI_STDOUTFCGI_STDERR之外的记录时,如果找到FCGI_END_REQUEST类型的记录,则打印。现在这就是我的完整代码:
use std::os::unix::net::{UnixStream};
use std::io::{Read, Write};
use std::str;

fn main() {
    const FCGI_VERSION_1: u8    = 1;

    const FCGI_BEGIN_REQUEST:u8 = 1;
    const FCGI_END_REQUEST: u8  = 3;
    const FCGI_STDIN: u8        = 5;
    const FCGI_STDOUT: u8       = 6;
    const FCGI_STDERR: u8       = 7;

    const FCGI_RESPONDER: u16  = 1;

    const FCGI_PARAMS: u8 = 4;

    let socket_path = "/run/php-fpm/php-fpm.sock";

    let mut socket = match UnixStream::connect(socket_path) {
        Ok(sock) => sock,
        Err(e) => {
            println!("Couldn't connect: {e:?}");
            return
        }
    };

    let requestId: u16 = 1;

    let role: u16 = FCGI_RESPONDER;

    let beginRequest = vec![
       // FCGI_Header
       FCGI_VERSION_1, FCGI_BEGIN_REQUEST,
       (requestId >> 8) as u8, (requestId & 0xFF) as u8,
       0x00, 0x08, // This is the size of `FCGI_BeginRequestBody`
       0, 0,
       // FCGI_BeginRequestBody
       (role >> 8) as u8, (role & 0xFF) as u8,
       0, // Flags
       0, 0, 0, 0, 0, // Reserved
    ];

    socket.write_all(&beginRequest).unwrap();

    // write the FCGI_PARAMS

    let param1_name = "SCRIPT_FILENAME".as_bytes();
    let param1_value = "/var/www/public/index.php".as_bytes();
    let lengths1 = [ param1_name.len() as u8, param1_value.len() as u8 ];
    let params1_len: u16 = (param1_name.len() + param1_value.len() + lengths1.len()) as u16;

    let param2_name = b"REQUEST_METHOD";
    let param2_value = b"GET";
    let lengths2 = [ param2_name.len() as u8, param2_value.len() as u8 ];
    let params2_len: u16 = (param2_name.len() + param2_value.len() + lengths2.len()) as u16;

    let params_len = params1_len + params2_len;
    let paramsRequest = vec![
       FCGI_VERSION_1, FCGI_PARAMS,
       (requestId >> 8) as u8, (requestId & 0xFF) as u8,
       (params_len >> 8) as u8, (params_len & 0xFF) as u8,
       0, 0,
    ];

    socket.write_all (&paramsRequest).unwrap();
    socket.write_all (&lengths1).unwrap();
    socket.write_all (param1_name).unwrap();
    socket.write_all (param1_value).unwrap();
    socket.write_all (&lengths2).unwrap();
    socket.write_all (param2_name).unwrap();
    socket.write_all (param2_value).unwrap();

    let mut output: String = String::new();

    loop {
        // get the response
        let requestHeader = vec![
        FCGI_VERSION_1, FCGI_STDOUT,
        (requestId >> 8) as u8, (requestId & 0xFF) as u8,
        0, 0,
        0, 0,
        ];
    
        socket.write_all(&requestHeader).unwrap();
    
        // read the response
        let mut responseHeader = [0u8; 8];
        socket.read_exact (&mut responseHeader).unwrap();
    
        if responseHeader[1] != FCGI_STDOUT && responseHeader[1] != FCGI_STDERR{
            if responseHeader[1] == FCGI_END_REQUEST {
                println!("FCGI_END_REQUEST");
                break;
            } else {
                println!("NOT FCGI_END_REQUEST: {}", responseHeader[1]);
                break;
            }
        }
    
        // read the padding
        let mut pad = vec![0; responseHeader[7] as usize];
    
        socket.read_exact (&mut pad).unwrap();
    
        // read the body
        let responseLength = ((responseHeader[4] as usize) << 8) | (responseHeader[5] as usize);
    
        let mut responseBody = Vec::new();
    
        responseBody.resize (responseLength, 0);
    
        let format = format!("{}", String::from_utf8_lossy(&responseBody));
    
        output.push_str(format.as_str());
    }
    
    
    println!("Output: {:?}", output);
}

问题在于这个程序的输出结果是这样的:

NOT FCGI_END_REQUEST Output: "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0

那么我做错了什么?我的代码有什么问题吗?
我按照评论中的指示执行了操作,打印了responseHeader[1]的值。因此将println!("NOT FCGI_END_REQUEST");改为println!("NOT FCGI_END_REQUEST: {}", responseHeader[1]);。然后我得到了以下输出:

不是 FCGI_END_REQUEST:45 输出: "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"


根据我从聊天中了解到的内容,我打算在每个 socket.read_exact (&mut responseHeader) 后添加一个 println!("{:?}", foo);。这样我的循环会是这样的:

loop {
    // get the response
    let requestHeader = vec![
    FCGI_VERSION_1, FCGI_STDOUT,
    (requestId >> 8) as u8, (requestId & 0xFF) as u8,
    0, 0,
    0, 0,
    ];

    socket.write_all(&requestHeader).unwrap();

    // read the response
    let mut responseHeader = [0u8; 8];
    socket.read_exact (&mut responseHeader).unwrap();

    // "debug"
    println!("{:?}", responseHeader);

    if responseHeader[1] != FCGI_STDOUT && responseHeader[1] != FCGI_STDERR{
        if responseHeader[1] == FCGI_END_REQUEST {
            println!("FCGI_END_REQUEST");
            break;
        } else {
            println!("NOT FCGI_END_REQUEST: {}", responseHeader[1]);
            break;
        }
    }

    // read the padding
    let mut pad = vec![0; responseHeader[6] as usize];

    socket.read_exact (&mut pad).unwrap();

    // "debug";
    println!("{:?}", pad);

    // read the body
    let responseLength = ((responseHeader[4] as usize) << 8) | (responseHeader[5] as usize);

    let mut responseBody = Vec::new();

    responseBody.resize (responseLength, 0);

    let format = format!("{}", String::from_utf8_lossy(&responseBody));

    output.push_str(format.as_str());
}

使用那段代码,我得到了这个输出:

[1, 6, 0, 1, 0, 78, 2, 0]
[88, 45]
[80, 111, 119, 101, 114, 101, 100, 45]
NOT FCGI_END_REQUEST: 111
Output: "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"

根据聊天记录,我了解到我的代码存在其他问题,但我还没有完全理解它们的含义以及如何进行更正。


你无法读取 FCGI_STDIN,只能向其写入内容(这也是你在此处所做的),但实际上你并不需要这样做。为了理解发生了什么,你需要打印从 FCGI 服务器接收到的消息类型(即 responseHeader[1]),因为显然它不是你预期的任何一种类型... - Jmb
@Jmb,您所说的“您无法读取FCGI_STDIN,只能向其写入”,是指输出应从另一种记录类型中读取吗? - DFG
FCGI_STDIN 是一个消息,用于在有数据要写入时发送。输出应从接收到的 FCGI_STDOUT(或 FCGI_STDERR)消息中读取。 - Jmb
你知道这个吗? - Olivier
@Olivier 我已经看过这个库了。但是由于现有的库没有我需要的功能,所以我想自己写一个。 - DFG
显示剩余6条评论
2个回答

2

我已经找到了获取FCGI_END_REQUEST的方法(或者我认为是这样)。我使用了Jmb的部分答案和他在聊天中说的一些内容。我首先只写了一次FCGI_STDOUT,并在执行loop之前完成。然后我创建了responseHeader变量并读取数据。然后,感谢Jmb的答案,我在读取响应体后读取填充,并读取responseHeader[6]而不是之前的responseHeader[7]。所以我的代码看起来像这样:

use std::os::unix::net::{UnixStream};
use std::io::{Read, Write};
use std::str;

fn main() {
    const FCGI_VERSION_1: u8    = 1;

    const FCGI_BEGIN_REQUEST:u8 = 1;
    const FCGI_END_REQUEST: u8  = 3;
    const FCGI_STDIN: u8        = 5;
    const FCGI_STDOUT: u8       = 6;
    const FCGI_STDERR: u8       = 7;

    const FCGI_RESPONDER: u16  = 1;

    const FCGI_PARAMS: u8 = 4;

    let socket_path = "/run/php-fpm/php-fpm.sock";

    let mut socket = match UnixStream::connect(socket_path) {
        Ok(sock) => sock,
        Err(e) => {
            println!("Couldn't connect: {e:?}");
            return
        }
    };

    let requestId: u16 = 1;

    let role: u16 = FCGI_RESPONDER;

    let beginRequest = vec![
       // FCGI_Header
       FCGI_VERSION_1, FCGI_BEGIN_REQUEST,
       (requestId >> 8) as u8, (requestId & 0xFF) as u8,
       0x00, 0x08, // This is the size of `FCGI_BeginRequestBody`
       0, 0,
       // FCGI_BeginRequestBody
       (role >> 8) as u8, (role & 0xFF) as u8,
       0, // Flags
       0, 0, 0, 0, 0, // Reserved
    ];

    socket.write_all(&beginRequest).unwrap();

    // write the FCGI_PARAMS

    let param1_name = "SCRIPT_FILENAME".as_bytes();
    let param1_value = "/home/davebook-arch/projects/so/index.php".as_bytes();
    let lengths1 = [ param1_name.len() as u8, param1_value.len() as u8 ];
    let params1_len: u16 = (param1_name.len() + param1_value.len() + lengths1.len()) as u16;

    let param2_name = b"REQUEST_METHOD";
    let param2_value = b"GET";
    let lengths2 = [ param2_name.len() as u8, param2_value.len() as u8 ];
    let params2_len: u16 = (param2_name.len() + param2_value.len() + lengths2.len()) as u16;

    let params_len = params1_len + params2_len;
    let paramsRequest = vec![
       FCGI_VERSION_1, FCGI_PARAMS,
       (requestId >> 8) as u8, (requestId & 0xFF) as u8,
       (params_len >> 8) as u8, (params_len & 0xFF) as u8,
       0, 0,
    ];

    socket.write_all (&paramsRequest).unwrap();
    socket.write_all (&lengths1).unwrap();
    socket.write_all (param1_name).unwrap();
    socket.write_all (param1_value).unwrap();
    socket.write_all (&lengths2).unwrap();
    socket.write_all (param2_name).unwrap();
    socket.write_all (param2_value).unwrap();

    let mut stdout: String = String::new();

    // get the response
    let requestHeader = vec![
        FCGI_VERSION_1, FCGI_STDOUT,
        (requestId >> 8) as u8, (requestId & 0xFF) as u8,
        0, 0,
        0, 0,
    ];

    socket.write_all(&requestHeader).unwrap();

    loop {
        // read the response header
        let mut responseHeader = [0u8; 8];
        socket.read_exact (&mut responseHeader).unwrap();
    
        if responseHeader[1] != FCGI_STDOUT && responseHeader[1] != FCGI_STDERR{

            if responseHeader[1] == FCGI_END_REQUEST {
                println!("FCGI_END_REQUEST: {:?}", responseHeader);
                break;
            } else {
                println!("NOT FCGI_END_REQUEST: {}", responseHeader[1]);
                break;
            }
        }

        // read the body
        let responseLength = ((responseHeader[4] as usize) << 8) | (responseHeader[5] as usize);

        let mut responseBody = vec![0; responseLength];

        socket.read_exact (&mut responseBody).unwrap();

        stdout.push_str(&String::from_utf8_lossy(&responseBody));

        // read the padding
        let mut pad = vec![0; responseHeader[6] as usize];

        socket.read_exact (&mut pad).unwrap();
    }
    
    println!("Output: {:?}", stdout);
}

通过这段代码,我得到了以下输出:
FCGI_END_REQUEST: [1, 3, 0, 1, 0, 8, 0, 0]
Output: "X-Powered-By: PHP/8.1.11\r\nContent-type: text/html; charset=UTF-8\r\n\r\nFirst file"

我真的认为我正在得到FCGI_END_REQUEST记录(我非常怀疑我是在混淆输出,而不是真正的FCGI_END_REQUEST记录)

关于赏金

我真的愿意给予赏金给那些回答以下问题的人:

  • 我做错了什么(或者可以改进的事情)

  • 为什么我从FCGI_STDIN读取和从FCGI_STDOUT读取都会得到FCGI_END_REQUEST? 根据Jmb的说法,我不应该从FCGI_STDIN读取,但如果我这样做,我会得到相同的结果

基本上,我愿意为更详细的答案提供奖励。 如果奖励结束时没有更详细的答案,我将接受我的答案是正确的。


1
我并没有说你不应该从FCGI_STDIN读取,我说的是你无法从中读取。这是根本不可能的。当您发送一个FCGI_STDIN请求时,您所做的是向FCGI_STDIN写入,而不是从中读取。同样,您也不应该_发送_FCGI_STDOUT消息,当您这样做时,php-fpm(或其他任何程序)都可以将其视为错误,并在此时关闭连接。 - Jmb
@Jmb 但是如果我从 FCGI_STDIN 中读取,为什么会得到相同的输出呢? - DFG
1
你不能从 FCGI_STDIN 读取数据,这是不可能的,你做不到。你所谓的“从 FCGI_STDIN 读取”实际上是你向 FCGI_STDIN 写入 数据,然后从 FCGI_STDOUT 读取数据。为什么在从 stdout 读取之前(或之后)向 stdin 写入数据会有问题呢? - Jmb

1
您的代码存在以下几个问题:
  • 在读取循环中,您编写了多个FCGI_STDOUT消息。根据规范中的表A,您不应该编写此类消息:FCGI_STDOUT消息只应从“应用程序”(即您正在与之通信的php-fpm或其他FCGI应用程序)发送到WS(即您的程序)。
  • 这源于一种关于何时以及如何发送FCGI_STDOUT消息的误解:您无需采取任何措施请求输出,相反,“应用程序”将在有话要说时自发地发送FCGI_STDOUT消息。
  • 您按错误的顺序读取填充和内容(请参见FCGI_Record的定义:内容出现在填充之前)。实际上,您根本没有读取内容(您缺少对socket.read_exact(&mut responseBody)的调用)。

根据跟踪记录,php-fpm向您发送了一个包含78个字节数据和2个字节填充的单个FCGI_STDOUT消息。数据以88, 45, 80, 111, 119, 101, 114, 101, 100, 45开头,它转换为“X-Powered-”。但是,您跳过了前两个字节,就好像它们是填充一样,您从未读取消息正文,然后您读取了接下来的8个字节,就好像它们是新的消息头。当您尝试从这8个字节中提取类型时,您会得到一个无效值,并且您的程序会出错。

修正后的代码(未经测试):

use std::os::unix::net::{UnixStream};
use std::io::{Read, Write};
use std::str;

fn main() {
    const FCGI_VERSION_1: u8    = 1;

    const FCGI_BEGIN_REQUEST:u8 = 1;
    const FCGI_END_REQUEST: u8  = 3;
    const FCGI_STDIN: u8        = 5;
    const FCGI_STDOUT: u8       = 6;
    const FCGI_STDERR: u8       = 7;

    const FCGI_RESPONDER: u16  = 1;

    const FCGI_PARAMS: u8 = 4;

    let socket_path = "/run/php-fpm/php-fpm.sock";

    let mut socket = match UnixStream::connect(socket_path) {
        Ok(sock) => sock,
        Err(e) => {
            println!("Couldn't connect: {e:?}");
            return
        }
    };

    let requestId: u16 = 1;

    let role: u16 = FCGI_RESPONDER;

    let beginRequest = vec![
       // FCGI_Header
       FCGI_VERSION_1, FCGI_BEGIN_REQUEST,
       (requestId >> 8) as u8, (requestId & 0xFF) as u8,
       0x00, 0x08, // This is the size of `FCGI_BeginRequestBody`
       0, 0,
       // FCGI_BeginRequestBody
       (role >> 8) as u8, (role & 0xFF) as u8,
       0, // Flags
       0, 0, 0, 0, 0, // Reserved
    ];

    socket.write_all(&beginRequest).unwrap();

    // write the FCGI_PARAMS

    let param1_name = "SCRIPT_FILENAME".as_bytes();
    let param1_value = "/var/www/public/index.php".as_bytes();
    let lengths1 = [ param1_name.len() as u8, param1_value.len() as u8 ];
    let params1_len: u16 = (param1_name.len() + param1_value.len() + lengths1.len()) as u16;

    let param2_name = b"REQUEST_METHOD";
    let param2_value = b"GET";
    let lengths2 = [ param2_name.len() as u8, param2_value.len() as u8 ];
    let params2_len: u16 = (param2_name.len() + param2_value.len() + lengths2.len()) as u16;

    let params_len = params1_len + params2_len;
    let paramsRequest = vec![
       FCGI_VERSION_1, FCGI_PARAMS,
       (requestId >> 8) as u8, (requestId & 0xFF) as u8,
       (params_len >> 8) as u8, (params_len & 0xFF) as u8,
       0, 0,
    ];

    socket.write_all (&paramsRequest).unwrap();
    socket.write_all (&lengths1).unwrap();
    socket.write_all (param1_name).unwrap();
    socket.write_all (param1_value).unwrap();
    socket.write_all (&lengths2).unwrap();
    socket.write_all (param2_name).unwrap();
    socket.write_all (param2_value).unwrap();

    let mut output: String = String::new();

    // get the response
    loop {
        // read the response header
        let mut responseHeader = [0u8; 8];
        socket.read_exact (&mut responseHeader).unwrap();
    
        if responseHeader[1] != FCGI_STDOUT && responseHeader[1] != FCGI_STDERR{
            if responseHeader[1] == FCGI_END_REQUEST {
                println!("FCGI_END_REQUEST");
                break;
            } else {
                println!("NOT FCGI_END_REQUEST: {}", responseHeader[1]);
                break;
            }
        }
    
        // read the body
        let responseLength = ((responseHeader[4] as usize) << 8) | (responseHeader[5] as usize);
        let mut responseBody = vec![0; responseLength];
        socket.read_exact (&mut responseBody).unwrap();
        output.push_str(&String::from_utf8_lossy(&responseBody));

        // read the padding
        let mut pad = vec![0; responseHeader[7] as usize];
        socket.read_exact (&mut pad).unwrap();
    }
    
    println!("Output: {:?}", output);
}

嗨,我尝试了你的代码,虽然有些东西变得更清晰了,但当我运行程序时,控制台保持黑色没有任何结果,程序也永远不会结束。 - DFG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接