RUST网络客户端的基本框架

一、说明

在前面介绍了Rust的基础环境,今天就开始学习RUST的一个基本的网络客户端架子(不是框架),并从这个基本架子开始,开始学习RUST的基本知识和各种用法。鉴于RUST现在区块链领域的应用趋势是越来越广泛,搞一搞RUST也是势在必行。

二、应用

照老样子,先看一个基本的例子:

mod datacontrol;
mod server;
mod databuild;

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


use std::str;
use std::io::{self, BufRead, BufReader};
use std::time::Duration;
use crate::databuild::{build_beat, build_signer, build_spacepw};
use crate::datacontrol::dp;

const BEAT:u16 = 0x00;
const REPLY_ID:u16 = 0x605;

fn client_main(){
    let dc =  datacontrol::dp::new();
    //172.16.110.241:18888
    let mut stream = TcpStream::connect("127.0.0.1:18888")
        .expect("connect server error!");

    //let data:[u8;15] = [0x53,0x53,0x05,0x00,0x5e,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x0d];

    //处理更新自己ID
    //写入交互协议代码
    let mut arr:[u8;12] = [0x00;12];
    let mut beat: [u8; 10] = [0x00;10];
    let mut signer:[u8;213] = [0x00;213];
    let mut spacepw:[u8;300] = [0x00;300];//74
    let mut sendlen = 0;
    let mut ok_send = false;

    //let mut beat1;
    unsafe {
        //build beat
        build_beat(&mut beat);

        //build singer
        let md = "12345678901234567890123456789012";
        let recvmd = "12345678901234567890123456789013";
        let datapw= "hijk[]lmn{}";
        build_signer(md,recvmd,&mut signer);
        //build spacepw
        sendlen = build_spacepw(md,recvmd,datapw,&mut spacepw);
    }

    match  stream.write(&signer[..213]){
        Ok(e)=>println!("send ok {}",e),
        Err(e)=>println!("send err!")
    }

    let fn_cb =  |buf:&[u8],len:usize|{

    };

    loop{
        //读控制变量
        let mut buffer: Vec<u8> = Vec::new();
        let mut dst:Vec<u8> = Vec::new();

        let mut reader = BufReader::new(&stream);

        let n = reader.read_until(b'\n', &mut buffer)
            .expect("Could not read into buffer");


        match dc.data_parse(&buffer,&dst,n,&fn_cb) {
            Ok(_0)=>{
                //type case
                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};
                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;
                    },
                    _=>{}
                }
                println!("parse ok!")
            },
            Err(..)=>println!("parse err!")
        }

        if !ok_send{
            thread::sleep(std::time::Duration::new(2,0));
        }else {
            match  stream.write(&spacepw[0..10]){
                Ok(e)=>println!("send ok {}",e),
                Err(e)=>println!("send err!")
            }
        }
        println!("recv data len:{}",n);
        print!("{}", str::from_utf8(&buffer)
            .expect("Could not write buffer as string"));

    }
}
fn call_client(){
    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 handler = thread::spawn(move || {
        thread::sleep(Duration::from_secs(6));
        client_main();

        //thread::sleep_ms(2000);
    });

    handler.join().unwrap();
}
fn main(){
    client_main();
    //server::server_main();

}

这是一个最简单的入门的网络客户端的例子,从这里可以看得出来,相对于用C++编写的客户端,确实是简单了不少。这里先忽略掉对数据解析和控制的问题,这样可能会更方便学习一些。
但是这里面,也有很多的不习惯,特别是对于二进制数据的拷贝和转换,一直都十分的挠头。

三、代码分析

看一下代码,和几乎所有的语言一样,都是从main函数开始,而在这里为了以后写服务端方便,把它们拆成了两个函数。在call_client()函数中,先生成一个小头的数据转换,然后通过线程启动真正的数据接收和发送,来保证整个客户端的稳定运行。
在这里使用了move||,一个无参半包,可以强制通过move获取当前的值。
在client_main()函数中,就执行了两个动作,连接服务端,读写数据。虽然还有第三个动作,数据的解析和分发,但这里不是重点,可以暂时忽略。通过unsafe来组建心跳,这块比较简单。在获得Socket的流操作后,可以直接把心跳发送,再使用match判断结果。在下一篇里会重点分析各个用到的技术。
下面就是通过循环不断的读取Socket缓冲区的数据,并对数据进行分析处理。

四、总结

在2017年就开始学习和初步应用RUST,但一直没有广泛的在实际工程中实践,后续的学习和应用也是断断续续,做为对这三年多来对RUST学习的一个回顾和总结,抱着实际应用的想法,开始这个学习应用的系列。
在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值