Categories
php

php简介

    php原始为Personal Home Page的缩写,已经正式更名为 “PHP: Hypertext Preprocessor”。

    php依赖php运行容器即php进程,通过该进程对php文件进行输入处理,在 标准输出流 返回输出结果。特点运行简单,无需编译。在web容器下,每个请求都会产生一个php进程,所以只需把php文件更改后,立即访问该php文件,即可看见最新的更改(每发送一个请求,产生了新的进程重新读取文件)。调试十分方便。

运行php环境有多种方法

    1:通过php命令

    php -f “xxx.php” 通过指定需要加载php文件,开启php进程,在控制台标准输出流看到该文件的输出。

    php -s localhost:8080 (-t “项目文件夹”) 通过-t 指定php文件的文件夹,默认为当前进程执行文件夹目录。浏览器访问localhost:8080通过文件系统路径访问对应的文件(默认为index.php),即可在浏览器看到对应文件的输出。这个就是把php进程的输出流打在web容器的请求输出上,所以能在浏览器看到输出

    2:通过web容器访问。其实就是通过web容器执行请求输入到socket中(文件socket或端口socket都可)。服务器开启php-fpm服务,监听对应的socket作为进程输入,将php-fpm的标准输出流打在socket上供web容器读取。web容器再把socket的读取的内容作为请求响应返回给用户。(这就是标准的cgi做法,以进程标准输入流接受请求,标准输出流产生响应,一个请求就是一个进程)。

    nginx配置:

location ~ .php$ {
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}

    apache配置:

LoadModule php7_module “${INSTALL_DIR}/bin/php/php7.1.9/php7apache2_4.dll”

<IfModule php7_module>
    DirectoryIndex index.php index.php3 
AddType application/x-httpd-php .php
    AddType application/x-httpd-php .php3
</IfModule>
Categories
linux

emmc烧写后 文件系统扩容

lsblk                         # 查看磁盘和分区信息
df -h                         # 查看文件系统使用情况

输出

NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
mmcblk0     179:0    0   64G  0 disk
├─mmcblk0p1 179:1    0  256M  0 part /boot
└─mmcblk0p2 179:2    0    8G  0 part /         # 仅用了 8G,剩余空间未分配

/ 代表的就是跟文件系统分区 要扩容就是这个分区扩容

sudo resize2fs /dev/mmcblk0p2  # 扩展 ext4 文件系统
Categories
linux

rootfs.img 修改root账号密码 并设置允许ssh访问

sudo mount -o loop rootfs.img ~/mount_dir

挂载镜像到某个目录

修改root账号密码

sudo vim /etc/shadow

修改密码文件

root:!:19475:0:99999:7:::

!或*代表该账号无法登录

数据段说明

用户名:加密密码:最后修改时间:最小密码年龄:最大密码年龄:警告期:不活动期:过期时间:保留字段
mkpasswd -m sha-512

执行该命令然后输入密码 替换上面的加密密码段

修改ssh配置允许root访问

/etc/ssh/sshd_config

修改配置文件

PermitRootLogin yes  # 修改后重启 SSH 服务:sudo systemctl restart sshd

设置允许root 密码登录

Categories
linux

uboot kernel rootfs 关系

在嵌入式Linux系统中,U-Boot、Kernel(内核)和Rootfs(根文件系统) 是三个核心组件,它们分工协作,共同完成系统启动和运行。以下是它们的相互关系和作用:


1. U-Boot(Bootloader)

  • 作用:硬件初始化、引导加载内核。
  • 功能
    • 初始化CPU、内存、时钟等硬件。
    • 提供交互式命令行(可选),用于调试或配置启动参数。
    • 从存储设备(如eMMC、SD卡、Flash)加载内核镜像(zImageuImage)和设备树(dtb)到内存。
    • 传递启动参数(如根文件系统位置、控制台设备等)给内核。
  • 输出:将控制权移交内核。

2. Kernel(Linux内核)

  • 作用:管理系统硬件资源、提供核心服务。
  • 功能
    • 进一步初始化硬件(如驱动加载、中断管理)。
    • 挂载根文件系统(Rootfs)到 / 目录。
    • 启动用户空间的第一个进程(通常是 init 或 systemd,PID=1)。
  • 依赖:需要U-Boot正确加载内核镜像,并传递正确的启动参数(如root= 指定Rootfs位置)。

3. Rootfs(根文件系统)

  • 作用:提供用户空间环境和应用程序运行基础。
  • 内容
    • 系统工具(如/bin/sbin)。
    • 配置文件(如/etc)。
    • 库文件(如/lib)。
    • 用户程序(如/usr)。
  • 挂载时机:由内核根据启动参数(如root=/dev/mmcblk0p2)挂载。
  • 关键文件/sbin/init 或 /lib/systemd/systemd(第一个用户进程)。

三者的协作流程

  1. 硬件上电 → U-Boot执行,初始化硬件。
  2. U-Boot 加载内核镜像和设备树到内存,传递参数(如console=ttyS0 root=/dev/nfs)。
  3. 内核 启动,解压自身并初始化子系统(进程调度、驱动等)。
  4. 内核 挂载Rootfs(从Flash、NFS、RAM等设备)。
  5. 内核 启动Rootfs中的init进程,进入用户空间,完成系统启动。

关键依赖关系

  • U-Boot依赖:需适配硬件(如DDR初始化代码、存储驱动)。
  • 内核依赖:需匹配硬件架构(如ARM/X86)和U-Boot传递的参数。
  • Rootfs依赖:需包含内核驱动的对应模块(如文件系统驱动、设备节点)。

常见问题

  • 启动失败:若U-Boot未正确加载内核,系统无法启动。
  • 内核恐慌(Kernel Panic):通常因找不到或无法挂载Rootfs。
  • Rootfs损坏:系统可能启动但无法进入用户空间(如/bin/sh缺失)。

类比理解

  • U-Boot:像电脑的BIOS,负责“唤醒”硬件。
  • Kernel:像操作系统内核,管理硬件和资源。
  • Rootfs:像C盘的Windows系统文件,提供运行环境。

通过三者协同,嵌入式系统从硬件上电到完整启动,最终运行应用程序。

Categories
rust

Rust 异步编程

第一步 安装tokio库

cargo add tokio --features full
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // 绑定到本地地址的8080端口
    let listener = TcpListener::bind("127.0.0.1:8080").await?;
    println!("服务器正在监听 127.0.0.1:8080");

    loop {
        // 等待新的连接
        let (socket, addr) = listener.accept().await?;
        println!("接收到来自 {} 的新连接", addr);

        // 为每个连接生成一个新任务
        tokio::spawn(async move {
            if let Err(e) = handle_connection(socket).await {
                println!("处理连接时出错: {}", e);
            }
        });
    }
}

async fn handle_connection(mut socket: TcpStream) -> Result<(), Box<dyn Error>> {
    // 创建一个缓冲区来存储数据
    let mut buf = [0; 1024];

    loop {
        // 读取数据
        let size = match socket.read(&mut buf).await {
            // 客户端关闭了连接
            Ok(size) if size == 0 => return Ok(()),
            Ok(size) => size,
            Err(e) => {
                return Err(e.into());
            }
        };

        let data = &buf[..size];
        let received = String::from_utf8_lossy(data);
        println!("Received data: {}", received);
        // 检查是否是telnet的断开命令(IAC IP)
        if size >= 3 && buf[0] == 255 && buf[1] == 244 {
            println!("Detected telnet disconnect command (IAC IP)");
             //显示关闭连接并且传播异常
            socket.shutdown().await?;
            //这个也能退出事件循环 关闭连接
            return Ok(());
        }
        
        // 检查普通ASCII的CTRL+C (3)
        if buf[..size].contains(&3) {
            println!("Detected CTRL+C, closing connection");
            //显示关闭连接并且传播异常
            socket.shutdown().await?;
            //这个也能退出事件循环 关闭连接
            return Ok(());
        }

        println!("接收到 {} 字节数据", size);

        // 将数据写回客户端
        if let Err(e) = socket.write_all(&buf[0..size]).await {
            return Err(e.into());
        }
    }
}
Categories
Uncategorized

K3S

本地 kubernetes dashboard访问路径 https://kubernetes.local/

本地nexus访问路径 http://nexus.local/

本地kibana访问路径 http://kibana.local/app/home

本地grafana访问路径 http://grafana.local/

Categories
Uncategorized

Blender 3D打印

使用blender画模型后

导出STL文件 然后bamboo connect 加载STL发送打印任务到 3D打印机

Categories
rust

Rust 网络编程

服务端代码:socket阻塞循环读

use std::io::{Read, Write};
use std::net::{TcpListener,TcpStream};
use std::thread;

fn handle_client(mut stream: TcpStream) {
    let mut buffer = [0; 1024];

    loop {
        match stream.read(&mut buffer) {
            Ok(0) => {
                // 客户端关闭连接
                println!("Client disconnected");
                break;
            }
            Ok(size) => {
                // 读取到数据,回显给客户端
                let data = &buffer[..size];
                let received = String::from_utf8_lossy(data);
                println!("Received data: {}", received);
                // 检查是否是telnet的断开命令(IAC IP)
                if size >= 3 && buffer[0] == 255 && buffer[1] == 244 {
                    println!("Detected telnet disconnect command (IAC IP)");
                    if let Err(e) = stream.shutdown(std::net::Shutdown::Both) {
                        println!("Error shutting down stream: {}", e);
                    }
                    break;
                }
                
                // 检查普通ASCII的CTRL+C (3)
                if buffer[..size].contains(&3) {
                    println!("Detected CTRL+C, closing connection");
                    if let Err(e) = stream.shutdown(std::net::Shutdown::Both) {
                        println!("Error shutting down stream: {}", e);
                    }
                    break;
                }

                 if let Err(e) = stream.write_all(&buffer[..size]) {
                    println!("Error writing to stream: {}", e);
                    break;
                }
            }
            Err(e) => {
                // 发生错误,关闭连接
                println!("Error: {}", e);
                break;
            }
        }
    }
}

fn main() {
    let listener = TcpListener::bind("127.0.0.1:65432").unwrap();
    println!("Server listening on 127.0.0.1:65432");

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                // 为每个客户端连接创建一个新线程
                thread::spawn(move || {
                    handle_client(stream);
                });
            }
            Err(e) => {
                println!("Error accepting stream: {}", e);
                break;
            }
        }
    }

    // 注意:在实际应用中,应该优雅地关闭监听器,比如监听一个关闭信号。
    // 这里为了简化,直接退出主循环后程序将结束。
}

client 端代码

use std::io::{self, Read, Write};
use std::net::TcpStream;

fn main() -> io::Result<()> {
    let mut stream = TcpStream::connect("127.0.0.1:65432")?;
    println!("Connected to server!");
    
    loop {
        let mut input = String::new();
        io::stdin().read_line(&mut input)?;
        
        if input.contains('\x03') { // CTRL+C
            println!("Sending CTRL+C to server");
            stream.write_all(input.as_bytes())?;
            break;
        }
        
        stream.write_all(input.as_bytes())?;
        
        let mut buffer = [0; 1024];
        let size = stream.read(&mut buffer)?;
        if size == 0 {
            println!("Server closed connection");
            break;
        }
        
        println!("Server echo: {}", String::from_utf8_lossy(&buffer[..size]));
    }
    
    Ok(())
}
Categories
rust

Rust 进程/线程处理

Categories
rust

Rust 文件系统

use std::fs::OpenOptions;
use std::io::prelude::*;
use std::path::Path;

fn main() -> std::io::Result<()> {
    let file_path = Path::new("hello.txt");
    
    let mut file = OpenOptions::new()
        .create(true)
        .append(true)
        .open(file_path)?;
        
    file.write_all(b"Hello, World!\n")?;
    
    println!("成功追加内容到文件: {}", file_path.display());
    Ok(())
}

创建文件并且写入


fn read() -> Result<(), Box<dyn Error>> {
    let file_path = Path::new("hello.txt");
    
    match File::open(file_path) {
        Ok(mut file) => {
            let mut contents = String::new();
            file.read_to_string(&mut contents)?;
            println!("文件内容:\n{}", contents);
        }
        Err(e) => eprintln!("无法打开文件: {}", e),
    }
    
    Ok(())
}

读取文件

Categories
rust

Rust 流