rust学习(二)mio和socketpair及多线程

前言
上章学习了rust 环境搭建及IDE配置
这章主要讲述 模拟C++的socketpair,顺便用下多线程
rust 中文教程 地址:https://kaisery.github.io/trpl-zh-cn/
english :https://doc.rust-lang.org/book/
第三方库:https://docs.rs/
标准库:https://www.rustwiki.org.cn/zh-CN/std/index.html
当前使用的rust 1.65版本

1:mio库
当前 已经是0.8.5版本了,上次的demo用的0.6.* 版本 ,tokio 也用mio
Mio 提供可跨平台的 system selector 访问,所以 Linux epoll、Windows IOCP、FreeBSD/macOS ,甚至许多有潜力的平台都可调用相同的 API。 不同平台使用 Mio API 的开销不尽相同。 由于 Mio 是提供基于 readiness(就绪状态)的 API,与 Linux epoll 相似,不少 API 在 Linux 上都可以一对一映射。 (例如: 实质上是一个 阵列。 )对比之下,Windows IOCP 是基于完成(completion-based)而非基于 readiness 的 API,所以两者间会需要较多桥接。 同时mio提供自身版本的TcpListener、TcpStream、UdpSocket,这些API封装了底层平台相关API,并设为非阻塞且实现Evented trait。

在这里插入图片描述
2: socketpair
虽然有channel
但是不可能以线程 一直等着接受消息
所以跟c++ 的一样的,有消息存在,发送个通知给对方,这样只需要调用
Token(1) 为socketpair专用poll1.poll(&mut events, geptime)
channel send 一个条消息,socket发送一个字节,收到多少字节就调用多少次receiver1.recv()
std::sync::mpsc::channel;//支持多Sender,仅支持1个Receiver,可保证接收消息的顺序与发送的顺序一致。
let (sender1, receiver1) = channel::<Trans_Data>(); //channel::<>()
let (sender2, receiver2) = channel::<Trans_Data>();
在这里插入图片描述

3:code`
在这里插入图片描述

extern crate mio;
extern  crate rand;

use std::net;
use std::io ;


use mio::{Events, Poll, Interest, Token};
use mio::net::TcpStream ;

use std::sync::mpsc::channel;//支持多Sender,仅支持1个Receiver,可保证接收消息的顺序与发送的顺序一致。
use std::{thread,time};
use std::io::{Write, Read, Error};
use std::time::{Duration};

use std::io::{ ErrorKind};


fn socket_pair()->std::io::Result<(std::net::TcpStream,std::net::TcpStream)>{
    let listener = net::TcpListener::bind("127.0.0.1:0")?;

    let clientaddr = listener.local_addr()? ;
    let stream1 = net::TcpStream::connect(&clientaddr)?;
    // accept connections and process them serially
    //  let  Ok((stream,_)) =  listener.accept()?;
    match listener.accept() {
        Ok((socket, _)) =>{ drop(listener); return Ok((stream1,socket)); },
        Err(e) => {drop(listener); return Err(e); }
    }
}

//#[derive(Clone)]
struct Trans_Data {
    userid: u32,
    msgindex:u32,
    context:String
}
//
// impl Clone for Trans_Data{
//     fn clone(&self) -> Self{
//         Self { userid: self.userid, msgindex: self.msgindex,context:self.context.clone() }
//     }
// }
//impl Copy for Trans_Data{}


fn main() {
    println!("Hello, world!");
    let x = rand::random::<u8>();
    println!("num={}",x);

    let mut poll1 = Poll::new().expect("Failed to create Poll_1");
    let mut poll2 = Poll::new().expect("Failed to create Poll_2");

    let(socket1,socket2) = match  socket_pair() {
        Ok((s1,s2))=> (s1,s2),
        _=>unreachable!()
    } ;

    let mut fd1=   register(& mut poll1, &  socket1,Token(1)).unwrap();
    let mut fd2=   register(& mut poll2,&   socket2,Token(1)).unwrap();

    // let (sender1, receiver1) = channel(); //channel::<>()
    //
    // let (sender2, receiver2) = channel();

    let (sender1, receiver1) = channel::<Trans_Data>(); //channel::<>()

    let (sender2, receiver2) = channel::<Trans_Data>();
    const WAITGEPMS: u32 = 1000;
    thread::spawn(move|| {
        let mut events = Events::with_capacity(4);
        sender2.send(Trans_Data{
            userid: 1,
            msgindex:1,
            context:String::from("context=1+1")
        }).unwrap() ;
//        sender2.send(2).unwrap() ;
//        let mut s = [0 as u8; 1];
//        s[0] = 1;
        //  fd1.write(&s[..]) ;
//        fd1.write(&[1]);
        fd1.write(&[1]);
        //     println!("thread1 send");
        //   const WAITGEPMS: u32 = 1000;
        let geptime = Some(Duration::from_millis(WAITGEPMS as u64));

        loop {
            match poll1.poll(&mut events, geptime){
                Ok(())=>{},  //println!("[1111111]OK")
                _=>{println!("[1111111] num= ERR");}
            }

            for event in &events {
                if event.token() == Token(1) {
                  //  println!("recv [11111] event.token()");

                    //event.is_readable()
                    if event.is_readable() {
                        let mut buf=[0u8;4096];
                        let bytes = match fd1.read(&mut buf) {
                            Ok(n) => {
                                if n > 1 {
                                    println!("[11111] read data len={}",n);
                                }
                                n
                            },
                            Err(e)=> {
                                if e.kind() == ErrorKind::WouldBlock {
                                    0
                                }else{
                                    println!("[1111111] read data fail={}",e); 0
                                }
                            }
                        };
                        thread::sleep(time::Duration::from_millis(1));
                        for i in  0 ..bytes {
                            let mut recvnum = receiver1.recv().unwrap();
                           // sender2.send(recvnum+1).unwrap() ;
                           let mut data1 =  recvnum as Trans_Data  ;

                            let tmpuser = data1.userid;
                            let mut tmpmsgindex = data1.msgindex ;

                            let msgcount =  data1.msgindex ;
                            data1.msgindex += 1 ;
                           // data1.context=String::from("context=");
                            let mut  tmpcontext = String::from("context=")+ &data1.userid.to_string() ;
                            tmpcontext += "+" ;
                            tmpcontext+= &data1.msgindex.to_string();
                            data1.context = tmpcontext;
                         //   data1.context = "context="+

                            sender2.send(data1).unwrap() ;

                            fd1.write(&[1]).unwrap();

                            let tmpnum = rand::random::<u8>();

                            for j in 0..(tmpnum&0xF) {
                                let mut  tmpcontext3 = String::from("context=")+ &tmpuser.to_string() ;
                                tmpcontext3 += "+" ;
                                tmpmsgindex += 1;
                                tmpcontext3 += &tmpmsgindex.to_string();

                                sender2.send(Trans_Data{
                                    userid: tmpuser,
                                    msgindex:tmpmsgindex,
                                    context:tmpcontext3
                                }).unwrap() ;

                            }
                         //   println!("[1111111] recv data={:?} send data={}", msgcount,tmpmsgindex);
                        }
                    }
                    reregister(& mut poll1,& mut fd1,Token(1));
                }
            }
//            let mut recvnum = receiver1.recv().unwrap();
//            println!("[1112222222] recv data={:?} send data={}", recvnum,recvnum+1);
        }
    });

    {
        //  const WAITGEPMS: u32 = 1000;
        let geptime = Some(Duration::from_millis(WAITGEPMS as u64));
        let mut events = Events::with_capacity(4);
        loop {

            match poll2.poll(&mut events, geptime){
               // Ok(num)=>{println!("[222222] num= {}",num);},
                Ok(())=>{}, //println!("[22222]OK")
                _=>{println!("[222222] num= ERR");}
            }

            for event in &events {
                if event.token() == Token(1) {
                  //  println!("recv [22222] event.token()");
                    if event.is_readable() {
                        let mut buf=[0u8;4096];
                        let bytes = match fd2.read(&mut buf) {
                            Ok(n) => {
                                if n > 1 {
                                    println!("[222222] read data len={}", n);
                                }
                                n
                                //  println!("[222222] read data len={}",n); n},
                            }
                            Err(e)=> {
                                if e.kind() == ErrorKind::WouldBlock {
                                    0
                                } else {
                                    println!("[222222] read data fail={}", e);
                                    0
                                }
                            }
                        };
                        //   println!("[222222] read data len={}",bytes);
                        thread::sleep(time::Duration::from_millis(1));
                        for i in  0 ..bytes {
                            let mut recvnum = receiver2.recv().unwrap();

                            let mut data1 =  recvnum as Trans_Data  ;

                            let tmpuser = data1.userid;
                            let mut tmpmsgindex = data1.msgindex ;

                            let msgcount =  data1.msgindex ;
                            data1.msgindex += 1 ;

                            let mut  tmpcontext = String::from("context=")+ &data1.userid.to_string() ;
                            tmpcontext += "+" ;
                            tmpcontext+= &data1.msgindex.to_string();
                            data1.context = tmpcontext;
                            sender1.send(data1).unwrap() ;
                            //     recvnum += 1 ;
                           // sender1.send(recvnum+1).unwrap() ;
                            fd2.write(&[1]).unwrap();

                            let tmpnum = rand::random::<u8>();

                            for j in 0..(tmpnum&0x1F) {
                                let mut  tmpcontext3 = String::from("context=")+ &tmpuser.to_string() ;
                                tmpcontext3 += "+" ;
                                tmpmsgindex += 1;
                                tmpcontext3 += &tmpmsgindex.to_string();

                                sender1.send(Trans_Data{
                                    userid: tmpuser,
                                    msgindex:tmpmsgindex,
                                    context:tmpcontext3
                                }).unwrap() ;

                            }
                          //  println!("[222222] recv data={:?} send data={}", msgcount,tmpmsgindex);
                        }
                    }
                    reregister(& mut poll2,& mut fd2,Token(1));
                }
            }
        }
    }


}

// #[cfg(target_os = "linux")]
// fn get_stream(sock:&  std::net::TcpStream)->mio::net::TcpStream{
//
// }

// #[cfg(target_os = "windows")]
// fn get_stream(sock:&  std::net::TcpStream)->mio::net::TcpStream{
//    // unsafe { mio::net::TcpStream::FromRawSocket::from_raw_socket(*sock) }
//     mio::net::TcpStream::connect("")
// }

pub fn register( poll: &mut Poll,sock:&  std::net::TcpStream,token:Token) -> io::Result<(mio::net::TcpStream)> { //& mut

    let mut  stream = mio::net::TcpStream::from_std((*sock).try_clone()?);
    // if cfg!(target_os = "linux") {
    //     println!("linux");
    // } else {
    //     println!("not linux");
    // }
    match poll.registry().register(
         &mut stream,
         token,
         Interest::READABLE | Interest::WRITABLE){
        Ok(_)=>Ok(stream),
        _=>unreachable!()
    }
}

pub fn reregister(poll: &mut Poll, stream:& mut mio::net::TcpStream,token:Token) -> io::Result<()> {
    //trace!("connection reregister; token={:?}", self.token);

    poll.registry().reregister(
        stream,
        token,
        Interest::READABLE | Interest::WRITABLE
    ).or_else(|e| {
            //error!("Failed to reregister {:?}, {:?}", self.token, e);
            Err(e)
        })
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Rust是一种现代的系统级编程语言,它提供了内存安全、并发性和高性能的特性。在Rust中,多线程同步是通过标准库中的原子类型和同步原语来实现的。 Rust的原子类型(Atomic Types)是一种特殊的数据类型,可以在多个线程之间进行原子操作,保证操作的原子性。常见的原子类型包括AtomicBool、AtomicIsize、AtomicUsize等。通过原子类型,可以实现多线程之间的共享数据的安全访问。 除了原子类型,Rust还提供了一些同步原语,用于实现多线程之间的同步和互斥。其中最常用的是Mutex和RwLock。Mutex提供了互斥锁机制,确保在同一时间只有一个线程可以访问被锁定的数据。RwLock则提供了读写锁机制,允许多个线程同时读取数据,但只允许一个线程进行写操作。 使用Rust进行多线程同步的一般步骤如下: 1. 导入所需的库:在Rust中,需要使用std::sync模块中的相关类型和函数来实现多线程同步。 2. 创建共享数据:定义需要在多个线程之间共享的数据结构。 3. 使用原子类型:对需要在多个线程之间进行原子操作的数据使用原子类型进行封装。 4. 使用同步原语:使用Mutex或RwLock对需要进行互斥访问的数据进行封装。 5. 创建线程:使用std::thread模块创建多个线程,并传递共享数据的引用给每个线程。 6. 进行同步操作:在每个线程中,使用Mutex的lock方法获取锁,并对共享数据进行操作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值