Linux 网络编程项目 —— FTP 网盘

news2024/11/25 5:38:32

文章目录

  • 项目简介
  • 知识点描述
  • 项目功能指令
    • 远程功能指令
    • 本地功能指令
  • 使用的关键函数
    • access 函数
    • popen 函数
    • chdir 函数
    • strtok 函数
    • strncmp 函数
    • linux system函数是否执行成功判断方法
  • 基本流程
    • 服务端
    • 客户端
  • FTP代码实例
    • 头文件 ftp.h
    • 客户端 client.c
    • 服务端 server.c
  • V2.0版 – 启用副服务器

项目简介

  • FTP服务器(File Transfer Protocol Server)是在互联网上提供文件存储和访问服务的计算机,它们依照FTP协议提供服务。 FTP是File Transfer Protocol(文件传输协议)。
  • 这个项目分成ftp客户端及服务端,实现的功能和Linux开源的 FTP 服务器类似,客戶端通过网络,远程获取服务端磁盘上的文件夹内容,下载文件,上传文件等功能。

知识点描述

  • FTP服务器用到的是Socket网络通信,当收到客户端接入的时候,服务器创建子进程对接连接,子进程启动后分析来自客户端的指令,服务端可同时处理多个客户端接入并对指令作出解析,并把执行结果返回给客户端。比如:收到get file1的指令,是客户端想要获取file1文件的,我先用strstr()函数进行字符串分割,获取到文件名,在判断文件是否存在,如果文件存在,就读取文件內容,再将內容通过套接字发给客户端,客户端收到数据后,创建文件,并将收到的数据写入文件,完成文件的远程下载。 (说明网络编程,字符串编程,文件编程)

  • 上传文件和下载文件类似,主要还是涉及文件的操作,字符串的操作,以及网络编程。

  • 还支持了Is、pwd、cd等Linux系统常用的指令。普通指令的实现用popen来调用系统指令,并读取执行的结构。如果不需要获取执行结果,用system函数调用就可以了。 (说明popen,system的编程)

项目功能指令

远程功能指令

  1. LS —— 展示服务端文件,用法:ls
  2. PWD —— 展示服务端的当前路径,用法:pwd
  3. CD —— 用于切换服务端的路径,用法:cd path
  4. RM —— 用于删除服务端的文件,用法:rm file
  5. GET —— 下载服务端文件至客户端本地,用法:get file
  6. PUT —— 把客户端本地文件上传至服务端,用法:put file

本地功能指令

  1. LLS —— 展示客户端本地文件,用法:lls
  2. LPWD —— 展示客户端当前路径,用法:lpwd
  3. LCD —— 用于切换客户端本地的路径,用法:lcd path
  4. LRM —— 用于删除客户端本地的文件:用法:lrm file
  5. QUIT —— 用于客户端的退出,用法:quit

使用的关键函数

access 函数

int access(const char *pathname, int mode);

功能:判断文件是否存在

参数1:

  • 文件名字

参数2:(这里用F_OK)

  • R_OK 只判断是否有读权限
  • W_OK 只判断是否有写权限
  • X_OK 判断是否有执行权限
  • F_OK 只判断是否存在

返回值:

  • 不存在返回-1

popen 函数

FILE *popen(const char *command, const char *type);
int pclose(FILE *stream); //打开后要用 pclose 关闭文件

功能:可以像打开文件一样打开 shell 指令。后续可以使用 fread 读取内容到缓冲区 buf

参数1:

  • shell 指令

参数2:

  • r 或者 w ,一般都是 r

注意:

  • popen与system的区别:popen可以将返回的结果写在文件中,system只能执行指令,返回成功与否
  • popen返回的是文件流,可以通过fread读取文件流可以写入到指定缓冲区,指令LS PWD需要用到该函数
  • system 函数直接返回结果到控制台,指令LLS LPWD 可以使用该函数,在客户端直接展示
  • RM LRM 指令因为处理完不需要看到文件情况,所以也可以直接调用 system 函数来处理,处理完成后只需要提醒客户端再次输入 LS 或者 LLS 即可查看文件变动情况。

chdir 函数

int chdir(const char *path);

功能:跳转至以参数path 指定目录

参数:

  • 指向目标目录的指针

返回值执:

  • 成功则返回0,
  • 失败返回-1, errno 为错误代码.

注意:

  • 为什么不直接调用 system 函数来跳转目录呢?因为调用 system 函数相当于 fork 出一个子进程来处理跳转目录,子进程执行了 cd 命令后改变了自己的 pwd, 但是子进程执行完后会消亡,而父进程的路径没有改变,所以不能使用 system 函数来跳转目录。

strtok 函数

char *strtok(char *str, const char *delim);

功能:字符串分隔,把参数二的字符修改为’\0’,返回其前面的字符串地址。

参数1:

  • 要分割的字符串

参数2:

  • 分隔字符
  • 指定临界点
#include <stdio.h>
#include <string.h>
 
int main()
{
    char buf[128] = "hello Linux !!!";
    char *p;
    printf("buf = %s\n", buf);
 
    p = strtok(buf, " ");
    printf("\n第一次处理: 相当于 buf = hello\\0Linux !!! \n");
    printf("p1 = %s\n", p);
    printf("buf = %s\n", buf);
 
    p = strtok(NULL, " ");
    printf("\n第二次处理:相当于 buf = hello\\0Linux\\0!!! \n");
    printf("p2 = %s\n", p);
    printf("buf = %s\n", buf);
    printf("buf + 6 = %s\n", buf + 6);
 
    p = strtok(NULL, " ");
    printf("\n第三次处理:从第一个 ! 开始,直到最后遇到\\0结束\n");
    printf("p3 = %s\n", p);
    printf("buf = %s\n", buf);
    printf("buf + 12 = %s\n", buf + 12);
 
    p = strtok(NULL, " ");
    printf("\n第四次处理:后面没有字符串,指针指向 NULL \n");
    printf("p4 = %s\n", p);
    printf("buf = %s\n", buf);
    printf("buf + 15 = %s\n", buf + 15);
    return 0;
}

输出结果
在这里插入图片描述

strncmp 函数

int strcmp(const char *s1, const char *s2);
 
int strncmp(const char *s1, const char *s2, size_t n);

功能:字符串比较。strncmp能够精确判断字符的个数

参数1:

  • 比较字符串1

参数2:

  • 比较字符串2

参数3:

  • 比较前几个是否一样

返回值:

  • 一样返回0,
  • 不一样非0

注意:

  • 为什么不用 strcmp,因为 strcmp 在判断一些需要带有文件名的指令时,如(cd xxx)不能准确判断,而 strncmp 可以准确判断前面指令的字符个数,不易出错。
  • 还有一种方案是用 strstr 函数,查看命令中是否含有特殊的指令来判断也可以。

linux system函数是否执行成功判断方法

参考博文:linux system函数是否执行成功判断方法

基本流程

服务端

  1. socket 创建服务端的套接字
  2. bind 端口号和 IP 地址
  3. listen 监听客户端的连接
  4. accept 接受客户端的接入
  5. fork 创建子进程处理客户端操作
  6. read 接收客户端发送的 cmd
  7. 服务端开始处理从客户端接收到的 cmd
  8. write 服务端处理完的 data 到客户端

客户端

  1. socket 创建客户端的套接字
  2. connect 连接上服务端,配置端口号和 IP 地址
  3. 连接成功后,获取用户键盘输入,处理输入命令 cmd
  4. write 客户端的 cmd 到服务端
  5. read 服务端处理完返回的 data

FTP代码实例

头文件 ftp.h

#define LS   0
#define LLS  1
#define PWD  2
#define CD   3
#define RM   5
#define GET  6
#define PUT  7
#define LPWD 8
#define LCD  9
#define LRM  10
 
#define QUIT 120
 
struct myFTP
{
    int set;         // 客户端返回给服务器的宏命令
    int mark;        // 判断文件是否存在的标识
    char cmd[128];   // 用户输入的命令
    char data[1024]; // 存放根据指令进行相关读取操作的 结果
};

客户端 client.c

#include "ftp.h"
#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

char *stringSplit(char *buf)
{
    char *p;
    p = (char *)malloc(128);//buf.cmd空间为128字节
    p = strtok(buf, " ");
    p = strtok(NULL, " ");
    return p;
}
 
/* 判断输入的完整指令的前几个关键指令 */
int getCommandSet(char *cmd)
{
    if (strncmp(cmd, "ls", 2) == 0)return LS;
    if (strncmp(cmd, "lls", 3) == 0)return LLS;
    if (strncmp(cmd, "pwd", 3) == 0)return PWD;
    if (strncmp(cmd, "cd", 2) == 0)return CD;
    if (strncmp(cmd, "rm", 2) == 0)return RM;
    if (strncmp(cmd, "get", 3) == 0)return GET;
    if (strncmp(cmd, "put", 3) == 0)return PUT;
    if (strncmp(cmd, "lpwd", 4) == 0)return LPWD;
    if (strncmp(cmd, "lcd", 3) == 0)return LCD;
    if (strncmp(cmd, "lrm", 3) == 0)return LRM;
    if (strncmp(cmd, "quit", 4) == 0)return QUIT;
    return -1;
}
 
/* 读取服务器处理完后 buf.data 的内容 */
void readFromServer(int c_fd, struct myFTP buf)
{
    int nread = read(c_fd, &buf, sizeof(buf));
    if (nread == -1)
    {
        perror("read");
    }
    else if (nread == 0)
    {
        printf("server quit\n");
        exit(0);
    }
    else
    {
        printf("%s", buf.data);
    }
}
 
void sendCommand(int c_fd, struct myFTP buf)
{
    buf.mark = 0; //判断文件是否存在的标识
    char *p_tmp = NULL;
    int fd;
    off_t fileSize;
 
    while (1)
    {
        memset(&buf, 0, sizeof(buf)); // 每次操作命令前都先把 buf 的内容清空,确保不会被上次操作遗留的内容影响下次操作
        printf("\n************************************************************************\n");
        printf("*****please input (ls pwd cd rm get put quit lls lpwd lcd lrm lcd)*****\n");
        printf("**************************************************************************\n");
        printf(">> ");
        gets(buf.cmd); // 从键盘获取完整命令
        printf("command:%s\n", buf.cmd);
        buf.set = getCommandSet(buf.cmd);
 
        switch (buf.set)
        {
        case LS: // 和 PWD 的处理方式一样,所以不需要 break
 
        case PWD:
            write(c_fd, &buf, sizeof(buf)); // 把 buf 结构体发送至 c_fd 给服务器处理
            readFromServer(c_fd, buf);
            break;
 
        case LLS: // 和 LPWD、LRM 的处理方式一样,所以不需要 break
        case LPWD:
 
        case LRM:
            p_tmp = buf.cmd;
            p_tmp++; // 加一是为了指向第二个字符,以第二个字符开始,屏蔽L
            system(p_tmp);
            break;
 
        case LCD:
            p_tmp = stringSplit(buf.cmd); // 字符串分割提取路径
            strcpy(buf.cmd, p_tmp);
            int ret = chdir(buf.cmd); // 切换路径
            if (ret == -1)
            {
                perror("chdir");
            }
            else
            {
                printf("chdir success\n");
            }
            break;
 
        case CD:
            p_tmp = stringSplit(buf.cmd);   // 字符串分割提取路径
            strcpy(buf.cmd, p_tmp);         // 把路径复制到 buf.cmd
            write(c_fd, &buf, sizeof(buf)); // 传整个结构体过去 c_fd 给 server
            readFromServer(c_fd, buf);      // 读取服务器操作完返回的数据
            break;
 
        case RM:
            write(c_fd, &buf, sizeof(buf)); // 把 rm xxx 传给客户端用 system 函数处理
            readFromServer(c_fd, buf);
            break;
 
        case GET:
            p_tmp = stringSplit(buf.cmd); // 提取文件名
            strcpy(buf.cmd, p_tmp);
            write(c_fd, &buf, sizeof(buf));
            read(c_fd, &buf, sizeof(buf)); // 把服务器传送过来 c_fd 处理完的内容读取到 buf 结构体
            if (buf.mark == 0)             // 判断服务器是否因为找不到目标文件而把标志位设置为 -1
            {
                fd = open(buf.cmd, O_RDWR | O_CREAT, 0777); // 打开 get 的文件,如果没有则创建文件,权限可读可写
                write(fd, buf.data, strlen(buf.data));      // 把客户端放进 buf.data 的内容写入 fd 文件
                close(fd);
                printf("get success\n");
            }
            else // 服务器因为找不到目标文件而把标志位设置为 -1
            {
                printf("%s\n", buf.data);
            }
            break;
 
        case PUT:
            p_tmp = stringSplit(buf.cmd); // 提取文件名
            strcpy(buf.cmd, p_tmp);
            if (access(buf.cmd, F_OK) == -1) // 如果找不到目标文件
            {
                buf.mark = -1; // 把标志位至 -1
                printf("NO this file\n");
                strcpy(buf.data, "NO this file\n");
                write(c_fd, &buf, sizeof(buf));
            }
            else
            {
                fd = open(buf.cmd, O_RDWR);        // 打开目标文件,权限可读可写
                fileSize = lseek(fd, 0, SEEK_END); // 移动光标至文件最后,返回值是该文件(光标前面)的字节数
                lseek(fd, 0, SEEK_SET);            // 设置光标至最前
                read(fd, buf.data, fileSize);      // 把目标文件的内容读取至 buf.data
                write(c_fd, &buf, sizeof(buf));    // 把 buf 结构体发送至 c_fd 传给服务器
                close(fd);                         // 关闭目标文件
                printf("put success\n");
            }
            break;
 
        case QUIT:
            exit(0);
            break;
 
        case -1:
            printf("error command\n");
            break;
        }
    }
}
 
int main(int argc, char *argv[])
{
    int c_fd;
    int c_Ret;
    struct myFTP buf;
    struct sockaddr_in c_addr;
    memset(&c_addr, 0, sizeof(struct sockaddr_in));
 
    if (argc != 3)
    {
        printf("input error\n");
    }
 
    // 1. socket
    c_fd = socket(AF_INET, SOCK_STREAM, 0);
    // 防止段错误
    if (c_fd == -1)
    {
        perror("socket");
        exit(-1);
    }
 
    // 2. bind   配置 struct sockaddr_in 结构体,绑定时再转换成 struct sockaddr * 结构体类型
    c_addr.sin_family = AF_INET;            /* address family: AF_INET */
    c_addr.sin_port = htons(atoi(argv[2])); /* port in network byte order */
    inet_aton(argv[1], &c_addr.sin_addr);   /* internet address */
 
    // 3. connect
    c_Ret = connect(c_fd, (struct sockaddr *)&c_addr, sizeof(struct sockaddr_in));
    // 防止段错误
    if (c_Ret < 0)
    {
        perror("connect");
        exit(-1);
    }
    else
    {
        printf("connect success\n");
        sendCommand(c_fd, buf);
    }
    close(c_fd);
 
    return 0;
}

服务端 server.c

#include "ftp.h"
#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
 
//判断一个 system 函数调用 shell 脚本是否正常结束
int System_Check(int result)
{
    if ((-1 != result) && (WIFEXITED(result)) && (!(WEXITSTATUS(result))))
        return 0;
    else
        return -1;
}
 
void commandHandler(int c_fd, struct myFTP buf, int cmd)
{
    int nread;
    int result = 0;
    int fd;
    off_t fileSize; // 文件内容大小
    buf.mark = 0;   // 0 -> 成功,   -1 -> 失败
    int ret;
    FILE *file;
 
    /* 连接到客户端后一直 while(1) 读取客户端发过来的内容进行处理 */
    while (1)
    {
        memset(&buf, 0, sizeof(buf));
        nread = read(c_fd, &buf, sizeof(buf));
 
        if (nread < 0)
        {
            perror("read");
        }
        else if (nread == 0)
        {
            printf("No.%d client quit\n", cmd);
            exit(0);
        }
        else
        {
            printf("No.%d command:> %s\n\n", cmd, buf.cmd);
 
            switch (buf.set)
            {
            case LS:
 
            case PWD:
                file = popen(buf.cmd, "r"); // popen()可以执行shell命令,并读取此命令的返回值
                fread(buf.data, 1024, 1, file);
                write(c_fd, &buf, sizeof(buf));
                pclose(file);
                break;
 
            case CD:
                ret = chdir(buf.cmd);
                if (ret == -1)
                {
                    perror("chdir");
                }
                else
                {
                    strcpy(buf.data, "chdir success! You can input ls to check!~\n");
                    write(c_fd, &buf, sizeof(buf));
                }
                break;
 
            case RM:
                result = system(buf.cmd); // system 函数处理命令 rm xxx
                if (!System_Check(result))
                {
                    strcpy(buf.data, "rm success! You can input ls to check!~\n");
                    write(c_fd, &buf, sizeof(buf));
                }
                else
                {
                    strcpy(buf.data, "rm fail\n");
                    write(c_fd, &buf, sizeof(buf));
                }
                break;
 
            case GET:
                if (access(buf.cmd, F_OK) == -1) // 如果找不到目标文件
                {
                    buf.mark = -1; // 把标志位至 -1
                    strcpy(buf.data, "NO this file\n");
                    write(c_fd, &buf, sizeof(buf));
                }
                else
                {
                    fd = open(buf.cmd, O_RDWR);        // 打开目标文件,权限可读可写
                    fileSize = lseek(fd, 0, SEEK_END); // 移动光标至文件最后,返回值是该文件(光标前面)的字节数
                    lseek(fd, 0, SEEK_SET);            // 设置光标至最前
                    read(fd, buf.data, fileSize);      // 把目标文件的内容读取至 buf.data
                    write(c_fd, &buf, sizeof(buf));    // 把 buf 结构体发送至 c_fd 传给客户端
                    close(fd);                         // 关闭目标文件
                    printf("client command: GET success!~\n");
                }
                break;
 
            case PUT:
                if (buf.mark == 0) // 判断客户端是否因为找不到目标文件而把标志位设置为 -1
                {
                    fd = open(buf.cmd, O_RDWR | O_CREAT, 0777);
                    write(fd, buf.data, strlen(buf.data));
                    close(fd);
                }
                else // 客户端因为找不到目标文件而把标志位设置为 -1
                {
                    printf("%s\n", buf.data);
                }
                break;
            }
        }
    }
}
 
int main(int argc, char *argv[])
{
    int s_fd;
    int c_fd;
    int s_Ret;
    struct myFTP buf;
    int cmd = 0;
    struct sockaddr_in s_addr;
    struct sockaddr_in c_addr;
 
    memset(&s_addr, 0, sizeof(struct sockaddr_in));
    memset(&c_addr, 0, sizeof(struct sockaddr_in));
 
    if (argc != 3)
    {
        printf("input error\n");
    }
 
    // 1. socket
    s_fd = socket(AF_INET, SOCK_STREAM, 0);
    // 防止段错误
    if (s_fd == -1)
    {
        perror("socket");
        exit(-1);
    }
 
    // 2. bind   配置 struct sockaddr_in 结构体,绑定时再转换成 struct sockaddr * 结构体类型
    s_addr.sin_family = AF_INET;            /* address family: AF_INET */
    s_addr.sin_port = htons(atoi(argv[2])); /* port in network byte order */
    inet_aton(argv[1], &s_addr.sin_addr);   /* internet address */
 
    s_Ret = bind(s_fd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr_in));
    // 防止段错误
    if (s_Ret == -1)
    {
        perror("bind");
        exit(-1);
    }
 
    // 3. listen
    s_Ret = listen(s_fd, 10);
    // 防止段错误
    if (s_Ret == -1)
    {
        perror("listen");
        exit(-1);
    }
 
    // 4. accept
    int len = sizeof(struct sockaddr_in);
    while (1)
    {
        c_fd = accept(s_fd, (struct sockaddr *)&c_addr, &len);
        if (c_fd == -1)
        {
            perror("accept");
            exit(-1);
        }
        else
        {
            cmd++;
            printf("get connect: No.%d IP:%s\n", cmd, inet_ntoa(c_addr.sin_addr));
        }
 
        if (fork() == 0)
        {
            commandHandler(c_fd, buf, cmd);
        }
    }
    close(s_fd);
    close(c_fd);
 
    return 0;
}

V2.0版 – 启用副服务器

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/47124.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何实现虹科物联网HMI/网关的调度器功能?

一、前言 JMobile软件提供了一个调度器引擎&#xff0c;通过设定的时间计划表自动执行特定动作&#xff0c;从而赋予HMI/网关调度器功能&#xff0c;减少现场操作人员的工作压力。本文主要介绍如何实现JMobile软件的调度器功能。 二、工具 1. Windows PC 2. JMobile Studio…

《论文阅读》DeepSFM: Structure From Motion Via Deep Bundle Adjustment

留个笔记自用 DeepSFM: Structure From Motion Via Deep Bundle Adjustment 做什么 首先是最基础的&#xff0c;Structure-from-Motion&#xff08;SFM&#xff09;&#xff0c;SFM可以简单翻译成运动估计&#xff0c;是一种基于dui8序列图片进行三维重建的算法。简单来说就…

C++11(三)可变模板参数、lambda表达式、包装器

&#x1f9f8;&#x1f9f8;&#x1f9f8;各位大佬大家好&#xff0c;我是猪皮兄弟&#x1f9f8;&#x1f9f8;&#x1f9f8; 文章目录一、可变模板参数1.通过递归推导参数包2.通过列表初始化推导参数包二、emplace三、lambda表达式1.lambda表达式语法2.使用lambda3.捕捉列表说…

phpstorm+wamp在线调试wordpress

简介 本文源自公司内部使用wordpress搭建了一套官网&#xff0c;经常有定制化的需求&#xff0c;有些插件实现不了&#xff0c;需要通过phpstorm调试的方式熟悉wordpress&#xff0c;同时修改php代码&#xff0c;本地测试环境window&#xff0c;适合用wamp作为php运行环境&…

解放你的双手----WIN7设置自动化任务

近期在使用双屏工具DualMonitor的时候遇到一个问题&#xff0c;每次电脑锁屏超过一定时常之后&#xff0c;登录解锁该软件虽然在运行但是功能失效了&#xff0c;需要手动关闭打开该程序&#xff0c;一时也没找到有效的解决方法和替代软件&#xff0c;于是就想着能不能在我登录解…

数据存储——存储图像

图像数字化&#xff08;一&#xff09;图像数字化1.图像采样2.数字图像的技术指标3.编码&#xff08;三&#xff09;数字图像的分类1.光栅图2.矢量图总结&#xff1a;图像数字化的过程&#xff08;一&#xff09;图像数字化 按一定空间间隔&#xff0c;自左至右&#xff0c;自…

面试系列Spring:SpringMVC的工作流程

核心组件&#xff1a; DispatcherServlet&#xff1a;前端控制器&#xff0c;负责调度其他模块执行&#xff0c;核心模块 Handler&#xff1a;处理器&#xff0c;完成具体的业务逻辑&#xff0c;相当于Servlet HandlerMapping&#xff1a;处理器映射器&#xff0c;DispatcherSe…

[世界杯]根据赔率计算各种组合可能性与赔率

目录 一、背景 二、数据输入 2.1 赔率示意图 2.2 代码 三、数据处理 3.1 计算各种组合可能性 3.2 修正概率 四、输出结果 一、背景 本文以世界杯体彩“混合过关”4场串胜平负为的赔率进行编码 其他类型如比分 、总进球数可以参考代码进行相应修改 需要的库&#xff…

Web3中文|区块链游戏的成长之痛

来源 | cointelegraph 编译 | DaliiNFTnews.com 在过去十年中&#xff0c;手机游戏已成为互动娱乐产业的重要支柱&#xff0c;得益于智能手机的普及&#xff0c;来自世界各地的用户都成为了硬核游戏玩家。 现在&#xff0c;区块链技术的出现正在推动一种范式的转变&#xff…

基于SSM的在线书城网站【附源码】

一、项目功能 1.前台功能 图书基本展示,包括推荐图书展示和类图书类型展示.推荐图书包括条幅推荐,热销推荐和新品推荐.按照图书类型展示商品.图书详细信息展示.图书加入购物车.修改购物车内图书信息,例如数量等.用户登录.用户注册.修改个人信息,包括密码和收获信息.购物车付款…

环状序列(逐行解析)(保姆式解析)(算法竞赛入门经典二)

环状序列长度为n的环状串有n种表示法&#xff0c;分别为某个位置开始顺时针得到。例如&#xff0c;图中的环状串有10种表示&#xff1a; CGAGTCAGCT,GAGTCAGCTC,AGTCAGCTCG等。在这些表示法中&#xff0c;字典序最小的称为“最小表示”。 输入一个长度为n(n<100)的环状DNA串…

leetcode 526. 优美的排列(回溯)

题目链接&#xff1a;526. 优美的排列 回溯 树型结构: 预处理 matchmatchmatch 数组&#xff08;每个位置符合条件的数有哪些&#xff09;&#xff1a; void getMatch(int n) {used.resize(n 1);match.resize(n 1);for (int i 1; i < n; i) {for (int j 1; j < n…

供应双功能螯合剂THP-Mal,THP 马来酰亚胺,CAS:1314929-99-1

一&#xff1a;产品描述 1、名称 THP-Mal THP Maleimide THP 马来酰亚胺 2、CAS编号&#xff1a;1314929-99-1 3、分子式&#xff1a;C44H57N9O13 4、分子量&#xff1a;919.41 5、外观&#xff1a;白色或者灰白色粉末 6、沸点&#xff1a;1389.365.0 C(Predicted) …

内网穿透无法访问本地wordpress网站

解决办法:在wordpress主目录下修改wp-config.php文件 增加2行代码。 define(WP_SITEURL, http:// . $_SERVER[HTTP_HOST]); define(WP_HOME, http:// . $_SERVER[HTTP_HOST]); 增加2代码的意思&#xff1a;设置网站域名为当前访问的域名&#xff0c;也就是取消了域名的绑定。…

Linux下 生成coredump文件前配置

一. Linux下coredump文件 在 Linux 系统下&#xff0c;存在一种 coredump机制。 Linux 系统下&#xff0c;在进行 C/C 开发时&#xff0c;经常会遇到程序运行突然崩溃的问题。这时可以通过离线调试即 coredump 方式进行 bug 的定位。 具体为当程序出现段错误时&#xff0c;内…

用匠心创造可期未来!与广州流辰信息科技一起携手创佳绩!

当今社会世界经济一体化趋势逐渐明朗化&#xff0c;竞争也愈发激烈&#xff0c;同时&#xff0c;这也是一个机遇与挑战并存的开放社会。在机遇面前&#xff0c;作为企业&#xff0c;要紧紧抓住机遇&#xff0c;顺势而为&#xff0c;创造辉煌佳绩&#xff1b;在挑战面前&#xf…

Hostlink读写寄存器报文分析

引言 Hostlink是欧姆龙PLC默认的串口上行通信协议&#xff0c;使用默认的通信协议可免除PLC端的配置工作&#xff0c;易于实现分工协作。下面以CP1E-E的PLC为例进行说明&#xff0c;CP系列的PLC规则都是一样的。 读离散量 请求报文 字节流 40 33 31 46 41 30 30 30 30 30 3…

[Jetson]在nvidia orin/xavier上快速配置深度学习环境(Tensorflow,Pytorch都可以参考)

本文章将介绍如何通过docker在边缘计算设备nvidia orin/xavier上快速配置深度学习环境.该方法适用于Tensorflow,Pytorch,但是本文以介绍Tensorflow的安装为主. 文章目录第一步:安装docker第二步:安装nvidia-docker2第三步:拉取tensorflow镜像3.1 确定容器版本3.2 拉取镜像3.3 测…

awk命令应用

记录&#xff1a;353 场景&#xff1a;在CentOS 7.9操作系统上&#xff0c;使用awk文本处理工具处理文本&#xff1b;使用awk、cat和grep搭配使用处理文本&#xff1b;使用awk直接处理文本&#xff1b;使用shell脚本调用awk脚本处理文本。 版本&#xff1a; 操作系统&#x…

基于神经网络彩色图像插值研究-附Matlab程序

⭕⭕ 目 录 ⭕⭕✳️ 一、引言✳️ 二、色彩过滤阵列CFA✳️ 三、BP网络结构✳️ 四、神经网络彩色图像插值实验验证✳️ 五、参考文献✳️ 六、Matlab程序获取与验证✳️ 一、引言 彩色图像插值是通过估算相邻像素来估计缺失的颜色分量的过程&#xff0c;数字相机通过色彩过滤…