use std::io;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
pub async fn run_proxy(listen_addr: &str) -> io::Result<()> {
let listener = TcpListener::bind(listen_addr).await?;
println!("代理服务器启动,监听地址: {}", listen_addr);
loop {
let (client_stream, client_addr) = listener.accept().await?;
println!("收到来自 {} 的连接", client_addr);
tokio::spawn(async move {
if let Err(e) = handle_client(client_stream).await {
eprintln!("处理客户端连接时出错: {}", e);
}
});
}
}
async fn handle_client(mut client_stream: TcpStream) -> io::Result<()> {
let mut buffer = [0; 1024];
let n = client_stream.read(&mut buffer).await?;
if n == 0 {
return Ok(());
}
let request = String::from_utf8_lossy(&buffer[..n]);
println!("收到请求:\n{}", request);
let target_addr = parse_target_addr(&request).unwrap_or_else(|| "httpbin.org:80".to_string());
println!("连接到目标服务器: {}", target_addr);
let mut target_stream = TcpStream::connect(&target_addr).await?;
target_stream.write_all(&buffer[..n]).await?;
let (mut client_read, mut client_write) = client_stream.split();
let (mut target_read, mut target_write) = target_stream.split();
let client_to_target = tokio::io::copy(&mut client_read, &mut target_write);
let target_to_client = tokio::io::copy(&mut target_read, &mut client_write);
tokio::try_join!(client_to_target, target_to_client)?;
Ok(())
}
fn parse_target_addr(request: &str) -> Option<String> {
for line in request.lines() {
if line.starts_with("GET ") || line.starts_with("POST ") || line.starts_with("HEAD ") {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() >= 2 {
let url = parts[1];
if url.starts_with("http://") {
let url = &url[7..]; let host_port: Vec<&str> = url.split('/').collect();
return Some(host_port[0].to_string());
}
}
} else if line.to_lowercase().starts_with("host: ") {
let host = line[6..].trim();
return Some(format!("{}:80", host));
}
}
None
}
#[tokio::main]
async fn main() -> io::Result<()> {
let listen_addr = "127.0.0.1:8080";
println!("启动简单的TCP代理服务器...");
run_proxy(listen_addr).await
}