HTTP服务器基础的监听和响应
This commit is contained in:
parent
4bebc4d45e
commit
0597ace088
161
c/test/main.c
161
c/test/main.c
@ -1,164 +1,15 @@
|
|||||||
//头文件
|
|
||||||
#include<stdio.h>
|
#include<stdio.h>
|
||||||
#include <windows.h>
|
|
||||||
#include <conio.h>
|
|
||||||
#include<time.h>
|
#include<time.h>
|
||||||
|
#include<windows.h>
|
||||||
|
#include<stdlib.h>
|
||||||
|
|
||||||
//自定义头文件
|
#define aa 2
|
||||||
#include "founction_statement_page.h"//界面
|
|
||||||
#include "function_statement_effect.h"//功能
|
|
||||||
|
|
||||||
//初始化全局变量
|
void main(){
|
||||||
bool pick_revision = true;//初始化文件是否修改
|
int a=1,b=2;
|
||||||
bool pick_view_mode = false;//视图模式
|
if(a==aa-1||b==2){
|
||||||
unsigned int Total = 0;//初始化学生总数
|
|
||||||
|
|
||||||
static struct Snake
|
|
||||||
{
|
|
||||||
//0为y,1为x
|
|
||||||
int head[2];
|
|
||||||
int body[2];
|
|
||||||
int tail[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct Snake snake ;
|
|
||||||
|
|
||||||
static void main_printf_view ( void )//主页菜单
|
|
||||||
{
|
|
||||||
HideCursor ( );//隐藏光标
|
|
||||||
system ( "cls" );//清屏
|
|
||||||
|
|
||||||
CursorJump ( 8 , 50 );
|
|
||||||
color ( 2 );//设置颜色
|
|
||||||
printf ( "欢迎使用学生管理系统" );
|
|
||||||
CursorJump ( 9 , 48 );
|
|
||||||
color ( 4 );//设置颜色
|
|
||||||
printf ( "按下相应按键进入对应模式" );
|
|
||||||
|
|
||||||
CursorJump ( 10 , 47 );
|
|
||||||
for ( int i = 0 ; i < 26 ; ++ i )
|
|
||||||
{
|
|
||||||
color ( 7 );//设置颜色
|
|
||||||
printf ( "-" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CursorJump ( 11 , 52 );
|
|
||||||
color ( 1 );//设置颜色
|
|
||||||
printf ( "[Enter]" );
|
|
||||||
color ( 7 );//设置颜色
|
|
||||||
printf ( " 进入程序\n" );
|
|
||||||
CursorJump ( 12 , 52 );
|
|
||||||
color ( 1 );//设置颜色
|
|
||||||
printf ( "[M]" );
|
|
||||||
color ( 7 );//设置颜色
|
|
||||||
printf ( "\t 管理课程" );
|
|
||||||
|
|
||||||
CursorJump ( 13 , 52 );
|
|
||||||
color ( 1 );//设置颜色
|
|
||||||
printf ( "[ESC]" );
|
|
||||||
color ( 7 );//设置颜色
|
|
||||||
printf ( " 退出程序\n" );
|
|
||||||
|
|
||||||
for ( int i = 6 ; i <= 15 ; ++ i )
|
|
||||||
{
|
|
||||||
for ( int j = 45 ; j <= 74 ; ++ j )
|
|
||||||
{
|
|
||||||
if ( i == 6 || i == 15 || j == 45 || j == 74 )
|
|
||||||
{
|
|
||||||
CursorJump ( i , j );
|
|
||||||
color ( 7 );//设置颜色
|
|
||||||
printf ( "■" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void main_move_snake(void)//移动小蛇
|
|
||||||
{
|
|
||||||
Sleep (80);
|
|
||||||
CursorJump ( snake.tail[0] , snake.tail[1] );
|
|
||||||
printf (" ");
|
|
||||||
snake.tail[0]=snake.body[0];
|
|
||||||
snake.tail[1]=snake.body[1];
|
|
||||||
snake.body[0]=snake.head[0];
|
|
||||||
snake.body[1]=snake.head[1];
|
|
||||||
if(snake.head[0]==6&&snake.head[1]<74)
|
|
||||||
{
|
|
||||||
snake.head[1]++;
|
|
||||||
}
|
|
||||||
else if(snake.head[1]==74&&snake.head[0]<15)
|
|
||||||
{
|
|
||||||
snake.head[0]++;
|
|
||||||
}
|
|
||||||
else if(snake.head[0]==15&&snake.head[1]>45)
|
|
||||||
{
|
|
||||||
snake.head[1]--;
|
|
||||||
}
|
|
||||||
else if(snake.head[1]==45&&snake.head[0]>7)
|
|
||||||
{
|
|
||||||
snake.head[0]--;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
snake.tail[0]=6;
|
|
||||||
snake.tail[1]=45;
|
|
||||||
snake.body[0]=6;
|
|
||||||
snake.body[1]=46;
|
|
||||||
snake.head[0]=6;
|
|
||||||
snake.head[1]=47;
|
|
||||||
main_printf_view();
|
|
||||||
}
|
|
||||||
color ( 13 );//设置颜色
|
|
||||||
CursorJump ( snake.tail[0] , snake.tail[1] );
|
|
||||||
printf ("□");
|
|
||||||
CursorJump ( snake.body[0] , snake.body[1] );
|
|
||||||
printf ("□");
|
|
||||||
CursorJump ( snake.head[0] , snake.head[1] );
|
|
||||||
printf ("■");
|
|
||||||
}
|
|
||||||
|
|
||||||
//主函数
|
|
||||||
int main ( void )
|
|
||||||
{
|
|
||||||
//定义变量
|
|
||||||
static char start_pick = '0';//开始的选择
|
|
||||||
snake.head[0]=7;
|
|
||||||
snake.head[1]=45;
|
|
||||||
srand ( ( unsigned ) time ( NULL ) );
|
|
||||||
while ( 1 )
|
|
||||||
{
|
|
||||||
main_move_snake();//移动小蛇
|
|
||||||
//获取用户的输入
|
|
||||||
if ( _kbhit ( ) )
|
|
||||||
{
|
|
||||||
start_pick = ( char ) _getch ( );
|
|
||||||
}
|
|
||||||
//判断用户输入
|
|
||||||
switch ( start_pick )
|
|
||||||
{
|
|
||||||
case ENTER:
|
|
||||||
{
|
|
||||||
start_pick = '0';
|
|
||||||
system_start ( );//管理系统主页
|
|
||||||
snake.head[0]=7;
|
|
||||||
snake.head[1]=45;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'm':
|
|
||||||
case 'M':
|
|
||||||
{
|
|
||||||
start_pick = '0';
|
|
||||||
course_start ( );//管理系统主页
|
|
||||||
snake.head[0]=7;
|
|
||||||
snake.head[1]=45;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ESC:
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
84
rust/temp/src/core/mod.rs
Normal file
84
rust/temp/src/core/mod.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
use tokio::io::{AsyncReadExt};
|
||||||
|
use tokio::{net, runtime};
|
||||||
|
use crate::request::{Method,Request};
|
||||||
|
use crate::route::{Route};
|
||||||
|
use crate::respond::{Respond};
|
||||||
|
|
||||||
|
pub struct Server {
|
||||||
|
listener_addr: &'static str,
|
||||||
|
listener_port: i32,
|
||||||
|
status: bool,
|
||||||
|
routes:RwLock<Vec<Route>>,
|
||||||
|
}
|
||||||
|
impl Server {
|
||||||
|
pub fn new(listener_port:i32) -> Arc<Self> {
|
||||||
|
if listener_port < 1 || listener_port > 65535 {
|
||||||
|
panic!("listener port must be between 1 and 65535");
|
||||||
|
}
|
||||||
|
Arc::new(
|
||||||
|
Self {
|
||||||
|
listener_addr: "127.0.0.1",
|
||||||
|
listener_port,
|
||||||
|
status: false,
|
||||||
|
routes: RwLock::new(Vec::new()),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn start(self: Arc<Self>) {
|
||||||
|
let address=format!("{}:{}", self.listener_addr, self.listener_port);
|
||||||
|
let rt = runtime::Runtime::new().unwrap();
|
||||||
|
println!("Listening on {}", address);
|
||||||
|
let listener =rt.block_on(async { net::TcpListener::bind(address).await.expect("Failed to bind listener") });
|
||||||
|
rt.block_on(self.receive(listener));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Server {
|
||||||
|
async fn receive(self:Arc<Self>,listener:net::TcpListener) {
|
||||||
|
loop {
|
||||||
|
let (mut socket, _) = listener.accept().await.expect("Failed to accept connection");
|
||||||
|
let server = self.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let mut buf = [0; 1024];
|
||||||
|
if let Err(e) = socket.read(&mut buf).await {
|
||||||
|
println!("Failed to read from socket: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let content = match String::from_utf8(buf.to_vec()) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e1) => {
|
||||||
|
println!("Failed to convert buffer to string: {}", e1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let request = match Request::build(content) {
|
||||||
|
Some(req) => req,
|
||||||
|
None => {
|
||||||
|
println!("Request parsing failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let respond=Respond::build(socket);
|
||||||
|
for route in server.routes.read().expect("Unable to read route").iter() {
|
||||||
|
if request.method() == &route.method {
|
||||||
|
(route.function)(request, respond);
|
||||||
|
return;
|
||||||
|
}else {
|
||||||
|
println!("Request parsing failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Server {
|
||||||
|
pub fn route(self:&Arc<Self>, path: &'static str, method: &'static str, function: impl Fn(Request, Arc<Respond>) + Send + Sync + 'static) {
|
||||||
|
let test_method=method.to_uppercase().as_str().into();
|
||||||
|
if test_method == Method::Uninitialized {panic!("该方法未被定义")}
|
||||||
|
let route = Route { path, method:test_method, function: Box::new(function) };
|
||||||
|
self.routes.write().expect("Route write failed").push(route);
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,14 @@
|
|||||||
extern crate wasm_bindgen;
|
use core::Server;
|
||||||
|
mod core;
|
||||||
|
mod request;
|
||||||
|
mod respond;
|
||||||
|
mod route;
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
fn main() {
|
||||||
|
let server = Server::new( 8000);
|
||||||
#[wasm_bindgen]
|
server.route("/","get",|request, respond| {
|
||||||
extern {
|
respond.send();
|
||||||
pub fn alert(s: &str);
|
println!("{}",request.method())
|
||||||
}
|
});
|
||||||
|
server.start();
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn greet(name: &str) {
|
|
||||||
alert(&format!("Hello, {}!", name));
|
|
||||||
}
|
}
|
102
rust/temp/src/request/mod.rs
Normal file
102
rust/temp/src/request/mod.rs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::Display;
|
||||||
|
pub enum Method {
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Uninitialized
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Method {
|
||||||
|
fn from(s: &str) -> Method {
|
||||||
|
match s{
|
||||||
|
"GET" => Method::Get,
|
||||||
|
"POST" => Method::Post,
|
||||||
|
_ => Method::Uninitialized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Method {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
let method = match self {
|
||||||
|
Method::Get => {"GET"}
|
||||||
|
Method::Post => {"POST"}
|
||||||
|
Method::Uninitialized => {"Uninitialized"}
|
||||||
|
};
|
||||||
|
write!(f, "{}", method)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Method {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(Method::Get, Method::Get) => true,
|
||||||
|
(Method::Post, Method::Post) => true,
|
||||||
|
(Method::Uninitialized, Method::Uninitialized) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Version {
|
||||||
|
V1_1,
|
||||||
|
Uninitialized
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Version {
|
||||||
|
fn from(s: &str) -> Version {
|
||||||
|
match s {
|
||||||
|
"HTTP/1.1" => Version::V1_1,
|
||||||
|
_ => Version::Uninitialized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Resource{
|
||||||
|
Path(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Request{
|
||||||
|
method: Method,
|
||||||
|
version: Version,
|
||||||
|
resource: Resource,
|
||||||
|
headers: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Request{
|
||||||
|
pub fn build(content:String) -> Option<Request>{
|
||||||
|
let mut content =content.lines();
|
||||||
|
|
||||||
|
let request_line =content.next().unwrap_or("");
|
||||||
|
if request_line.is_empty(){return None}
|
||||||
|
let request_line:Vec<_> = request_line.split_whitespace().collect();
|
||||||
|
if request_line.len()<3 {return None}
|
||||||
|
let method=request_line[0];
|
||||||
|
let resource=request_line[1];
|
||||||
|
let version=request_line[2];
|
||||||
|
if method.is_empty()||resource.is_empty()||version.is_empty() {return None}
|
||||||
|
|
||||||
|
let mut headers =HashMap::<String, String>::new();
|
||||||
|
for i in content {
|
||||||
|
if i.len()==0 { break;}
|
||||||
|
let parts:Vec<&str> = i.split(": ").collect();
|
||||||
|
if parts.len() == 2 {
|
||||||
|
headers.insert(parts[0].to_string(), parts[1].to_string());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(Request{
|
||||||
|
method: method.into(),
|
||||||
|
version: version.into(),
|
||||||
|
resource: Resource::Path(resource.to_string()),
|
||||||
|
headers,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Request {
|
||||||
|
pub fn method(&self) -> &Method {
|
||||||
|
&self.method
|
||||||
|
}
|
||||||
|
}
|
60
rust/temp/src/respond/mod.rs
Normal file
60
rust/temp/src/respond/mod.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
use tokio::io::AsyncWriteExt;
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
use tokio::task;
|
||||||
|
|
||||||
|
pub struct Respond<'a>{
|
||||||
|
version:&'a str,
|
||||||
|
status_code:&'a str,
|
||||||
|
status_message:&'a str,
|
||||||
|
headers:HashMap<&'a str, &'a str>,
|
||||||
|
body:&'a str,
|
||||||
|
socket:Arc<Mutex<TcpStream>>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Respond<'_> {
|
||||||
|
pub fn build(socket: TcpStream) -> Arc<Respond<'static>> {
|
||||||
|
Arc::new(Respond {
|
||||||
|
version: "HTTP/1.1",
|
||||||
|
status_code: "200",
|
||||||
|
status_message: "OK",
|
||||||
|
headers: HashMap::new(),
|
||||||
|
body: "Hello, world!",
|
||||||
|
socket: Arc::new(Mutex::new(socket))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn format_message(self:Arc<Self>) -> String {
|
||||||
|
let mut massage =String::new();
|
||||||
|
let status_line= format!("{} {} {}\r\n", self.status_message,self.version,self.status_message);
|
||||||
|
massage.push_str(&status_line);
|
||||||
|
let mut header =String::new();
|
||||||
|
for (key, value) in self.headers.iter() {
|
||||||
|
header += &format!("{}: {}\r\n", key, value);
|
||||||
|
}
|
||||||
|
massage.push_str("\n\n");
|
||||||
|
massage.push_str(self.body);
|
||||||
|
massage
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(self: Arc<Self>) {
|
||||||
|
let socket = self.socket.clone();
|
||||||
|
let message = self.format_message();
|
||||||
|
|
||||||
|
task::spawn(async move {
|
||||||
|
let mut socket = socket.lock().await;
|
||||||
|
if let Ok(_) = socket.write_all(message.as_ref()).await {
|
||||||
|
if let Err(e) = socket.flush().await {
|
||||||
|
println!("Failed to flush: {}", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("Failed to send content");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
10
rust/temp/src/route/mod.rs
Normal file
10
rust/temp/src/route/mod.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use crate::request::{Method, Request};
|
||||||
|
use crate::respond::{Respond};
|
||||||
|
|
||||||
|
pub(crate) struct Route {
|
||||||
|
pub path: &'static str,
|
||||||
|
pub method: Method,
|
||||||
|
pub function: Box<dyn Fn(Request,Arc<Respond>) + Send + Sync>,
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user