HTTP服务器基础的监听和响应

This commit is contained in:
lsy 2024-10-21 00:44:50 +08:00
parent 4bebc4d45e
commit 0597ace088
6 changed files with 277 additions and 169 deletions

View File

@ -1,164 +1,15 @@
//头文件 #include<stdio.h>
#include <stdio.h> #include<time.h>
#include <windows.h> #include<windows.h>
#include <conio.h> #include<stdlib.h>
#include <time.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
View 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);
}
}

View File

@ -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));
}

View 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
}
}

View 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");
}
});
}
}

View 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>,
}