程序描述
- 一个本地简单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有误解,一时找不出原因,还请多多请教,谢谢~
更改历史
- 经 @Mike Tang 提示,此问题已更改read_to_end到read方法,解决了问题:“Vec和[u8]表现不一致”,再此感谢。因出现新的问题,固变更此问题。
- 经过研究第1点的问题,也找到原因了。
最终原因说明
- loop循环体,会多执行一次,此次stream.read()方法返回0或者Err()。
- 例如1:比如buf大小为5,实际读取总数为10,那么,loop循环体会循环3次。前两次一般正常返回为5,第三次返回0或者Err()。昨晚我试验时均是返回为Err.
- 第1点还不足说明为什么Jmeter接收数据失败,其原因如下:
- Listener.incomig返回的TcpStream目前为blocking模式,当上述例1,第三次read()时,TcpStream会blocking直到接收到数据。
- Jmeter我设置接收1s超时
- 综上,Jmeter在发送请求1s后接受不到数据就主动关闭socket,而此时服务器上TcpStream正在等等第三次读取,直到Jmeter关闭socket,read()方法返回错误信息时,再执行write()时,此连接已失效导致了。
话外
- @Mike Tang 提示的其实也是第2点的内容,只是我当时看的不是很明白。
- 昨晚我重新看了下rust官方文档,无论TcpLister还是TcpStream均未明确说明默认返回的TcpStream为blocking模式,在set_nonbloking()方法中也未说明。或许是默认为Blocking模式,大家都知道。还有我把一些知识点弄混了才导致自己走了不少弯路,值得反醒。
- 昨晚测试过是否使用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");
}
}
1
共 2 条评论, 1 页
评论区
写评论谢谢哈,根据你的提示,解决我的问题。再次感谢~ 对以下内容的回复:
read_to_end 直到读到你连接断开时为止,你的测试连接没有断开吧。其实这样写根本不对的,这里不能用 read_to_end。