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

2023-05-16

文章目录

  • 项目简介
  • 知识点描述
  • 项目功能指令
    • 远程功能指令
    • 本地功能指令
  • 使用的关键函数
    • 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函数调用就可以了。

项目功能指令

远程功能指令

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

执行校验:

md5sum test.txt  
#注1:结果为12列。第一列是md5值,第二列是md5值对应的文件名 
  • md5sum命令采用MD5报文摘要算法(128位)计算和检查文件的校验和。
  • 一般来说,安装了Linux后,就会有md5sum这个工具,直接在命令行终端直接运行。
  • linux中每个文件都会有1个md5值。当两个文件的md5值相同,表示这两个文件完全相同。

V2.0版 – 启用副服务器

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux 网络编程项目 —— FTP 网盘 的相关文章

  • iftop 较全

    iftop nBNP nbsp i nbsp enp2s0 nbsp f dst port 6379 可以使用iftop命令的 f选项来过滤指定的端口 该选项允许您指定BPF过滤器规则 用于仅显示符合规则的流量 例如 以下命令将仅显示目标端
  • 随机生成slam 真值和里程计值的 g2o 文件(python实现)

    生成了slam 里程计的真值和里程计的值 并保存顶点和边为 g2o文件 nbsp 随机生成slam 真值和里程计值的 g2o 文 件 gen test data py import numpy as np import matplotlib
  • 滑膜+pid+上层设计下层平均分配 优化分配 动态载荷分配

    滑膜 43 pid 43 上层设计下层平均分配 优化分配 动态载荷分配 xff0c 分布式电动汽车操稳控制 本研究在matlab simulink建立七自由度轮毂电机驱动汽车模型 xff0c 使用滑膜联合控制以及pid控制实现转向过程中质心
  • 12本Python书籍推荐

    Python是用于各种任务和领域的优秀编程语言之一 Python的用户友好性 xff0c 高级特性以及对简单性和增强代码可读性的强调使其成为全球许多开发人员的理想选择 诸如此类的功能使应用程序开发 xff0c 数据科学 xff0c 人工智能
  • Ubuntu 屏幕翻转90度怎么恢复

    笔记本电脑的 ubuntu 屏幕有时候会无意中90度翻转 xff0c 这时候你只能侧着脸看 xff0c 靠鼠标操作想要恢复是极其尴尬的一件事 xff0c 最快捷的方法就用命令是删除 iio sensor proxy 程序 第一步 Ctrl
  • 使用Python+Opencv从摄像头逐帧读取图片保存在本地

    今天测试的时候 xff0c 遇到了一个问题 xff0c 测试需求是 xff0c 需要把摄像头拍摄的实时视频逐帧率保存下来 经过查阅资料以及网友帮助 xff0c 目前已经完成 记录下来希望可以帮助有需要的朋友 1 思路 使用Python 43
  • vscode 运行C++

    本文先介绍了windows下 VSCODE运行C 43 43 前 xff0c 搭建C 43 43 运行环境的必要步骤 后介绍了tasks json launch json的作用 xff0c 并给出了自己使用的配置方案 最后给出了常见问题的解
  • 在执行launch文件时,如果显示不存在这个package

    在执行launch文件时 xff0c 如果显示不存在这个package xff0c 则应注意可能是下述情况导致 xff1a catmake编译完 xff0c 再用rosrun或roslaunch命令找不到package时 xff0c 这时需
  • 迷一样的穿越机飞控电容的作用

    穿越机电源上要并个大电容 xff0c 今天终于碰到一位真神说明白了 xff1a 电容两个作用 xff0c 一个是在你插电的一瞬间 xff0c 因为里面有降压设备大部分都是线圈类的东西 xff0c 产生电磁效应会有高于电池特别高的电压 xff
  • 一、机械小白学单片机之初认识ESP8266

    前言 本人刚接触单片机开发 xff0c 原专业为机械自动化 xff0c 因为传统机械行业的不景气 xff0c 想要转为从事电子行业 之前有一点C语言基础 xff0c 还学过一点点C xff0c 但是也就一点点 可谓小白学习之路 希望能够给大
  • VB.net写一个简易串口RS485调试助手

    最近在调试带rs485串口通讯的设备 xff0c 项目上主要是用PLC和串口通讯 xff0c 因为PLC有集成好的串口块 xff0c 使用起来比较容易 xff0c 为了方便测试 xff0c 就想着用上位机写一个简易的串口通讯程序 xff0c
  • 使用python加PyQt5,利用QMediaPlayer写一个简易的音乐播放器(进度条拖动,音量改变,播放停止切换,歌曲列表))

    当你学习了python之后 总想着利用它去做些什么 无论是制作小工具还是小游戏 都是一种锻炼 那么 利用python加上PyQt5写一个简单的音乐播放器 可能会是一个有趣的体验 下面我会分享一下如何编写简易的音乐播放器 其中参考了网络上的很
  • <Python>PyQt5自己编写一个音乐播放器(优化版)

    Python音乐播放器 更新日志 xff1a 20221031 xff1a 添加独立播放列表 20221107 xff1a 添加 上一首 下一首 功能 展示图片 xff1a 202211071308更新 xff1a 添加上一首 下一首功能
  • 以前做的一种特殊的平衡车----三轮球上平衡车

    这个项目做了很长的时间 xff0c 核心算法就是PID xff0c 目标就是让一个三轮车 xff08 轮子为全向轮 xff09 站到足球上并可以进行平移旋转等平面运动 机械部分 使用三个橡胶全向轮 xff0c 通过联轴器连接减速电机 xff
  • VAE与GAN做异常检测的原理

    近几年 xff0c 有大量的人用VAE和GAN来做异常检测 xff0c 用这两个模型做异常检测的假设都是一样的 xff0c 即假定正常数据是服从某一种分布的 xff0c 而异常数据是不能够拟合进这个分布的 xff0c 因此我们可以用VAE和
  • windows10上Eclipse和PyDev搭建python开发环境

    1 安装java环境 xff0c jdk下载地址如下 http www oracle com technetwork java javase downloads index html 完成安装后 xff08 记住安装位置 xff0c 之后有
  • 双系统引导启动切换

    双系统引导启动切换 微软双系统引导启动切换适用环境选择启动盘 微软双系统引导启动切换 适用环境 1 有双系统操作需求 2 强迫症 上期讲了如何重装新的操作系统 xff0c 我有两个盘 xff0c 一个盘固态 xff0c 一个机械 两个里面都
  • gazebo模型不显示

    提示 xff1a File 34 usr lib python2 7 xml etree ElementTree py 34 line 1657 in feed self parser Parse data 0 UnicodeEncodeE
  • 根文件系统(rootfs)的制作

    由于板子不知道什么缘故 xff0c u boot的tftp功能无法应用 xff0c 每次都用串口下载数据 xff0c 但是到后面要下载文件系统的时候实在是太大了 xff0c 完全无法下载 xff0c 因此 xff0c 尝试着做一个简单的文件
  • MPU6050 +STM32F411RCT6

    今天玩了一个MPU6050模块 xff0c 在这里跟大家分享一下 xff0c 希望对大家有所帮助 我用的控制板是我自己画图打板的 xff0c 使用的MCU是STM32F411RCT6 使用的MPU6050如下图 xff0c 在某宝上买的 M

随机推荐

  • Android 注解解析及使用

    目录 一 注解解析 1 什么是注解 xff1f 2 为什么要使用注解 xff1f 3 android中常见的注解有哪些 xff1f 4 元注解 二 注解使用 1 如何实现一个注解 xff1f 2 android中注解示例 一 注解解析 1
  • 2-ROS文件系统简单介绍

    本教程介绍了ROS文件系统的概念 xff0c 并介绍了roscd rosls rospack命令行工具的使用 至于为什么选择deepin而不是ROS通用的ubuntu 也仅仅是为了支持国产系统 鉴于本人水平有限 xff0c 如哪位攻城狮网友
  • Pixhawk 固定翼滑跑起飞逻辑

    起飞逻辑控制代码 xff08 runway cpp xff09 外环控制逻辑 xff08 fw pos control l1文件夹 xff09 xff0c L1导航代码 xff08 ecl l1 pos controller cpp xff
  • 控制分配问题概述

    线性过驱动系统分配方法研究现状 书中将可用于现行过驱动系统分配求解的方法归纳为三类 xff1a 1 广义逆类分配方法 主要包括伪逆法 xff0c 加权伪逆法 xff0c 再分配伪逆法 xff0c 多级伪逆法和串接链法等 xff1b 2 几何
  • Realsense D435i 相机与VINS-Mono连接时右侧不显示轨迹问题的解决

    Realsense D435i 相机与VINS Mono连接时右侧不显示轨迹问题的解决 文章目录 Realsense D435i 相机与VINS Mono连接时右侧不显示轨迹问题的解决1 问题描述2 问题原因查找3 解决办法 修改launc
  • 关于EKF和ErKF的理解

    EKF和ErKF的区别 大概6 20写完 快捷键 加粗 Ctrl 43 B 斜体 Ctrl 43 I 引用 Ctrl 43 Q插入链接 Ctrl 43 L插入代码 Ctrl 43 K插入图片 Ctrl 43 G提升标题 Ctrl 43 H有
  • ETH-Cubli阅读

    7月底补完
  • 端口扫描器设计实现(Python)

    一 个人感悟 通过本次实验 学习了扫描器设计的基本原理 并动手设计了一个开放端口扫描器 具体原理 1 编写前端GUI 2 学习Socket编程 使用Socket编程的connect方法返回0 为连接成功 实现端口扫描器 改进的地方 如果se
  • 学习心得

    敏捷开发宣言读后感 敏捷开发的原则 1 迭代式开发 即整个开发过程被分为几个迭代周期 每个迭代周期持续的时间一般较短 通常为1到6周 2 增量交付 产品是在每个迭代周期结束时被逐步交付使用 每次交付的都是可以被部署 能给用户带来即时效益和价
  • EKF SLAM Matlab仿真实践详解(附源码)

    EKF SLAM Matlab仿真实践详解 xff08 附源码 xff09 为提供更好的阅读体验 xff0c 详细内容及源码请移步https github com Nrusher EKF SLAM 或 https gitee com nru
  • FreeRTOS解析:List

    FreeRTOS解析 xff1a List 受博客限制 xff0c 如果您想获得更好的阅读体验 xff0c 请前往https github com Nrusher FreeRTOS Book或者https gitee com nrush F
  • FreeRTOS解析:任务的创建(TASK-2)

    任务的创建 受博客限制 xff0c 如果您想获得更好的阅读体验 xff0c 请前往https github com Nrusher FreeRTOS Book或者https gitee com nrush FreeRTOS Book下载PD
  • FreeRTOS解析:任务切换(TASK-3)

    任务切换 受博客限制 xff0c 如果您想获得更好的阅读体验 xff0c 请前往https github com Nrusher FreeRTOS Book或者https gitee com nrush FreeRTOS Book下载PDF
  • man命令使用指南

    man命令是linux下查找shell命令 函数等使用方法的利器 最简单的使用方式是man lt the thing you want gt 掌握上面那条命令应该也可以满足80 的使用场景了 这里记录一些更加深入的man命令使用的方法 xf
  • Vscode 搭建舒适的 Markdown 编辑环境

    文章目录 1 显示风格2 图片插入3 表格处理4 其他 1 显示风格 使用 Markdown notebook Microsoft xff0c 这个插件可以实现markdown的预览和编辑在同一页面下 xff0c 显示效果如下 外链图片转存
  • 如何启动英伟达TX2的两个CAN口

    英伟达的TX2有两路CAN xff0c 默认情况下是没有启动的 xff0c 通过ifconfig命令可以查看CAN是否启动 xff0c 如果启动了 xff0c 可以看到下面的设备 如果没有相应的设备 xff0c 则说明CAN没有启动起来 通
  • DDR基础

    欢迎关注我的博客网站nr linux com xff0c 图片清晰度和 xff0c 排版会更好些 xff0c 文章优先更新至博客站 DDR全称Double Data Rate Synchronous Dynamic Random Acces
  • OpenCV实验系列之Mask操作

    OpenCV实验系列之Mask操作 注意 xff1a 以下内容根据opencv官网提供的教程结合个人理解所得 xff0c 仅是个人学习笔记 xff0c 可能存在错误或偏差 xff0c 欢迎指正 OpenCV实验系列之Mask操作 Mask矩
  • UART通信可否只接VCC、RXD、TXD而不接GND?

    使用串口登录树莓派时出现的问题 xff1a 将TF卡插入到树莓派 xff0c 然后开启电源 xff0c 采用串口查看登录界面时出现误码 xff0c 最后排查得出是没有共地 那么假设有两款5V单片机 xff0c 独立供电 按理 xff0c 连
  • Linux 网络编程项目 —— FTP 网盘

    文章目录 项目简介知识点描述项目功能指令远程功能指令本地功能指令 使用的关键函数access 函数popen 函数chdir 函数strtok 函数strncmp 函数linux system函数是否执行成功判断方法 基本流程服务端客户端