Rust: сетевое программирование

Вопросы написания собственного программного кода (на любых языках)

Модератор: Olej


Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Rust: сетевое программирование

Непрочитанное сообщение Olej » 19 дек 2023, 23:35

Olej писал(а):
19 дек 2023, 21:52
Это в продолжение (или дополнение) темам:
С эхо-сервером, по аналогии, довольно просто...
В 1-м, очень draft приближении, это:

Код: Выделить всё

use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};

fn handle_client(mut stream: TcpStream) {
    let mut buffer = [0; 1024];
    loop {
	stream.read(&mut buffer).expect("Не удалось получить от клиента");
	let request = String::from_utf8_lossy(&buffer[..]);
	println!("Получен запрос: {}", request);
	stream.write(request.as_bytes()).expect("Не удалось отправить клиенту");
    }
}

fn main() {
    let listener = TcpListener::bind("127.0.0.1:53500")
	.expect("Не удалось привязаться к адресу");
    for stream in listener.incoming() {
	match stream {
	    Ok(stream) => {
		std::thread::spawn(move || handle_client(stream));
	    }
	    Err(e) => {
    		eprintln!("Не удалось установить соединение: {}", e);
	    }
	}
    }
}
Компиляцию таких одиночных, простых приложений (ещё и клиент) я намереваюсь делать без менеджера проектов cargo, а простой компиляцией:

Код: Выделить всё

olej@R420:~/2023/own.BOOKs/NET.2/Nexamples.WORK/Rust$ rustc echo_serv.rs 

Код: Выделить всё

 
olej@R420:~/2023/own.BOOKs/NET.2/Nexamples.WORK/Rust$ ls -l echo_serv
-rwxrwxr-x 1 olej olej 4354872 дек 19 22:33 echo_serv

Код: Выделить всё

 
olej@R420:~/2023/own.BOOKs/NET.2/Nexamples.WORK/Rust$ file echo_serv
echo_serv: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=4f8c3dd8d0a2b1f85f46c17017523d14722dde18, for GNU/Linux 3.2.0, with debug_info, not stripped

Код: Выделить всё

 
olej@R420:~/2023/own.BOOKs/NET.2/Nexamples.WORK/Rust$ ldd echo_serv
	linux-vdso.so.1 (0x00007ffe04699000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f86c02ab000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f86c0083000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f86c0355000)
Вложения
echo_serv.rs
(865 байт) 8 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Rust: сетевое программирование

Непрочитанное сообщение Olej » 19 дек 2023, 23:40

Olej писал(а):
19 дек 2023, 23:35
В 1-м, очень draft приближении, это:
Запуск сервера (и дальше обмен с ним):

Код: Выделить всё

olej@R420:~/2023/own.BOOKs/NET.2/Nexamples.WORK/Rust$ ./echo_serv
Получен запрос: 123 456

Получен запрос: строка

Получен запрос: строка

Получен запрос: строка

thread '<unnamed>' panicked at 'Не удалось отправить клиенту: Os { code: 32, kind: BrokenPipe, message: "Broken pipe" }', echo_serv.rs:10:38
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
...
И работающий с ним клиент:

Код: Выделить всё

olej@R420:~$ telnet 127.0.0.1 53500
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
123 456
123 456
строка
строка
^]
telnet> quit
Connection closed.
Или такой клиент:

Код: Выделить всё

olej@R420:~$ nc 127.0.0.1 53500
qwerty
qwerty
^C

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Rust: сетевое программирование

Непрочитанное сообщение Olej » 21 дек 2023, 12:31

Olej писал(а):
19 дек 2023, 23:35
С эхо-сервером, по аналогии, довольно просто...
Более-менее отработаннный, тестированием, эхо-сервер:

Код: Выделить всё

use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};

fn handle_client(mut stream: TcpStream) {
    loop {
	let mut buffer = [0; 120];
        match stream.read(&mut buffer) {
            Err(_)  => {   //клиент закрыл сокет
                return;
            }
            _ => (),	    
        }
	match stream.write(&mut buffer) {
	    Err(_)  => {   //клиент закрыл сокет
		return;
	    }
            _ => (),	    
	} 
    }
}

fn main() {
    const PORT : &str = "53500"; 
    let listener = match 
	TcpListener::bind("127.0.0.1:".to_string() + PORT) {
        Ok(listener) => listener,
        Err(_) => {
            println!("серверный порт занят");
            return;
        }
    };
    println!("waiting on port {}", PORT);
    for stream in listener.incoming() {
	println!("waiting on port {}", PORT); // новый клиент
	match stream {
	    Ok(stream) => {
		std::thread::spawn(move || handle_client(stream));
	    }
	    Err(e) => {
    		eprintln!("ошибка соединения: {}", e);
	    }
	}
    }
}
Вложения
echo_serv.rs
(1.08 КБ) 8 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Rust: сетевое программирование

Непрочитанное сообщение Olej » 21 дек 2023, 12:33

Olej писал(а):
21 дек 2023, 12:31
Более-менее отработаннный, тестированием, эхо-сервер:
И парный к нему TCP клиент:

Код: Выделить всё

use std::io;
use std::io::prelude::*;
use std::net::TcpStream;

fn main() -> std::io::Result<()> {
    let mut stream = match TcpStream::connect("127.0.0.1:53500") {    
        Ok(stream) => stream,
        _ => {
            println!("no server available");
            return Ok(());
        },
    };
    loop {
        print!("> ");
        io::stdout().flush()?;
        let mut req = String::new();
        io::stdin()
            .read_line(&mut req)
            .expect("ошибка ввода пользователя");
        if req.is_empty() {         // ^D - завершение работы
            println!("");
            break;
        }
        if req.len() == 1 {         // Enter - завершение работы
            break;
        }

        match stream.write(&req.as_bytes()) {
            Ok(..) => (),
            Err(e) => println!("Error: {}", e)
        }
        let mut buffer = [0; 120];     // буфер чтения
        match stream.read(&mut buffer) {
            Ok(..) => (),
            Err(e) => println!("Error: {}", e),
        }
        let rep = String::from_utf8_lossy(&buffer[..]);
        print!("{}", rep);
    }
    Ok(())
}
Вложения
echo_cli.rs
(1.17 КБ) 8 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Rust: сетевое программирование

Непрочитанное сообщение Olej » 21 дек 2023, 12:37

Olej писал(а):
21 дек 2023, 12:31
эхо-сервер
Olej писал(а):
21 дек 2023, 12:33
TCP клиент
Для компиляции отдельных (однофайловых) простых приложений нам нет необходимости использовать такой мощный менеджер проектов языка Rust, под именем cargo, а можно напрямую воспользоваться компилятором rustc, так же входящим в инсталляцию проекта Rust:

Код: Выделить всё

olej@R420:~/2023/own.BOOKs/NET.2/Nexamples.WORK/Rust$ rustc echo_serv.rs

Код: Выделить всё

olej@R420:~/2023/own.BOOKs/NET.2/Nexamples.WORK/Rust$ rustc echo_cli.rs

Код: Выделить всё

olej@R420:~/2023/own.BOOKs/NET.2/Nexamples.WORK/Rust$ ls -l | grep ^-rwx
-rwxrwxr-x  1 olej olej 4311104 дек 21 10:58 echo_cli
-rwxrwxr-x  1 olej olej 4361552 дек 21 10:58 echo_serv

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Rust: сетевое программирование

Непрочитанное сообщение Olej » 21 дек 2023, 12:49

Тестируем:

Код: Выделить всё

olej@R420:~/2023/own.BOOKs/NET.2/Nexamples.WORK/Rust$ ./echo_serv
waiting on port 53500
waiting on port 53500
waiting on port 53500
waiting on port 53500
waiting on port 53500
...

Код: Выделить всё

olej@R420:~/2023/own.BOOKs/NET.2/Nexamples.WORK/Rust$ ./echo_cli
> 1 234 567
1 234 567
> русская строка
русская строка
> у
у
> я
я
> х
х
>
И то же самое независимо, средствами утилит Linux:

Код: Выделить всё

olej@R420:~$ nc  127.0.0.1 53500
1 23 456 7890
1 23 456 7890
русская строка
русская строка
^C
telnet - с учётом тех артефактов поведения telnet, которые описаны и разрешены вот здесь Python: сетевые приложения:

Код: Выделить всё

olej@R420:~$ telnet 127.0.0.1 53500
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
string
string
строка
строка
ещё одна строка
ещё одна строка
русская строка
у
я
х
�
^]
telnet> ^]quit
?Invalid command
telnet> quit
Connection closed.
И на самых разных языках мира:

Код: Выделить всё

olej@R420:~$ socat tcp4:127.0.0.1:53500 STDOUT
नमस  ्त  े
नमस  ्त  े
Dobrý den
Dobrý den
لسلام عليكم
لسلام عليكم
今日は
今日は
안녕하세요
안녕하세요
你好
你好
^C

Ответить

Вернуться в «Программирование»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 12 гостей