< 返回版块

linjio 发表于 2019-08-17 12:44

程序描述

  • 一个本地简单echo程序,使用Tcplistener,TcpStream实现。

预期结果验证

  • 使用Jmeter5.0 TCP sampler + Jmeter View Results Tree,验证输入输出是否相同。

问题描述

  • 当不使用loop时,输入和输出相同。
  • 当使用loop时:A.Jmeter显示发送成功,但无接受内容。B.server端显示read和write_all方法执行成功。

实现代码

use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
fn main() {
    let listener = TcpListener::bind("127.0.0.1:12345").unwrap();

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                echo1(stream);
            }
            Err(e) => {
                println!("Error...:{:?}", e);
            }
        }
    }
}

fn echo1(mut stream: TcpStream) {
    let mut vec: Vec<u8> = Vec::new();
    let mut buf = [0u8; 30];

    loop //不使用loop时注释此行,但保留大括号
    {  
        let c = stream.read(&mut buf).unwrap();
        if c == 0 {
            break; //不使用loop时注释此行
        } else {
            vec.append(&mut buf[0..c].to_vec());
        }
    }

    let rc = vec.len();
    println!("rc:{}", rc);

    print!("vec:");
    for i in vec[0..rc].iter() {
        print!("{},", i);
    }
    println!("");

    stream.write_all(&vec[0..rc]).unwrap();
}

当不使用loop时,预期结果一致:

vec:48,49,50,51,52,53,54,55,56,57,97,115,100,102,103,104,106,107,109,110, rc:20

当使用loop时,Jmeter无返回内容,错误信息:

vec:48,49,50,51,52,53,54,55,56,57,97,115,100,102,103,104,106,107,109,110, rc:20


WHY?

不知道为什么会这样,感觉对loop有误解,一时找不出原因,还请多多请教,谢谢~

更改历史

  1. @Mike Tang 提示,此问题已更改read_to_end到read方法,解决了问题:“Vec和[u8]表现不一致”,再此感谢。因出现新的问题,固变更此问题。
  2. 经过研究第1点的问题,也找到原因了。

最终原因说明

  1. loop循环体,会多执行一次,此次stream.read()方法返回0或者Err()。
  • 例如1:比如buf大小为5,实际读取总数为10,那么,loop循环体会循环3次。前两次一般正常返回为5,第三次返回0或者Err()。昨晚我试验时均是返回为Err.
  1. 第1点还不足说明为什么Jmeter接收数据失败,其原因如下:
  • Listener.incomig返回的TcpStream目前为blocking模式,当上述例1,第三次read()时,TcpStream会blocking直到接收到数据。
  • Jmeter我设置接收1s超时
  • 综上,Jmeter在发送请求1s后接受不到数据就主动关闭socket,而此时服务器上TcpStream正在等等第三次读取,直到Jmeter关闭socket,read()方法返回错误信息时,再执行write()时,此连接已失效导致了。

话外

  1. @Mike Tang 提示的其实也是第2点的内容,只是我当时看的不是很明白。
  2. 昨晚我重新看了下rust官方文档,无论TcpLister还是TcpStream均未明确说明默认返回的TcpStream为blocking模式,在set_nonbloking()方法中也未说明。或许是默认为Blocking模式,大家都知道。还有我把一些知识点弄混了才导致自己走了不少弯路,值得反醒。
  3. 昨晚测试过是否使用loop的性能差异,在我的台式机上,非loop平均一次echo延迟为us级。而loop平均一次的echo延迟为ms级,其中绝大多数延迟被消费在最后一个返回0或者Err()上。

最后附上我更改后的代码

单线程阻塞模型下的Echo服务,分有buf上限和无buf上限的两种情形

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

fn main() {
    let listener = TcpListener::bind("127.0.0.1:12345").unwrap();

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                // echo_handler_array(stream);
                echo_handler_vec(stream);
            }
            Err(e) => {
                panic!("Error...:{:?}", e);
            }
        }
    }
}

fn echo_handler_array(stream: TcpStream) {
    let mut echo = Echo::new_arrary(stream);
    echo.read_array();
    echo.write();
}

fn echo_handler_vec(stream: TcpStream) {
    let mut echo = Echo::new_vec(stream);
    echo.read_vec();
    echo.write();
}

struct Echo {
    stream: TcpStream,
    buf: Vec<u8>,
    len: usize,
}

impl Echo {
    fn new_vec(stream: TcpStream) -> Echo {
        Echo {
            stream,
            buf: Vec::new(),
            len: 0,
        }
    }
    fn new_arrary(stream: TcpStream) -> Echo {
        let len = 1024*1024;
        let mut arr = Vec::with_capacity(len);
        unsafe {
            arr.set_len(len);
        }
        Echo {
            stream,
            buf: arr,
            len: 0,
        }
    }

    fn read_vec(&mut self) {
        self.stream
            .set_read_timeout(Some(Duration::from_micros(100)))
            .unwrap();
        let mut minbuf = [0u8; 4096];
        loop {
            match self.stream.read(&mut minbuf) {
                Ok(c) => {
                    if c > 0 {
                            self.buf.append(&mut minbuf[0..c].to_vec());
                    } else {
                        break;
                    }
                }
                Err(_) => {
                    break;
                }
            }
        }
    }

    fn read_array(&mut self) {
            self.len = self.stream.read(&mut self.buf[0..]).expect("debug1111");
    }

    fn write(&mut self) {
        self.stream.write(&self.buf[0..self.len]).expect("debug2222");
    }
}

评论区

写评论
作者 linjio 2019-08-17 15:32

谢谢哈,根据你的提示,解决我的问题。再次感谢~ 对以下内容的回复:

Mike Tang 2019-08-17 12:51

read_to_end 直到读到你连接断开时为止,你的测试连接没有断开吧。其实这样写根本不对的,这里不能用 read_to_end。

1 共 2 条评论, 1 页