为什么在HTTP负载测试结束时,边缘触发的epoll循环会冻结?

时间:2018-09-29 20:33:11

标签: rust epoll

我正在编写一个HTTP服务器,我希望每个CPU有一个线程,并且每个线程控制一个单独的epoll实例。我已经使用nix板条箱实现了边缘触发epoll的测试版本,但我不知道它有什么问题。

当我使用abab -n 200000 -c 1000)进行测试时,它可以快速运行, 但在测试结束时,epoll冻结。我不知道怎么了,也许我破坏了epoll状态或需要使用客户端的内部状态?

extern crate nix;

use nix::errno::Errno;
use nix::fcntl::*;
use nix::sys::epoll::EpollCreateFlags;
use nix::sys::epoll::*;
use nix::sys::socket::sockopt::ReuseAddr;
use nix::sys::socket::*;
use nix::unistd::close;
use nix::unistd::{read, write};
use nix::Error;
use std::collections::HashMap;
use std::os::unix::io::RawFd;
use std::thread;

const BUFSIZE: usize = 16384;

#[derive(Hash, Eq, PartialEq, Debug, Clone, Copy)]
pub enum State {
    Read,
    Write,
}

#[derive(Clone, Debug)]
pub struct Client {
    pub readed: Vec<u8>,
    pub state: State,
}

impl Client {
    fn new() -> Self {
        Client {
            readed: Vec::new(),
            state: State::Read,
        }
    }
}

fn socket_to_nonblock(sock: RawFd) -> Result<(), nix::Error> {
    let flags = match fcntl(sock, F_GETFL) {
        Ok(fl) => fl,
        Err(err) => return Err(err),
    };
    let new_flags = flags | OFlag::O_NONBLOCK.bits();
    let new_flags = OFlag::from_bits(new_flags).unwrap();

    match fcntl(sock, F_SETFL(new_flags)) {
        Ok(_) => return Ok(()),
        Err(err) => return Err(err),
    }
}

fn epoll_loop(server_sock: RawFd) -> nix::Result<()> {
    let mut clients: HashMap<RawFd, Client> = HashMap::new(); //SockFlag::EPOLLET

    let epfd = epoll_create1(EpollCreateFlags::from_bits(0).unwrap())?;
    let mut ev = EpollEvent::new(
        EpollFlags::EPOLLIN | EpollFlags::EPOLLOUT,
        server_sock as u64,
    );
    epoll_ctl(epfd, EpollOp::EpollCtlAdd, server_sock, &mut ev)?;

    let mut epoll_events = vec![EpollEvent::empty(); 1024];
    let buffer = [0; BUFSIZE];
    let critical_error = false;
    let mut accepted = 0;
    let mut closed = 0;

    let mut refused = 0;
    loop {
        let nfds = match epoll_wait(epfd, &mut epoll_events, -1) {
            Ok(n) => n,
            Err(e) => {
                println!("Err wait {:?}", e);
                panic!();
            }
        };

        for i in 0..nfds {
            let cur_socket = epoll_events[i].data() as i32;
            let cur_event = epoll_events[i].events();

            if cur_event == cur_event & EpollFlags::EPOLLERR
                || cur_event == cur_event & EpollFlags::EPOLLHUP
                || cur_event != cur_event & (EpollFlags::EPOLLIN | EpollFlags::EPOLLOUT)
            {
                println!("error big if {:?}", cur_event);
                close(epoll_events[i].data() as i32);
                continue;
            }

            if server_sock == cur_socket {
                loop {
                    let client_fd = match accept(server_sock) {
                        Ok(client) => {
                            accepted += 1;
                            if (client < 0) {
                                println!("JOPA");
                                panic!();
                            }
                            println!(
                                "Accepted {:?} Closed {:?} Dif: {:?} Refused {:?} Events len: {:?}",
                                accepted,
                                closed,
                                accepted - closed,
                                refused,
                                nfds
                            );
                            client
                        }
                        Err(err) => {
                            refused += 1;
                            println!("Error accept {:?}", err);
                            break;
                        }
                    };

                    match socket_to_nonblock(client_fd) {
                        Ok(_) => {}
                        Err(err) => println!("Non block err {:?}", err),
                    }

                    let mut ev = EpollEvent::new(
                        EpollFlags::EPOLLIN | EpollFlags::EPOLLET,
                        client_fd as u64,
                    );
                    match epoll_ctl(epfd, EpollOp::EpollCtlAdd, client_fd, &mut ev) {
                        Ok(e) => {}
                        Err(err) => println!("Server accept ctl {:?}", err),
                    }
                    println!("{:?}", clients.insert(client_fd, Client::new()));
                    break;
                }
                println!("loop breaked");
                continue;
            }

            if cur_event == cur_event & EpollFlags::EPOLLIN {
                let mut buf: [u8; 2048] = [0; 2048];
                let client = clients.get_mut(&cur_socket).unwrap();
                loop {
                    let mut total_len = client.readed.len();
                    let size = match read(cur_socket, &mut buf[total_len..]) {
                        Ok(size) => {
                            client.readed.extend_from_slice(&buf[..size]);
                            if (size == 0) {
                                break;
                            }
                        }
                        Err(e) => break,
                    };
                }

                let req = std::str::from_utf8(&client.readed.as_slice())
                    .unwrap()
                    .to_string();

                if !(req.find("\n\n").is_some() || req.find("\r\n\r\n").is_some()) {
                    continue;
                }

                let mut ev = EpollEvent::new(
                    EpollFlags::EPOLLOUT | EpollFlags::EPOLLET,
                    cur_socket as u64,
                );
                match epoll_ctl(epfd, EpollOp::EpollCtlMod, cur_socket, &mut ev) {
                    Ok(e) => {}
                    Err(err) => println!("Read ctl Err {:?}", err),
                }

                client.state = State::Write;
            }

            if cur_event == cur_event & EpollFlags::EPOLLOUT {
                let buf = "HTTP/1.1 200 Ok\nConnection: close\nContent-Type: text/plain\n\nha?\n\n";
                let buf_len = buf.len();
                let mut sended = 0;
                let mut need_to_close = false;
                loop {
                    match write(cur_socket, &buf.as_bytes()[sended..]) {
                        Ok(len) => {
                            sended += len;
                            if sended >= buf_len {
                                need_to_close = true;
                                break;
                            }
                        }
                        Err(e) => {
                            need_to_close = true;
                            break;
                        }
                    }
                }

                if (need_to_close) {
                    match epoll_ctl(
                        epfd,
                        EpollOp::EpollCtlDel,
                        cur_socket as i32,
                        &mut epoll_events[i],
                    ) {
                        Ok(e) => {}
                        Err(err) => println!("Err epollctl write {:?}", err),
                    }
                    clients.remove(&cur_socket);
                    match shutdown(cur_socket as i32, Shutdown::Both) {
                        Ok(e) => {}
                        Err(err) => println!("Err shutdown {:?}", err),
                    }
                    close(cur_socket as i32)?;
                    closed += 1;
                    println!("closed: {:?}", closed);
                }
            }
            continue;
        }
    }
}

fn main() {
    let server_sock = match socket(
        AddressFamily::Inet,
        SockType::Stream,
        SockFlag::SOCK_NONBLOCK,
        SockProtocol::Tcp,
    ) {
        Ok(sock) => sock,
        Err(err) => panic!("{:?}", err),
    };

    match setsockopt(server_sock, ReuseAddr, &true) {
        Ok(_) => {}
        Err(err) => panic!("Error set sock opt {:?}", err),
    }
    let addr = SockAddr::new_inet(InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 5468));

    match bind(server_sock, &addr) {
        Ok(_) => {}
        Err(err) => panic!("Error bind: {:?}", err),
    }

    socket_to_nonblock(server_sock);
    match listen(server_sock, 1024) {
        Ok(_) => {}
        Err(err) => panic!("Error listen: {:?}", err),
    }

    epoll_loop(server_sock.clone());
}

0 个答案:

没有答案