Принудительное чтение без блокировки с помощью TcpStream

У меня есть поток, который поддерживает список сокетов, и я хотел бы просмотреть этот список, посмотреть, есть ли что прочитать, если да - действовать на него, если нет - переходить к следующему. Проблема в том, что как только я сталкиваюсь с первым узлом, все выполнение останавливается до тех пор, пока что-то не будет прочитано.

я использую std::io::Read::read(&mut self, buf: &mut [u8]) -> Result<usize>

Из документа

Эта функция не дает никаких гарантий о том, блокирует ли она ожидание данных, но если объект должен заблокировать чтение, но не может, он обычно сигнализирует об этом через возвращаемое значение Err.

Копая в источник, реализация TcpStream Read

impl Read for TcpStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
}

Который вызывает

pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
    let fd = self.fd();
    let dolock = || self.lock_nonblocking();
    let doread = |nb| unsafe {
        let flags = if nb {c::MSG_DONTWAIT} else {0};
        libc::recv(fd,
                   buf.as_mut_ptr() as *mut libc::c_void,
                   buf.len() as wrlen,
                   flags) as libc::c_int
    };
    read(fd, self.read_deadline, dolock, doread)
}

И наконец, звонки read<T, L, R>(fd: sock_t, deadline: u64, mut lock: L, mut read: R)

Где я могу видеть циклы над неблокирующими чтениями, пока не будут получены данные или не произошла ошибка.

Есть ли способ заставить неблокировать чтение с TcpStream?

1 ответ

Решение

Обновленный ответ

Следует отметить, что по состоянию на Rust 1.9.0, std::net::TcpStream добавил функциональность:

fn set_nonblocking(&self, nonblocking: bool) -> Result<()>

Оригинальный ответ

Не удалось получить его с помощью TcpStream, и я не хотел извлекать отдельную библиотеку для операций ввода-вывода, поэтому я решил установить дескриптор файла как неблокирующий перед его использованием и выполнить системный вызов для чтения / записи. Определенно, не самое безопасное решение, но меньше работы, чем реализация новой библиотеки ввода-вывода, хотя MIO выглядит великолепно.

extern "system" {
    fn read(fd: c_int, buffer: *mut c_void, count: size_t) -> ssize_t;
}

pub fn new(user: User, stream: TcpStream) -> Socket {

    // First we need to setup the socket as Non-blocking on POSIX
    let fd = stream.as_raw_fd();
    unsafe {
        let ret_value = libc::fcntl(fd,
            libc::consts::os::posix01::F_SETFL,
            libc::consts::os::extra::O_NONBLOCK);

        // Ensure we didnt get an error code
        if ret_value < 0 {
            panic!("Unable to set fd as non-blocking")
        }
    }

    Socket {
        user: user,
        stream: stream
    }
}

pub fn read(&mut self) {
    let count = 512 as size_t;
    let mut buffer = [0u8; 512];
    let fd = self.stream.as_raw_fd();

    let mut num_read = 0 as ssize_t;
    unsafe {
        let buf_ptr = buffer.as_mut_ptr();
        let void_buf_ptr: *mut c_void = mem::transmute(buf_ptr);
        num_read = read(fd, void_buf_ptr, count);
        if num_read > 0 {
            println!("Read: {}", num_read);
        }

        println!("test");
    }
}
Другие вопросы по тегам