如何通过 libc 设置 TcpStream 的 sockopt?

How do I setsockopt of a TcpStream via libc?

我知道 TcpStreamstream.set_read_timeout 但我需要在 libc 中为 Windows 添加它,但我的代码不起作用,我相信这是因为我无法理解将毫秒放入 _value: *const c_char 的方法。在 Rust 中我写了 let qtie = [100].as_ptr(); 但它错了。我也不知道 return 如何在 extern "C" fn.

中出现 c_int
use std::net::{TcpListener, TcpStream};
use std::io::{Read, Write};
use std::thread;
use std::time::Duration;

use libc::c_int;
use libc::c_char;

pub unsafe extern "C" fn setsockopt(
    _socket: c_int,
    _nivel: c_int,
    _nombre: c_int,
    _value: *const c_char,
    _option_len: c_int
) -> c_int {return 0;}

fn al_cliente(mut stream: TcpStream) {
    
    const SOL_SOCKET:i32  = 1; // También 0xffff
    const SO_RCVTIMEO:i32 = 20;
    const SO_SNDTIMEO:i32 = 21;
    
    const tam_buff:usize = 10;
    let mut data = [0 as u8; tam_buff];
    
    loop {
        
        println!("{:?}", stream);
        let buska = format!("{:?}", stream);
        let arrsk:Vec<&str> = buska.split(" ").collect();
        
        let socket = arrsk[7].parse::<i32>().unwrap();
        //let socket = 0;
        println!("{}", socket);
        
        let qtie = [100].as_ptr();
        
        // Ejemplo: int nTimeout = 5000; // 5 seconds
        //          setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&nTimeout, sizeof(int));
        unsafe { setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, qtie, 10); }
        
        //stream.set_read_timeout(Some(Duration::from_secs(10)));
        let ver = stream.read(&mut data).unwrap();
        
        stream.write(&data[0..tam_buff]).unwrap();
        
        let atexto = String::from_utf8_lossy(&data);
        println!("{:?}", atexto);
    }
}


fn main() {
    let listener = TcpListener::bind("0.0.0.0:3333").unwrap();
    println!("Server listening on port 3333");

    for stream in listener.incoming() {
        
        match stream {
            Ok(stream) => {
                println!("Conectado: {}", stream.peer_addr().unwrap());
                
                let _hilo = thread::spawn(move || {
                    al_cliente(stream);
                });
            }
            Err(e) => {
                println!("Error: {}", e);
            }
        }
    }
}

根据 socket manpage:

Specify the receiving or sending timeouts until reporting an error. The argument is a struct timeval.

幸运的是,libc crate defines that structure 所以你可以这样做:


    let sock_timeout = libc::timeval {
        tv_sec: 10,
        tv_usec: 0,
    };

    let result = unsafe {
        libc::setsockopt(
            socket,
            libc::SOL_SOCKET,
            libc::SO_RCVTIMEO,
            &sock_timeout as *const libc::timeval as *const libc::c_void,
            std::mem::size_of::<libc::timeval>() as u32,
        );
    };

为了将 Rust 引用转换为 void * 指针,您需要将其转换两次:一次转换为指向该类型的指针,然后转换为 void 指针。

注意libc也定义了你需要的所有常量,所以你不需要自己定义它们。

另外不要忘记检查 setsockopt 中的 return 值。它将 return 0 表示成功,-1 表示错误。错误代码将在 errno 中可用,在 Rust 中,您可以通过 Error::last_os_error().raw_os_error().

访问