如何在Rust中关闭Unix套接字?

时间:2016-10-24 12:26:45

标签: sockets unix rust

我有一个打开并侦听Unix域套接字的测试。套接字被打开并且没有问题地读取数据,但它没有正常关闭。

这是我第二次尝试运行测试时遇到的错误:

  

主题'test_1'对Result::unwrap()上名为Err的'RUST_BACKTRACE=1感到恐慌   值:错误{repr:Os {代码:48,消息:“地址已在使用中”   }}',.. / src / libcore / result.rs:799注意:使用use std::io::prelude::*; use std::thread; use std::net::Shutdown; use std::os::unix::net::{UnixStream, UnixListener}; 运行   回溯。

代码可用at the Rust playground,并且有Github Gist for it

#[test]
fn test_1() {
    driver();
    assert_eq!("1", "2");
}

测试用例:

fn driver() {
    let listener = UnixListener::bind("/tmp/my_socket.sock").unwrap();

    thread::spawn(|| socket_server(listener));

    // send a message 
    busy_work(3);

    // try to disconnect the socket
    let drop_stream = UnixStream::connect("/tmp/my_socket.sock").unwrap();
    let _ = drop_stream.shutdown(Shutdown::Both);
}

主要入口点功能

#[allow(unused_variables)]
fn busy_work(threads: i32) {
    // Make a vector to hold the children which are spawned.
    let mut children = vec![];
    for i in 0..threads {
        // Spin up another thread
        children.push(thread::spawn(|| socket_client()));
    }
    for child in children {
        // Wait for the thread to finish. Returns a result.
        let _ = child.join();
    }
}

fn socket_client() {
    let mut stream = UnixStream::connect("/tmp/my_socket.sock").unwrap();
    stream.write_all(b"hello world").unwrap();
}

按间隔发送数据的功能

fn handle_client(mut stream: UnixStream) {
    let mut response = String::new();
    stream.read_to_string(&mut response).unwrap();
    println!("got response: {:?}", response);
}

处理数据的功能

#[allow(unused_variables)]
fn socket_server(listener: UnixListener) {
    // accept connections and process them, spawning a new thread for each one
    for stream in listener.incoming() {
        match stream {
            Ok(mut stream) => {
                /* connection succeeded */
                let mut response = String::new();
                stream.read_to_string(&mut response).unwrap();
                if response.is_empty() {
                    break;
                } else {
                    thread::spawn(|| handle_client(stream));
                }                
            }
            Err(err) => {
                /* connection failed */
                break;
            }
        }
    }
    println!("Breaking out of socket_server()");
    drop(listener);
}

侦听传入消息的服务器套接字

function CodSubmitOrder(){ $('#btn_cod').attr('disabled', true).addClass('disabled');

$.post('<?php echo base_url('/cod/process-payment');?>', function(data)
{
    if(data.errors != undefined)
    {
        console.log('data error');

        var error = '<div class="alert alert-danger">';
        $.each(data.errors, function(index, value)
        {
            error += '<p>'+value+'</p>';
        });
        error += '</div>';

        $.gumboTray(error);
        $('#btn_cod').attr('disabled', false).addClass('disabled');
    }
    else
    {
        console.log('data success');

        if(data.orderId != undefined)
        {
            window.location = '<?php echo site_url('order-complete/');?>/'+data.orderId;
        }
    }

    console.log(data);
}, 'json');}

1 个答案:

答案 0 :(得分:4)

请学习创建Minimal, Complete, and Verifiable example,然后花点时间这样做。在这种情况下,不需要线程或函数或测试框架;运行整个程序两次重现错误:

use std::os::unix::net::UnixListener;

fn main() {
    UnixListener::bind("/tmp/my_socket.sock").unwrap();
}

如果您在测试之前和之后查看文件系统,您将看到文件/tmp/my_socket.sock在第一次运行之前不存在,并且在第二次运行之前存在。删除文件允许程序再次运行完成(此时它会重新创建文件)。

此问题为not unique to Rust

  

请注意,一旦创建,即使服务器退出,此套接字文件仍将继续存在。如果服务器随后重新启动,则该文件会阻止重新绑定:

     

[...]

     

因此,服务器应在绑定之前取消套接字路径名的链接。

你可以选择在套接字周围添加一些包装器,当它被删除或create a temporary directory that is cleaned when it is dropped时会自动将其删除,但我不确定它的效果如何。您还可以创建一个包装函数,在打开套接字之前删除该文件。