O servidor de soquete de domínio Unix só imprime mensagem quando o cliente fecha [duplicado]

Dec 04 2020

Estou tentando implementar um servidor de soquete de domínio Unix em Rust, que permite que um cliente se conecte, então o cliente envia uma mensagem pelo soquete e o servidor a imprime. No entanto, o servidor não imprime a mensagem até que eu feche (CTLR + C) o processo do cliente. Qual poderia ser o problema? Aqui estão os dois códigos:

Servidor:

use std::thread;
use std::os::unix::net::{UnixStream, UnixListener};
use std::io::prelude::*;
use std::io::{BufRead, BufReader};

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

    for stream in listener.incoming() {
        match stream {
            Ok(mut stream) => {
                println!("Client connected!");
                thread::spawn(move ||  {
                    let mut out = String::new();
                    let mut bf = BufReader::new(stream);
                    bf.read_line(&mut out);
                    println!("{}", out);
                });
            } Err(err) => {
                println!("Connection failed!");
                break;
            }
        }
    }
    println!("Hello, world!");
}

Cliente:

use std::os::unix::net::{UnixStream, UnixListener};
use std::io::prelude::*;
use std::io::{BufWriter};

fn main() {
    let mut stream = UnixStream::connect("/tmp/socket.sock").unwrap();
    let mut bf = BufWriter::new(&stream);

    bf.write_all("Hello server".as_bytes());
    bf.flush();
    drop(bf);
}

Também tentei com o método read_to_string, mas ele simplesmente não imprime até que o cliente feche. Alguém tem ideia de qual é o problema?

Respostas

1 DavidSchwartz Dec 04 2020 at 18:06
bf.read_line(&mut out);

Seu código lido lê as linhas . Mas o seu código de envio não envia uma linha. Portanto, o código de leitura continua tentando ler uma linha conforme você pediu. Quando a conexão é fechada, o código lido não pode mais tentar ler uma linha, então ele retorna.

Você deve implementar o mesmo protocolo em ambos os lados. Se o leitor entender que terminações de linha são limites de mensagem, então o escritor deve colocar uma linha terminando em cada ponto em que você deseja que o código de recebimento entenda o final de uma mensagem.

A propósito, é realmente uma boa ideia documentar qualquer protocolo que você vai sobrepor a um protocolo de rede, pelo menos até ter muito mais experiência. Isso teria evitado esse tipo de erro. O protocolo diria que as mensagens consistem em linhas ou diria que consistem em outra coisa, e isso deixaria claro qual lado está errado e qual está certo.

Como está agora, nenhum dos lados está certo ou errado. Eles simplesmente discordam. Esses erros são completamente evitados pela documentação de protocolo adequada. O protocolo que esses dois programas estão usando para se comunicarem é baseado em linha? Ou não? Você precisa de documentação para saber. Vale o esforço para documentar.