在Rust 0.9中,现在在0.10中,我尝试在Rust中实现一个简单的tcp客户端,将数据存储在环形缓冲区中,认为这是处理任务和端口/通道提供不可预测输入的好方法。但我抓住了TcpStream的东西。
这是我的环缓冲区实现。感觉很笨,但我认为这将是一个有效的概念验证:
static BUFFER_SIZE: uint = 10;
static BUFFER_CELL_SIZE: uint = 128;
pub struct SimpleRingBuffer {
//see below in SimpleRingBuffer#new for waffling on design.
cells: ~[ Option<~[u8]> ], //see, it's still low-level because raw bytes.
max_cell_size: uint,
write_cursor: uint,
read_cursor: uint,
length: uint,
}
impl SimpleRingBuffer {
//look out for fencepost errors.
pub fn new(buffer_length: uint, max_cell_length: uint) -> SimpleRingBuffer {
//should this pre-allocate the arrays to avoid resizing penalties? This would mean culling
//Nones and dealing with sizing elsewhere I'd think. Also ahving to think about it.
let mut none_array: ~[ Option<~[u8]> ] = ~[];
for each_u8 in range(0, buffer_length) { //FIXME use proper ittorator.
//none_array.push(std::vec::with_capacity<u8>(max_cell_length));
none_array.push(None);
};
SimpleRingBuffer {
cells: none_array,
max_cell_size: max_cell_length,
write_cursor: 0, //not really cursors.
read_cursor: 0, //not really cursor.
length: buffer_length
}
}
//FIXME use <T> and a sanitize method.
pub fn write_data(&mut self, incoming_data: &[u8]) {
if self.write_cursor == self.length {
self.write_cursor = 0;
}
self.cells[self.write_cursor] = Some(incoming_data.to_owned());
self.write_cursor += 1;
}
pub fn read_cell(&mut self) -> ~[u8] {
let mut read_array: ~[u8] = ~[];
match self.cells[self.read_cursor] {
Some(ref n) => read_array = n.clone(),
None => ()
}
self.read_cursor += 1;
read_array
}
pub fn release_entire_buffer(&mut self) -> ~[ ~[u8] ] {
self.read_cursor = 0;
let mut buffer_array: ~[ ~[u8] ] = ~[];
for each_cell in range(self.read_cursor, self.length) {
buffer_array.push(self.read_cell());
}
self.read_cursor = 0;
self.write_cursor = 0;
buffer_array
}
}
这是我的客户:
pub mod simpletcpclient {
use std::io::net::ip::SocketAddr;
use std::io::net::tcp::TcpStream;
use std::str;
use simpletcpclient::simpleringbuffer::SimpleRingBuffer;
static BUFFER_SIZE: uint = 16;
static BUFFER_CELL_SIZE: uint = 1024;
pub struct SimpleClient {
read_buffer: SimpleRingBuffer,
write_buffer: SimpleRingBuffer, //unimplemented
socket: SocketAddr
}
impl SimpleClient {
pub fn new(host_addr: &str) -> SimpleClient {
let mut write_buff = SimpleRingBuffer::new(BUFFER_SIZE, BUFFER_CELL_SIZE);
let mut read_buff = SimpleRingBuffer::new(BUFFER_SIZE, BUFFER_CELL_SIZE);
SimpleClient {
read_buffer: read_buff,
write_buffer: write_buff,
socket: from_str::<SocketAddr>(host_addr).unwrap()
}
}
//see https://mail.mozilla.org/pipermail/rust-dev/2013-August/005111.html
pub fn launch_client(&mut self) {
let mut in_stream = TcpStream::connect(self.socket);
let an_req: ~str = ~"GET / HTTP/1.1\r\n\r\n";
//let an_req: ~str = ~"GET more-than-a-thousand.html HTTP/1.1\r\n\r\n";
self.read_incoming(an_req);
self.print_read_info();
}
fn read_incoming(&mut self, tcp_req: ~str) {
let mut in_stream = TcpStream::connect(self.socket);
let mut temp_cell = ~[0, .. BUFFER_CELL_SIZE];
in_stream.write(tcp_req.as_bytes());
//TcpStream indecision here!
//in_stream.read(temp_cell);
//let temp_cell = in_stream.read_to_str();
in_stream.push_bytes(&mut temp_cell, BUFFER_CELL_SIZE);
self.read_buffer.write_data(temp_cell);
}
fn print_read_info(&mut self) {
println!("Releasing ring buffer contents");
let released_byte_array = self.read_buffer.release_entire_buffer();
for each_array in released_byte_array.iter() {
if each_array.len() > 0 {
println!("{}", str::from_utf8(each_array.clone()));
};
};
}
}
如果我需要少于1024个字节,则返回我期望的内容。
我的想法是,因为我不知道我要求的数据是什么样的,我想要请求一定数量的字节,将其作为字节存储在缓冲区中,重复直到EOF然后读取方便。但是TcpStream方法似乎有不同的用途,但我并不完全清楚它适合读取某些数据并将其存储在某个地方以供日后使用。
我做错了什么?特别是,我想通过TCP下载一个更大的文件,而不是一个push_bytes()
。同样地,我的SimpleRingBuffer
对于嵌套向量感觉相当不平缓,这使我担心在重新分配/增长时的惩罚。