使用 TcpStream 强制非阻塞读取 [英] Force non blocking read with TcpStream

查看:25
本文介绍了使用 TcpStream 强制非阻塞读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个线程,它维护一个套接字列表,我想遍历该列表,看看是否有任何要读取的内容,如果有 - 对其采取行动,如果没有 - 转到下一个.问题是,一旦我遇到第一个节点,所有执行都会停止,直到读取中出现某些内容.

I've got a thread, that maintains a list of sockets, and I'd like to traverse the list, see if there is anything to read, if so - act upon it, if not - move onto the next. The problem is, as soon as I come across the first node, all execution is halted until something comes through on the read.

我正在使用 std::io::Read::read(&mut self, buf: &mut [u8]) ->结果<使用大小>

来自 doc

这个函数不提供任何关于它是否阻塞等待数据的保证,但是如果一个对象需要阻塞读取但不能,它通常会通过一个 Err 返回值来表示.

This function does not provide any guarantees about whether it blocks waiting for data, but if an object needs to block for a read but cannot it will typically signal this via an Err return value.

深挖源码,TcpStream Read的实现是

Digging into the source, the TcpStream Read implementation is

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)

在那里我可以看到非阻塞读取的循环,直到检索到数据或发生错误.

Where I can see loops over non blocking reads until data has been retrieved or an error has occurred.

有没有办法用 TcpStream 强制非阻塞读取?

Is there a way to force a non-blocking read with TcpStream?

推荐答案

更新答案

需要注意的是,从 Rust 1.9.0 开始,std::net::TcpStream 增加了功能:

It should be noted, that as of Rust 1.9.0, std::net::TcpStream has added functionality:

fn set_nonblocking(&self, 非阻塞: bool) ->结果<()>

原答案

无法通过 TcpStream 准确获取它,并且不想为 IO 操作引入单独的库,因此我决定在使用之前将文件描述符设置为非阻塞,并执行系统调用以读取/写.虽然 MIO 看起来不错,但绝对不是最安全的解决方案,但比实现新的 IO 库的工作量要少.

Couldn't exactly get it with TcpStream, and didn't want to pull in a separate lib for IO operations, so I decided to set the file descriptor as Non-blocking before using it, and executing a system call to read/write. Definitely not the safest solution, but less work than implementing a new IO lib, even though MIO looks great.

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

这篇关于使用 TcpStream 强制非阻塞读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆