简体   繁体   English

如何通过 libc 设置 TcpStream 的 sockopt?

[英]How do I setsockopt of a TcpStream via libc?

I know TcpStream has stream.set_read_timeout but I need to make it in libc for Windows, but my code don´t works and I believe it is because I can't understand the way to put milliseconds in _value: *const c_char .我知道TcpStreamstream.set_read_timeout但我需要在libc中为 Windows 制作它,但我的代码不起作用,我相信这是因为我无法理解将毫秒放入_value: *const c_char的方法。 In Rust I wrote let qtie = [100].as_ptr();在 Rust 我写了let qtie = [100].as_ptr(); but its wrong.但这是错误的。 I also don't know how return a c_int in extern "C" fn .我也不知道如何在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);
            }
        }
    }
}

According to the socket manpage :根据套接字联机帮助页

Specify the receiving or sending timeouts until reporting an error.指定接收或发送超时,直到报告错误。 The argument is a struct timeval.参数是一个 struct timeval。

Luckily, the libc crate defines that structure so you can do this:幸运的是,libc crate定义了该结构,因此您可以这样做:


    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,
        );
    };

In order to get the rust reference into a void * pointer, you need to cast it twice: once to a pointer to the type, then to the void pointer.为了将 rust 引用转换为void *指针,您需要将其转换两次:一次转换为指向该类型的指针,然后转换为 void 指针。

Note that libc also defines all the constants you need, so you don't need to define them yourself.请注意, libc还定义了您需要的所有常量,因此您无需自己定义它们。

Also don't forget to check the return value from setsockopt .也不要忘记检查setsockopt的返回值。 It will return 0 for success and -1 for an error.它将返回 0 表示成功,-1 表示错误。 The error code will be available in errno , which in rust you can access via Error::last_os_error().raw_os_error() .错误代码将在errno中提供,在 rust 中,您可以通过Error::last_os_error().raw_os_error()访问。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM