自己动手写一个网盘?

作者:桂花年糕仔,未经允许,不得转载!

持续更新中

前言

该项目是用C和C++写的,涉及到很多知识点,还没写完,是一个拓展视野的好项目!

第1章 环境搭建

说明,本人租用的是阿里云服务器,其实用本地虚拟机也可以,结合https://blog.csdn.net/qq_43647359/article/details/105645615(FastDFS 的安装、使用、踩坑过程)和B站的一个视频 https://www.bilibili.com/video/BV1gh411m7tG?p=6(FastDFS分布式文件系统精品教程)可以将 TrackerStorage运行起来
一直可以到这一步

fdfs_monitor /etc/fdfs/client.conf   %向客户端返回storage的信息

在这里插入图片描述

第2章 上传测试及自写API

2.1 上传测试

fdfs_upload_file /etc/fdfs/client.conf 捕获.PNG   
/*通过启动客户端,将捕获.png文件,上传至storage.
要注意,当前路径包含捕获.PNG
fastdfs会通过算法,将捕获.PNG转换成一个唯一的文件名。如下所示*/

别看这个操作好像很鸡肋,如果每个人都有一个fastDFS,那么就可以集体上传了,或许百度网盘这个客户端自身就是集成了fastDFS这种类型的功能,只不过是作为client的角色!
在这里插入图片描述
查看我们的文件到底上传到哪了,可以发现在这个位置,自动帮我们保存了,还能发现存储路径和上一张图名字很像。在这里插入图片描述

2.2 自写API

这时候,我们需要做一件事,就是自己封装一个文件上传的API,然后用main函数调用。当然了,一些头文件用的还是fast DFS自带的,主要有以下几个模块,fdfs_api.hfdfs_api.cmain.c
代码如下:

//fdfs_api.h
 1 #ifndef _FDFS_API_H
 2 #define _FDFS_API_H
 3 int fdfs_upload_file(const char* conf_file,const char* myfile,char* file_id);
 //函数声明
 4 #endif
//fdfs_api.c
1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <string.h>
  5 #include <errno.h>
  6 #include <sys/types.h>
  7 #include <sys/stat.h>
  8 #include "fdfs_client.h"
  9 #include "fastcommon/logger.h"
 10 
 11 int fdfs_upload_file(const char* conf_file,const char* myfile,char *file_id)
 13 {
 14     char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
 15     ConnectionInfo *pTrackerServer;
 16     int result;
 17     int store_path_index;
 18     ConnectionInfo storageServer;
 19 
 20     //通过客户端配置文件初始化一些数据
 21     //result中包含了客户端的一些信息
 22     if ((result=fdfs_client_init(conf_file)) != 0)
 23     {
 24         return result;
 25     }
 26     // 通过从配置文件中读出的数据,连接追踪器trackker
 27     // 通过得到的地址可以访问追踪器
 28     pTrackerServer = tracker_get_connection();
 29     //如果追踪器连接不上
 30     if (pTrackerServer == NULL)
 31     {
 32         fdfs_client_destroy();  //释放客户端
 33         return errno != 0 ? errno : ECONNREFUSED;
 34     }
 35 
 36     *group_name = '\0';
 37 
 38     //通过tracker得到存储节点信息
 39     if ((result=tracker_query_storage_store(pTrackerServer, \
 40                     &storageServer, group_name, &store_path_index)) != 0)
 41     {
 42         fdfs_client_destroy();
 43         fprintf(stderr, "tracker_query_storage fail, " \
 44             "error no: %d, error info: %s\n", \
 45             result, STRERROR(result));
 46         return result;
 47     }
 48 
 49     //文件上传
 50     result = storage_upload_by_filename1(pTrackerServer, \
 51             &storageServer, store_path_index, \
 52             myfile, NULL, \
 53             NULL, 0, group_name, file_id);
 54     if (result == 0)
 55     {
 56         printf("%s\n", file_id);
 57     }
 58     else
 59     {
 60         fprintf(stderr, "upload file fail, " \
 61             "error no: %d, error info: %s\n", \
 62             result, STRERROR(result));
 63     }
 64 
 65     tracker_close_connection_ex(pTrackerServer, true);
 66     fdfs_client_destroy();
 67 
 68     return result;
 69 }
 70 

//main.c
  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include"fdfs_api.h"
  5 
  6 int main(int argc,char* argv[])
  7 {
  8     char fileid[1024]={0};
  9     //调用第4行头文件中的函数,参数1是配置文件的名字,
        //参数2是你要上传的文件名,在启动的时候通过main函数传入,
        //参数3是一个返回值,我们提前定义了一个数组用于接收
 10     fdfs_upload_file("/etc/fdfs/client.conf",argv[1],fileid);
 11     printf("fileID = %s\n",fileid);
 12 }

编译的过程中,当我们输入:gcc fdfs_api.c main.c 会出现fdfs_client.h:没有那个文件或目录的错误,是因为我们没有关联这些头文件的路径,这时候,我们包含这个目录gcc fdfs_api.c main.c -I /usr/include/fastdfs/,又会出现有些函数找不到定义的情况,这是因为我们缺动态库,需要指定动态库。再次输入gcc fdfs_api.c main.c -I /usr/include/fastdfs/ -lfdfsclient,发现不会报错了。这时候我们输入gcc fdfs_api.c main.c -I /usr/include/fastdfs/ -lfdfsclient -o app,用于获取一个app可执行文件。
接下来执行可执行文件

./app a.out   //a.out是我们要输入的参数2,即要上传的文件名

上一段的过程如下:在这里插入图片描述
在这里插入图片描述

2.3 上传的同时更新日志文件

可以看到上面一张图中,控制台输出了两行信息,其实,我们有时候不需要,如果每次上传之后,log日志文件中会有记录,那么我们想看的时候,在log日志中看不是更方便吗!下面给出了log日志的API,一个.c文件,一个.h文件。

//make_log.h
#ifndef  _MAKE_LOG_H_
#define  _MAKE_LOG_H
#include "pthread.h"

int out_put_file(char *path, char *buf);
int make_path(char *path, char *module_name, char *proc_name);
int dumpmsg_to_file(char *module_name, char *proc_name, const char *filename,
                        int line, const char *funcname, char *fmt, ...);
#ifndef _LOG
#define LOG(module_name, proc_name, x...) \
        do{ \
                dumpmsg_to_file(module_name, proc_name, __FILE__, __LINE__, __FUNCTION__, ##x);\
        }while(0)
#else
#define LOG(module_name, proc_name, x...)
#endif

extern pthread_mutex_t ca_log_lock;

#endif

//make_log.c
#include<string.h>
#include"make_log.h"
#include<pthread.h>
{
        char mesg[4096]={0};
        char buf[4096]={0};
            char filepath[1024] = {0};
        time_t t=0;
        //struct file_path *path;
        //path = (struct file_path*)paths;
        now = localtime(&t);
        va_end(ap);
        make_path(filepath, module_name, proc_name);

        pthread_mutex_lock(&ca_log_lock);
            out_put_file(filepath, buf);
        pthread_mutex_unlock(&ca_log_lock);

        return 0;
}

//写入内容
int out_put_file(char *path, char *buf)
{
    fd = open(path, O_RDWR | O_CREAT | O_APPEND, 0777);

            fprintf(stderr, "write error!\n");
            //write(fd, "\n", 1);
    }

        return 0;
}
//创建目录
int make_path(char *path, char *module_name, char *proc_name)
        char y_dir[1024] = {0};
        char m_dir[1024] = {0};
        char d_dir[1024] = {0};
        time(&t);
        now = localtime(&t);

        sprintf(third_dir, "%s/%s", second_dir, module_name);
        sprintf(y_dir, "%s/%04d/", third_dir, now -> tm_year + 1900);
        sprintf(m_dir, "%s/%02d/", y_dir, now -> tm_mon + 1);
        sprintf(d_dir,"%s/%02d/", m_dir, now -> tm_mday);

        if(access(top_dir, 0) == -1) {
                if(mkdir(top_dir, 0777) == -1) {
                        fprintf(stderr, "create %s failed!\n", top_dir);
                } else if(mkdir(second_dir, 0777) == -1) {
                        fprintf(stderr, "%s:create %s failed!\n", top_dir, second_dir);
                } else if(mkdir(third_dir, 0777) == -1) {
                        fprintf(stderr, "%s:create %s failed!\n", top_dir, third_dir);
                } else if(mkdir(y_dir, 0777) == -1) {
                }
        } else if(access(second_dir, 0) == -1) {
                if(mkdir(second_dir, 0777) == -1) {
                        fprintf(stderr, "create %s failed!\n", second_dir);
                } else if(mkdir(third_dir, 0777) == -1) {
                        fprintf(stderr, "%s:create %s failed!\n", second_dir, third_dir);
                } else if(mkdir(y_dir, 0777) == -1) {
                        fprintf(stderr, "%s:create %s failed!\n", second_dir, y_dir);
                } else if(mkdir(m_dir, 0777) == -1) {
                        fprintf(stderr, "%s:create %s failed!\n", second_dir, m_dir);
                }
        } else if(access(third_dir, 0) == -1) {
                if(mkdir(third_dir, 0777) == -1) {
                        fprintf(stderr, "create %s failed!\n", third_dir);
                } else if(mkdir(y_dir, 0777) == -1) {
                        fprintf(stderr, "%s:create %s failed!\n", third_dir, y_dir);
                } else if(mkdir(m_dir, 0777) == -1) {
                        fprintf(stderr, "%s:create %s failed!\n", third_dir, m_dir);
                }
        } else if (access(y_dir, 0) == -1) {
                if(mkdir(y_dir, 0777) == -1) {
                        fprintf(stderr, "create %s failed!\n", y_dir);
                } else if(mkdir(m_dir, 0777) == -1) {
                        fprintf(stderr, "%s:create %s failed!\n", y_dir, m_dir);
                }

        } else if (access(m_dir, 0) == -1) {
                if(mkdir(m_dir, 0777)) {
                        fprintf(stderr, "create %s failed!\n", m_dir);
                }
        }
        //printf("path:%s\n", path);
        return 0;
   }
    

我们在上传文件的功能中,将上传成功以及上传失败的信息都加入到了log日志当中。LOG的前两个参数只是路径名
在这里插入图片描述
在这里插入图片描述

第3章 redis数据库

3.1 介绍

在这里插入图片描述
在这里插入图片描述

3.2 安装

进入官网:http://redis.io,下载3.2.8版本,现在已经出到6.0+版本了,由于我们是学习,不需要那么高版本。在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

下载好之后,通过finalshell上传到云服务器的相应文件夹中,然后执行以下命令,进行解压缩,安装在这里插入图片描述

tar -zxvf redis-3.2.8.tar.gz  解压缩
cd redis-3.2.8
make
sudo make install

make的过程中发现了很有意思的东西:在这里插入图片描述
在这里插入图片描述
redis启动命令:redis-server
在这里插入图片描述
重开一个窗口,输入redis-cli命令去链接redis,因为原先启动了redis服务的那个窗口会阻塞。
在这里插入图片描述
通过set key valuemset key value命令去创建单键值对以及批量创建键值对。key *命令可以查看所有的key在这里插入图片描述
redis的一些命令还可以对已经存储了的键值对进行加减(数值才可以)、拼接的操作,这个具体查看相应的命令即可。

3.3 修改配置文件

通过修改redis.conf文件,可以生成log文件,可以让其他电脑连接这个数据库。

3.4 Redis Desktop Manager

项目中用到了redis,想查询redis中的数据,一直想找一个可视化工具,今天发现了Redis Desktop Manager,试用了一下,很好用。下载链接:http://www.xue51.com/soft/5385.html(别进这个链接下载,有毒,下面先给正常情况下的效果图)
这里要注意修改redis.conf中的一些东西,还要注意开放云服务器的相应端口,否则用这个软件连不上。
在这里插入图片描述

所有都配置好后,可以测试一下,通过在云端修改数据库,然后刷新这个redis管理工具,可以看到数据库的变动在这里插入图片描述

3.5 中毒体验

我真是想揍它的,这个网址下载的软件有毒,搞得我云服务器CPU占有率100%,去网上查了一下是说中了病毒crypto和pnscan病毒在这里插入图片描述
在这里插入图片描述

3.6 修复木马

后面百度了一下,说是中了pnscan 挖矿蠕虫病毒,由于我云服务器也没配置什么东西,看了一下修复操作挺复杂的,索性就重置了一下服务器,后面还特意把redis.conf中的允许其它用户连接改成了仅允许本级访问,还特地加了redis-cli密码,还把redis的端口号也给改了。我就不信以后还会中病毒。
redis.conf中随意一个位置加入requirepass ***,***指的是你要设置的密码,redis的启动密码。从下图中可以发现,单单通过端口号去链接可以连上,但是无法使用命令,所以我们在登陆时,不仅要用-p指定端口号,还需要-a加上登陆密码

ps aux | grep redis-server  //查看redis进程

在这里插入图片描述

第4章 MYSQL的安装

4.1 MYSQL下载

首先这个安装过程还是有点复杂的,不过照着这个步骤来,不会错。建议安装5.7.20版本的MYSQL。高版本的MYSAL发生了问题也不好解决(用的人不多)。
第一步:官网下载https://downloads.mysql.com/archives/community/,也可以直接百度,进入MYSQL首页,然后在最下方找到社区版在这里插入图片描述

第二步:进入历史版本,选择5.7.20以及红帽系统,再点击第一个下载,第一个安装的最全在这里插入图片描述
在这里插入图片描述

4.2 MYSQL安装

第三步:下载好安装包后,通过finalshell管理工具上传至云服务器上,和其它软件一样,我们安装在了usr/local/目录下在这里插入图片描述
第四步:要安装首先得把解出到一个目录,使用tar –xvf 包名 –C 目录名
依次执行以下命令:

mkdir mysql
tar -xvf mysql-5.7.20-1.el7.x86_64.rpm-bundle.tar -C mysql
cd mysql

进入目录后会看到如下文件在这里插入图片描述
这个包里边除了服务端和客户端外,还有一些依赖库以及拓展包,我们只要安装服务端和客户端即可。不过安装这些包都有依赖关系,再没有安装依赖包之前安装软件会报错,所以一般都是以下顺序安装:

sudo rpm -ivh mysql-community-common-5.7.20-1.el7.x86_64.rpm
sudo rpm -ivh mysql-community-libs-5.7.20-1.el7.x86_64.rpm
sudo rpm -ivh mysql-community-client-5.7.20-1.el7.x86_64.rpm
sudo rpm -ivh mysql-community-server-5.7.20-1.el7.x86_64.rpm
sudo rpm -ivh mysql-community-devel-5.7.20-1.el7.x86_64.rpm
  • 执行上面命令的过程中可能会报错: mariadb-libs 被 mysql-community-libs-8.0.13-1.el7.x86_64 取代
    一个命令:yum remove mysql-libs解决,即清除之前安装过的依赖即可。参考于https://blog.csdn.net/ypp91zr/article/details/84801204

  • 还有可能出现 mysql-community-client(x86-64) >= 5.7.9 被 mysql-community-server-5.7.30-1.e64需要的 错误。
    出现该问题的原因可能为,在安装MYSQL之前,删除了mariadb,导致部分依赖找不到,通过以下指令重新安装mariadb。参考于https://blog.csdn.net/weixin_44311939/article/details/106189130

yum install mariadb-server mariadb 
systemctl start mariadb
systemctl enable mariadb
  • 最后还有一种方法可以解决,卸载刚刚安装好的软件,使用以下命令查看当前安装mysql情况,查找以前是否装有mysql,参考于https://www.cnblogs.com/nicknailo/articles/8563456.html

  • rpm -qa|grep -i mysql会显示之前安装了:

    MySQL-client-5.5.25a-1.rhel5

    MySQL-server-5.5.25a-1.rhel5

    • 停止mysql服务、删除之前安装的mysql,删除命令:rpm -e –nodeps 包名
    • rpm -ev MySQL-client-5.5.25a-1.rhel5
      rpm -ev MySQL-server-5.5.25a-1.rhel5

在这里插入图片描述
第五步:安装完之后,我们启动mysql,启动命令为sudo service mysqld start,此时可以用ps –ef | grep mysqld看到mysql的守护进程mysqld
在这里插入图片描述

4.3 MYSQL登录及修改密码

第六步登录:mysql.5.7的mysql默认密码跟以往不同的是,默认mysql中root用户密码会写到log文件里边,我们要从log文件中找到默认密码,登录上去。

cd /var/log/    //进入log文件目录
vim mysqld.log  //查看默认的密码

可以看到如图所示的默认密码在这里插入图片描述
输入mysql –uroot –p密码进行登录
第7步:修改密码
方法一,在还未连接时,直接修改,可以修改成功,但是会提示警告,因为通过网络传输修改密码不安全

mysqladmin -u root -p password "要修改的密码"

Enter password: 【输入原来的密码】

方法二,通过登录mysql系统

 mysql -uroot -p
 Enter password: 【输入原来的密码】
 mysql>use mysql;
 mysql> update user set password=passworD("要修改的密码") where user='root';
 mysql> exit; 

至此,就结束了,通过mysql -uroot -p,再输入刚刚修改的密码,即可验证是否成功。

4.4 MYSQL设置远程访问(Navicate)

连接上MYSQL,然后输入以下命令,开启远程连接

mysql>GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '登陆密码' WITH GRANT OPTION;

flush privileges   //类似于刷新操作

打开Navicat软件进行连接在这里插入图片描述
连接成功在这里插入图片描述

4.5 MYSQL修改字符编码

连接上mysql数据库之后,我们可以查看当前的字符集,命令为\s,如下图所示:一开始的时候图中圈出的两个是拉丁,我们需要更改为utf8。
在这里插入图片描述
更改方式如下,打开my.cnf配置文件,配置文件在/etc/mysql/my.cnf,有些在直接就在/etc目录下。

cd /etc/
vim my.conf
将这两行代码加入到[mysqld]下方
character-set-server=utf8
collation-server=utf8_general_ci

在这里插入图片描述
保存文件后,重启mysql,命令如下

service mysqld stop    停止
service mysqld start   重启

再次连接mysql,输入\s,查询是否修改成功。

第5章 shell脚本

shell脚本通常以.sh 为后缀名,例如通过 vim test.sh命令创建了一个名为test的脚本。其中shell脚本里面通常编写的是一些命令。
例如:在test.sh中写入以下两行命令

ls -l  显示当前文件夹内所有目录文件的相关信息
echo "你好"

保存退出以后通过./test.sh命令可以执行shell脚本,值得注意的是,再输入命令之前我们还需要赋予test.sh文件一定的权限,否则无法运行

chmod u+x  文件名.sh
或者用
chmod 777  文件名.sh

然后再输入./test.sh命令就可以执行了,(补充:sh test.sh命令也可以)效果如下在这里插入图片描述

第6章 Nginx部署

6.1 Nginx下载及安装

nginx下载地址:http://nginx.org/download/nginx-1.19.4.tar.gz,下载好之后发送到云服务器的/usr/local/文件夹

cd /usr/local/src

tar zxvf nginx-1.19.4.tar.gz     解压

yum install -y gcc zlib zlib-devel openssl openssl-devel pcre
//安装gcc编译环境
//安装zlib库,zlib库提供了很多压缩和解压缩的方式
//安装套接字密码库,它是一个强大的套接字层密码库,nginx不仅支持http还支持https(即ssl协议上传输http)
//pcre正则表达式

cd /usr/local/nginx-1.19.4/

./configure
make
make install

cd /usr/local/nginx/sbin
./nginx                   //启动
ps aux |grep nginx        //查看进程是否启动了

在网址栏输入自己的云服务器ip地址,可以看到能够成功访问在这里插入图片描述
重写配置文件后,需要重启nginx服务器。
重启命令./nginx -s reload
注意,在其他位置启动nginx必须加上绝对路径/usr/local/nginx/sbin,因为nginx在安装的时候没有加入到path路径中。

6.2 Nginx配置及优化

由于每次启动nginx,如果不是在/usr/local/nginx/sbin目录下,就必须加上绝对路径,即用该命令去启动nginx:/usr/local/nginx/sbin/./nginx,会比较麻烦,因此我们可以通过创建软连接的方式去直接使用nginx的命令去启动nginx。
具体原理如下:

  • 在linux中,lscd等都是命令,通过which ls,可以发现ls命令在 /usr/bin/ls中,而通过echo $PATH命令,我们可以看到,linux的环境变量中包含了如下路径/usr/local/sbin: /usr/local/bin: /usr/sbin: /usr/bin: /root/bin,其中就包含了ls的所在路径,因此我们可以理解为,通过添加路径到PATH中,我们可以直接使用nginx这种简洁的命令去启动nginx。

step1:先关闭正在运行的nginx,在**/usr/local/nginx/sbin**目录中先输入./nginx -s stop
step2:通过ln -s /usr/local/nginx/sbin/./nginx /usr/bin/nginx命令,将/usr/local/nginx/sbin/./nginx这一操作加入到/usr/bin/目录中,并命名为nginx,至此,我们在任意位置只需要输入nginx,即可启动nginx服务器。
并且现在关闭nginx的命令也只需要输入nginx -s stop,此外nginx -s quit命令会更柔和一点,会先执行完手中的活,再退出nginx。


注意,step2中的这一操作在很多地方可用来提升办公效率
Nginx官方参考文档:http://nginx.org/en/docs/
淘宝团队翻译版本:http://tengine.taobao.org/nginx docs/cn/cocs/需要看源码再深入了解,一般是运维才需要了解。
配置文件的位置/usr/local/nginx/conf

6.3 Nginx测试

第一步:将测试的文件html1.tar.gz上传至云服务器。输入tar zxvf html1.tar.gz进行解压缩。解压缩完成后,会自动创建一个demo的目录,目录下有相应的文件在这里插入图片描述
第二步:修改配置文件,在这里我们加入了两个界面进行测试。在这里插入图片描述
在网址栏分别输入云服务器的ip地址,以及云服务器ip地址/second.html,即可访问下面两个页面。在这里插入图片描述
在这里插入图片描述
由上面两个静态页面可以得出,用户也可以随时添加其它静态页面,ip地址后面的/指的是资源文件。如192.168.22.12/second.html,输入这个网址,会在资源文件的根目录中找到second.html的资源。又如192.168.22.12/test/index.html则表示会在资源文件的根目录中找到test目录下的index.html的资源。


关于配置文件中,localtion的一些用法日后可以详细探索
补充1,上网通过域名连接到ip地址的方式如下图所示:在这里插入图片描述
补充2,host文件也是通过解析的方式,不过是在本地,访问谷歌什么的,其实并不需要VPN,只需要在host文件中指定解析ip,这个具体还得查阅,没去深究。
补充3,反向代理的前提:有多台web服务器,因为要去做负载均衡,如果只有一台,直接链接就可以了

6.4 Nginx反向代理

必要条件
在这里插入图片描述
windows下nginx的配置文件nginx.conf中要加入的配置项

#设置两个Linux服务器的反向代理
# 先配置luffy
upstream luffy.web{       
	server 192.168.82.251:80;
}
# 再配置robin
upstream robin.web{
	server 192.168.82.253:80;
}
#配置要代理的服务器信息
# 先配置luffy
# luffy - 192.168.82.251
server{
	# 监听的端口
	listen 80;
	# 通过什么域名去访问当前的web服务器
	server_name luffy.com;
	location / {
		# 设置代理
		proxy_pass http://luffy.web;
		}
	}
	
# 配置robin	
# robin	- 192.168.82.253
server{
	# 监听的端口
	listen 80;
	# 通过什么域名去访问当前的web服务器
	server_name robin.com;
	location / {
		# 设置代理
		proxy_pass http://robin.web;
		}
	}

具体原理:
反向代理服务器通过监听80端口,查看80端口传来的信息是通过什么域名去访问当前的web服务器的。
举例,监听到当前80端口,传来了一个访问luffy.com的信息,通过定位server_name luffy.com,查看location中的代理http://luffy.web,再通过http://luffy.web找到upstream中http://luffy.web最终指向的真实ip192.168.82.251:80


工作流程

  • 通过浏览器访问server模块中的server_name对应的域名
  • 服务器去找location /
  • 需要在里面设置代理:proxy_pass +url
  • url自己编一个就可以
  • 通过这个url的名字去找到upstream模块
  • 找到之后,去访问该模块中server对应的ip地址

6.5 Nginx负载均衡

说明负载均衡是在反向代理的基础上进行的。
和6.4反向代理不同的是,负载均衡不需要那么多server,只需要一个就行了。

#在反向代理的基础上设置两个Linux服务器的负载均衡
# 配置linux.web
upstream linux.web{       
	server 192.168.82.251:80;  #什么都没设置,那默认两者的权重是一样的
	server 192.168.82.253:80;  #nginx通过轮询的方式将请求传递给两者
	#下面这种方式为设置权重的方式  51   注意weight的最小值为1
	# server 192.168.82.251:80 weight=5;
	# server 192.168.82.253:80 weight=1;
}

# 配置要代理的服务器信息
server{
	# 监听的端口
	listen 80;
	# 通过什么域名去访问当前的web服务器
	server_name localhost;   
	location / {
		# 设置代理
		proxy_pass http://linux.web;
		}
	}
  • 入口:server模块里面server_name对应的域名,也就是刚面写的localhost,这个server_name对应的域名没有要求,可以随意取。
  • 配置好之后重启,在网址栏输入localhost,nginx会进入到location /,发现是一个代理,里面的proxy_pass有一个url,然后通过url的名字去找upstream,找到之后,则会根据权重将用户的请求转发给251或者253ip地址中的其中一个。

6.6 Nginx总结

1.nginx作为web服务器

1. 优缺点

优点

  1. 部署简单
  2. 效率高
  3. 热部署

缺点

  1. 只能在nginx上边部署静态网页
  2. 动态网页?
    2.1 要登陆
    2.2 例如给定网址http://1.1.1.1/login.html
    2.3 用户在这个网址需要输入账号密码进行登录,但是nginx无法直接处理登陆的数据
    2.4 如果用户要验证,则需要在nginx中调用第三方模块去处理

如何处理
使用CGI去处理
我们需要做的事是调用CGI接口去完成数据处理(涉及http协议)


第7章 FastCGI

7.1 FastCGI和Spawn-fcgi的安装

第一步:安装FastCGI
首先解压FastCGI,
然后cd进入解压后的文件夹,
执行./configure命令,
继续执行make命令,这时候会发现有报错。在这里插入图片描述
在这里插入图片描述
错误原因:C++版本迭代的时候,将EOF的定义换到了另一个头文件中。
解决方法:在fcgio.cpp中加入相关的头文件,首先我们要找到这个fcgio.cpp
查找命令为find ./ -name "fcgio.cpp"
在这里插入图片描述
然后vim fcgio.coo,加入#include<stdio.h>头文件。在这里插入图片描述
然后执行以下两步:
make
make install
第二步:安装Spawn-fcgi
这个简单,执行以下四个步骤

  • 解压缩:tar zxvf spawn-fcgi-1.6.4.tar.gz
  • 进入文件夹,./configure
  • make
  • make install

7.2 FastCGI和Spawn-fcgi的作用

在这里插入图片描述

7.3 三者的配置

第一步:(配置nginx.conf)
当网页需要进行如登录注册这种光靠nginx无法完成的行为时,需要借助fastCGI模块进行配置,首先要vim nginx.conf,在nginx.conf中加入如下的代码:

#处理一个指令 test
          #url:http://106.15.34.47/test   用户访问的url
          #但是nginx自身无法处理指令,所以要配置fastCGI模块
          location /test{
              #配置fastCGI模块
              fastcgi_pass localhost:9001;
              #包含一个配置文件和nginx.conf一个目录
              include fastcgi.conf;
          }

注意: 上面的localhost改成127.0.0.1或者你本机的ip都行。不过这里还有要注意的:
如果nginx.conf中写的是127.0.0.1或者localhost,那么在spawn-fcgi -a IP -p 端口 -f fastcgi程序命令中的IP就要填127.0.0.1,如果nginx.conf中写的是服务器的IP,那么在spawn-fcgi -a IP -p 端口 -f fastcgi程序命令中的IP就要填服务器的IP
将要处理的数据发送到9001端口,9001端口对应一个进程,该进程可以收到nginx发过来的数据。


第二步:(编写fcgi程序)
到这里nginx就算配置好了,然后我们需要编写一个fcgi程序,这个程序是用来被spawn-fcgi调用的。
我们首先使用cp echo.c ~命令,将/usr/local/fcgi-2.4.1-SNAP-0910052249/examples目录中的示例文件echo.c拷贝到根目录,然后执行以下命令去编译他:

gcc echo.c   #执行这句话会报错,提示缺少动态库

gcc echo.c -lfcgi  #-l指的是连接动态库,fcgi指的是fcgi.so

执行完之后,会得到一个a.out文件

但是当我们去执行这个a.out文件时,会报错,如下(未找到动态库)

./a.out: error while loading shared libraries: libfcgi.so.0: cannot open shared object file: No such file or directory

在这里插入图片描述
解决方法:
首先,我们检查这个动态库是否存在:

find  /usr/local/lib -name libfcgi.so.0

执行完后,发现动态库是在的,在以下目录
/usr/local/lib/libfcgi.so.0

然后我们执行以下操作
vi /etc/ld.so.conf  打开文件 
在下面加一行/usr/local/lib
执行 ldconfig命令

如下图所示
在这里插入图片描述

在这里插入图片描述
补充:有时缺少动态库还需要执行以下操作
碰到的一个问题:在执行命令时出现了这样的错误
在这里插入图片描述
后面发现原因处在了出在了缺少动态库:libhiredis.so.0.13 => not found在这里插入图片描述
我先是用find命令查找这个库,发现并没有找到这个库,然后看到一篇博客,说要下载:执行以下命令

wget https://github.com/redis/hiredis/archive/v0.13.3.tar.gz
tar -xzvf v0.13.3.tar.gz
cd  hiredis-0.13.3
make -j4
make -j4 install
ldconfig

但是我发现执行完上述命令后还是不行,还需要添加下两个命令。

ln -s /usr/local/lib/libhiredis.so.0.13 /usr/lib/libhiredis.so.0.13
ln -s /usr/local/lib/libhiredis.so.0.13 /usr/lib64/libhiredis.so.0.13

现在再执行ldd upload就没有这一类问题了
在这里插入图片描述

第三步:运行
首先,我们在静态网页前端代码中这样设置,将method设置为get,后面的action设置为你服务器的ip地址和test请求,这里的意思相当于你在网页上填好了你的个人信息,然后点击提交,那么就会触发get请求,然后指向test请求。如下图所示。
在这里插入图片描述
然后我们要重启一下nginx,因为刚刚修改了nginx.conf,如果不重启,我们提交表单的时候可能不生效,就会显示如下的界面。
在这里插入图片描述
重启命令为:nginx -s reload
最后, 我们只需要输入以下命令即可spawn-fcgi -a 127.0.0.1 -p 9001 -f ./a.out,然后在网页填写相应的信息再提交即可,如下图所示:

 -a - IP: 服务器IP地址
 -p - port: 服务器将数据发送到的端口
 -f - cgi程序: spawn-fcgi启动的可执行fastcgi程序
在这里插入图片描述
在这里插入图片描述
仔细观察上面一幅图可以发现,用户提交的信息主要在这一行QUERY_STRING=username=%E5%B0%8F%E5%BC%BA&phone=15970qweqwe&email=1589221119%40qq.com&date=2021-11-13&sex=female&class=3&rule=on,那么我们只需要想办法提取就可以获得我们想要的信息。


如果把静态网页前端代码中的method设置为post,那么会得到这样的界面。会发现更简洁了在这里插入图片描述
fastcgi.conf中常用环境变量:
○ QUERY_STRING: 请求的资源, 请求行的第二部分
○ REQUEST_METHOD: 请求方法, get/post
○ CONTENT_TYPE: 文件类型
○ SCRIPT_NAME: 处理的指令, nginx中配置cgi的时候用
○ REQUEST_URI: 浏览器中请求的资源, 不包括IP+port


8 实现文件上传的操作

8.1 基本流程

  1. 将上传的前端代码文件夹zyupFile拷贝到ngixn安装目录
  2. 查看上传文件对应的html文件
    ○ 找到数据提交的位置(nginx需要配置的指令 - /upload)
  3. 修改nginx配置文件
    ○ 添加一个location /upload{
    fastcgi_pass IP:port;
    include fastcgi.conf;
    }
  4. 重新加载nginx配置文件
    ○ nginx -s reload
  5. 编写一个fastcgi程序
     将上传文件内容保存到web服务器
     调用fastdfs api将文件上传到fastdfs存储节点上
     得到一文件ID
     将文件和对应的fastdfs返回的文件ID存储到mysql数据库
     将上传之后的文件从web服务器删除

8.2 部署web界面

  • 前端html文件解释
    在这里插入图片描述
  • nginx.conf配置(配置完之后记得重启)
    在这里插入图片描述
  • 在浏览器以两种方式输入相应的url,然后观察效果,可以看到,配置完之后,不论是根目录还是二级目录都能访问,效果如下:在这里插入图片描述
    在这里插入图片描述

8.3 文件上传(阶段一)

在阶段一,我们首先看一下文件上传过程中,会有哪些信息。

  • 首先在html文件中查看上传的请求 在这里插入图片描述
  • 会发现上传时会用到upload请求,这时候我们需要在nginx.conf中配置upload请求。在这里插入图片描述
  • 我们设置了一个8002端口用于负责upload请求,然后通过spawn-fcgi -a 127.0.0.1 -p 8002 -f ./a.out命令启动了a.out程序用于监听8002端口,一旦有请求过来,那么就会执行a.out程序,a.out程序的作用是将上传的文件信息打印在网页上,如下图所示,我们上传了一张图片,点击上传操作时,a.out程序就会显示如下信息。在这里插入图片描述
    其中图片的信息夹在两行语句之间,如下图所示紫色的为文件名,红色的为文件的自身信息
------WebKitFormBoundaryHnkjpSB2GTtBWlrg
文件名
文件类型
文件的数据
------WebKitFormBoundaryHnkjpSB2GTtBWlrg

在这里插入图片描述

这一节,我们主要演示了图片在上传时,我们将其信息打印出来,主要用到的是a.out程序也就是echo.c.
那么思考一下,如何将图片上传到服务器呢?
其实就是写一个程序,将------WebKitFormBoundaryHnkjpSB2GTtBWlrg
之间的内容也就是文件的名称和信息写到fastDFS即可,有了名称上传到fastDFS我们还能得到一个id,然后将名称和id存到数据库中,这时候就能实现下载的操作。这就是我们在阶段二要做的事。

8.4 文件上传(阶段二)

第一步:
fastdfs-nginx-module_v1.16.tar.gz文件上传到云服务器上,解压完毕后路径下,会有以下文件。
在这里插入图片描述
第二步:(注意这一步是错误的,下面会修正)

这里需要重新下一个1.10.1版本的nginx,用于部署在storage节点上,目的是为了方便下载阶段,1.10.1版本以上可能会报错。
nginx1.10.1的下载链接:https://nginx.org/download/nginx-1.10.1.tar.gz
下载完毕后,重新编译nginx,此时编译nginx的过程中要将上面出现的pwd路径加入到命令中。
./configure --add-module=/usr/local/fastdfs-nginx-module/src
make
在make之后会报错,说是缺少.h文件,这时候我们需要在makefile中加入这个头文件的路径。在这里插入图片描述
打开Makefile,会发现这个文件只有23行,认真解读会发现其真正的Makefile工作是在objs目录下进行的。在这里插入图片描述
打开真正的Makefile会发现有1000多行,然后我们要在**-I**的位置将刚刚缺少的头文件的路径放进去。在这里插入图片描述
找到刚刚缺失的头文件的路径,一般来说头文件是在/usr/include/目录下的,输入以下命令进行查询:find /usr/include/ -name fdfs_define.h,会发现这个头文件在这个目录下: /usr/include/fastdfs/fdfs_define.h ,把这个路径加入到-I之后继续make,还会发现缺少了一个logger.h文件,按照同样的方法继续执行,但是这里就会发现问题没有解决,反而报错还更多了。
在这里插入图片描述

第二步:
所以第二步得重新来,而且后面发现其实不需要在下载一个nginx,直接在原有的nginx的基础上进行配置即可,

  • 删除掉刚刚的两个文件夹,由于是fastdfs-nginx-module中的代码出了问题,考虑到可能是fastdfs-nginx-module和nginx版本不兼容的问题,我们重新下载一个fastdfs-nginx-module
    下载地址:https://github.com/happyfish100/fastdfs-nginx-module

  • nginx就用之前的,这时候重新执行以下两行代码
    ./configure --add-module=/usr/local/fastdfs-nginx-module-master/src
    make
    最后直接make install

  • 这样就顺利执行了,然后重启nginx -s reload,查看进程ps aux|grep nginx,会发现nginx中的worker进程没有启动,说明还有问题。在这里插入图片描述

  • 找到nginx的log日志,会发现是缺少了mod_fastdfs.conf,这时候,我们需要把mod_fastdfs.conf放在/etc/fdfs目录下。在这里插入图片描述

  • 同时,我们也对mod_fastdfs.conf进行配置,配置和storage.conf差不多。在这里插入图片描述

  • 除此之外,还需要将usr/local/fastdfs/conf/中的http.conf 拷贝到/etc/fdfs/下,从usr/local/nginx-1.19/conf/中的mime.types 拷贝
    到/etc/fdfs/下

  • 配置nginx.conf,加入以下模块:

  • location /group1/M00 {

    root /root/fastdfs/storage/data;
    ngx_fastdfs_module;
    }

  • 把nginx.conf第一行的 #user nobody 换成 user root,否则此后会出现权限不够的问题。

  • 最后重启nginx -s reload即可。

第三步:测试
上面的location指的是将浏览器中的**/group1/M00地址定向为服务器内存中的地址/root/fastdfs/storage/data**,我们服务器上有一张图片,名字为ag8iL2F_X8aAfZhjAAX3_BxwTws124.png在这里插入图片描述
然后在我们的网址栏,输入这个文件对应的名称,就能看到服务器上所存储的图片了。在这里插入图片描述

  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枫恋蝶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值