一、客户端的说明
上文中的网络客户端,其实就是一个比较简单的TCP通信客户端,原来为了实现和服务端的通信,增加了相关的通信协议的相关内容,在这里分析时,可以忽略掉,毕竟它和RUST本身的内容没有什么太大关系。
用一个实际的例子讲解分析RUST可能更容易理解和进一步的掌握实际应用的形式和特点,不会为了学而学,导致学而不会用的现象出现。
二、主要技术
在这个客户端里,应用到的主要技术有:
1、变量声明和使用
2、二进制数据的操作
3、分支匹配跳转
4、线程应用
5、Socket的应用
下面就按照这几个方向的内容进行解析和学习。
三、技术分析
1、RUST的变量
基础的变量命名如下:
let md = "12345678901234567890123456789012";
let recvmd = "12345678901234567890123456789013";
let mut sendlen = 0;
let mut ok_send = false;
在RUST中,变量是参绑定的方式存在的,一种是普通变量绑定,一种是可变变量(mut关键字)绑定。前者有点类似于不可变变量声明,后者类似于传统的其它语言的普通变量声明定义。
2、二进制数据
无论是哪种语言,对二进制的处理都是一个比较棘手的问题,看一下RUST中的一些处理方式:
//使用向量处理二进制处理
let mut buffer: Vec<u8> = Vec::new();
let mut dst:Vec<u8> = Vec::new();
//普通数组和指针来处理二进制数据,包括使用unsafe非安全的操作方式
let typebuf: [u8;2] = [dst[2],dst[3]];
let ptr :*const u8 = typebuf.as_ptr();
let ptr :*const u16 = ptr as *const u16;
let td =unsafe{ *ptr};//有点类似于c#早期的处理
//大小头模式对U32数据向二进制转换
let mut data:u32 = 0x12345678;
let mut arr:[u8;4];
unsafe { arr = std::mem::transmute::<u32, [u8;4]>(data.to_le()); };// == [42, 0, 0, 0]
//典型的二进制数组的初始化方式和截取方式
let mut pbuf1 = &self.buf[0..];
let mut pbuf:[u8;4096] = [0x00;4096];
// 二进制数据的循环遍历赋值
for (d1, d2) in pbuf.iter_mut().zip(buf.iter()) {
*d1 = *d2;
println!("{}",*d1);
}
对RUST中二进制数据的操作真心的有一种力不从心的感觉,文档也不全,而且版本不同导致相关的说明都不一致,这也引起了很大的歧义,估计这也是RUST初学者的一种痛苦吧。毕竟新语言,相对于成熟的老语言,好多技术都在迅速迭代,RUST本身又没有什么超级大公司在后面撑着(比如GO有GOOGLE),相关的学习还是比较让人烦的。
3、分支跳转
分支跳转类似于switch这个语句,但在RUST更灵活方便:
//类似Switch
match td {
BEAT=>{
//回复心跳
match stream.write(&beat[0..10]){
Ok(e)=>println!("send ok {}",e),
Err(e)=>println!("send err!")
}
},
REPLY_ID=>{
//处理消息回复
ok_send = true;
continue;
},
_=>{}
}
match的特点在于,它是会穿透整个过程并且每个分支必须是一个表达式,除非发生恐慌painc,另外它还可以对数据进行解构。
4、多线程
多线程的使用就是下蛋,产卵,记得最初看到这个好像在安卓的framework中,有意思:
let handler = thread::spawn(move || {
thread::sleep(Duration::from_secs(6));
client_main();
//thread::sleep_ms(2000);
});
//这一行代码的作用是等待子线程结束,如果不等待,有可能会出现主线程退出而子线程仍然在运行产生未知结果
//不过在RUST,这个应该不会有崩溃的现象发生
handler.join().unwrap();
move||是强制获取闭包所在环境的所有权,说白就是穿透二者的栅栏可以互通有无,类似于c++中的Lambda表达式中的[&]之类的用法。后面文章会详细分析。
5、网络通信客户端
RUST网络通信真得简单:
let mut stream = TcpStream::connect("127.0.0.1:18888")
.expect("connect server error!");
stream.write(&signer[..213])
let mut reader = BufReader::new(&stream);
let n = reader.read_until(b'\n', &mut buffer)
.expect("Could not read into buffer");
确实比其它语言要简单许多,至少比c++需要设置各种协议各种转换要简单不少。
上面的应用中,有借用(引用和生命周期)和闭包以及多线程会在后面具体介绍,这里篇幅展不开。
这里的分析说明,并不是说把RUST中相关的技术都透彻的讲一遍,而是小范围有目的的一步步的引入。正如孩提时代,学习认识世界一样,一步步来,不需要一下子把所有的东西都弄明白。这也是一种学习的方法吧,好不好,就看适合不适合具体的个人情况了。
四、总结
RUST虽然推出也算不短时间了,但由于IDE及相关调试工具以及社区的普及性等等问题,仍然是只在个别的领域内小范围的火,大规模的推广普及从其设计和发展来看,至少短时间内的可能性还是比较小的。
他山之石,可以攻玉,学习新东西,就是为了拓展视野,看看能不能更好的解决当前实际工程的实际问题。适合的,就是最好的。单纯的追求技术上或者思想上的先进性,有可能会陷入思维的误区。