最近在学习rust,大概看了看基础语法过后,写了几个小demo,感觉不是很过瘾。这时发现手册上有tcp的封装,自己做了好几年php,还从来没有自己实现过http的接收和返回,于是动手整了个demo。往这里发一发自己的写法,主要是学习rust语言的语法,请大神不要笑我就行。
大概看了下http的协议内容,主要是文件请求方法的,请求头和相应头的定义,标准化请求和相应内容。这些先全部抛开,整一个能够正常接受到请求并且能够成功返回到例子,作为第一步学习的目的就到了。
所以第一步就是从tcp请求中获取到请求内容。
首先在main函数中定义tcp监听器,申明ip和端口,然后用for in 获取每一个请求,然后用其他函数来处理
let ip = "127.0.0.1:8080"; //监听ip和端口
let listener = TcpListener::bind(ip).expect("没能创建监听");
info!("服务器正在监听 [http://{}]", ip);
for stream in listener.incoming() {
match stream {
Ok(stream) => match handle_connection(stream) {
Ok(_) => (),
Err(e) => error!("链接处理错误 {}", e),
},
Err(e) => error!("链接错误: {}", e),
}
}
然后申明一块缓存读取请求的内容,为什么要申明缓存呢,明明可以直接放过去,主要是想到一个get请求的url最大可能会有2k,这里也是限制一下。然后将缓存的这个数组转换成字符串,接着下一步。
let mut buffer = [0; 512];
let request = String::from_utf8_lossy(&buffer[..]);
讲真rest这语言的变量是真的要求严谨,写惯了php真的不习惯。尤其是字符串操作,简直复杂。
从客户端传到服务器的内容一半是 method url http版本 .......后面跟请求头,这次只是先写个简单能处理get请求的就行,像post,put,patch,delete,option这些之后再说。
go on
下一步就是解析请求 既然只搞get,这一步就很简单,用空格把字符拆成迭代器就行。然后就跟着next(),就能依次获取到 method,url,和http版本。
let mut parts = request.split_ascii_whitespace();
接着通过url定位获取文件地址,用fs获取文件内容,然后拼接相应头,往会丢就行。
let content = fs::read_to_string(&request.file_path).unwrap();
let response = format!("HTTP/1.1 200 OK \\r\\n\\r\\n{}", content);
这里有个小小的地方,就是文件不存在怎么办。先默认写一个404.html,然后只要文件不存在就返回这个,再加上一个404的状态码。
if !Path::new(&file_path).exists() {
let content = fs::read_to_string("404.html").unwrap();
}
let response = format!("HTTP/1.1 404 Not Found \\r\\n\\r\\n{}", content);
ok,这次就先写到这里。后续还有很多内容,边学边写算了,先插个眼。
还有:
- 其他请求方法
- 其他异常返回
- 多进程处理请求
......