【Linux】图片服务器

项目背景

类似于在CSDN中上传博客,选择上传图片后,会进去选择图片文件的界面,然后上传成功后,我们就可以看到上传的图片被显示,其实质就是将图片上传到了CSDN的后台服务器中。

核心功能

  • 新增图片
  • 查看所有的图片信息
  • 查看指定图片信息
  • 查看图片内容
  • 删除图片
    该项目的核心就是实现一个HTTP服务器,然后用该服务器来存储图片,针对每个图片提供唯一的URL,有了该URL后,就可以接住它将图片展示在其他网页上。
  • 上传图片(得到唯一的URL)
  • 根据图片的URL访问图片,并获取图片的内容
  • 获取某个图片的属性
  • 删除图片

模块划分

1.数据库存储模块
包括:设计数据库、使用MySQL C API操作
2. 服务器模块
包括新增图片、查看所有图片信息、查看指定图片的内容,删除图片

数据库设计

create database if not exists image_system;
use image_system;

创建图片表

drop table if exists 'image_table';
create table 'image_table'(image_id int not null primary key auto_increment,
image_name varchar(50),
size bigint,
upload_time varchar(50),
md5 varchar(128),
content_type varchar(50) comment '图片类型',
path varchar(1024) comment '图片所在路径'
);

其中,image_id为主键自增属性
md_5如何文件校验字符串?
这是一种常见的hash算法,具有三个特性:
1.不管源字符串多长,得到的最终的md5值都是固定长度的
2.源字符串稍微变化一点内容,md5值会变化很大(降低冲突概率)
3.通过源字符串很容易得到md5值,但是根据md5值推导源字符串很难(几乎不可能)

md5的作用:用于校验图片的正确性
(上传图片的时候,服务器可以计算出该图片的md5值,后续用户下载该图片时,也能够获取到该图片的md5值,用户可以把自己计算的md5值和服务器计算的md5进行对比,以此来判断下载的图片是否正确)

使用MySQL C API操作数据库

安装MySQL C API

yum install mysql -devel

代码中使用时需要连接上MySQL提供的库

-L /usr/lib64/mysql -lmysqlclient 

服务器的 API设计

我们需要实现一个HTTP服务器,HTTP服务器需要接受HTTP请求,HTTP响应,因此我们需要约定不同的请求来表示不同的操作方式。
如有些请求表示上传图片,有些请求表示查看图片,有些请求表示删除图片。

  • http method 表示操作的动词:GET查,POST增,PUT改,DELETE删
  • http path表示操作的对象
  • 补充信息一般使用body来传递,通常情况下body中使用json的格式来传递
  • 响应数据通常也是json格式组织
    json是一种数据组织格式,最主要的用途为序列化,json源于javascript,用来表示一个对象,类似于map的key:value格式
    json的优势,方便调试
    json的劣势,组织格式的效率低,更加占用存储空间和带宽
    具体设计:
    1.上传图片
请求:
POST /image 
Content-Type:application/x-www-form-urlencoded

----------WebKitFormBoundary5muoelvEmAAVUyQB
Content-Disposition:form-data;name="filename";filename="图标.jpg"
Content-Type:image/jpeg
......[图片正文]......

响应;
HTTP/1.1 200 ok
{
	"OK":true;
}

2.查看所有图片信息

请求:
GET /image/

HTTP/1.1 200 OK
[
	{
		"image_id":1,
		"image_name":"1.png",
		"content_type":"image/png",
		"md5":"[md5值]"
	}
]

3.查看指定图片的信息

请求:
GET /image/:image_id

响应:
HTTP/1.1 200 ok
{
	"image_id":1,
	"image_name":"1.png",
	"content_type":"image/png",
	"md5",:"[md5值]" 
} 

4.查看指定图片的内容

请求:
GET /image/show/:image_id

响应:
HTTP/1.1 200 OK
content_type :image/png

[响应 body中为图片的内容数据]

5.删除图片

请求:
DELETE /image/:image_id

响应:
HTTP/1.1 200 OK
{
	"OK":true
}

6.服务端设计
封装数据库操作

namespace image_system
{
	static MYSQL* MySQLInit(){}
	static void MySQLRelease(MYSQL* mysql){}
	
	class ImageTable{
		ImageTable(MYSQL* mysql){ }
		bool Insert(const Json::Value& image);
		bool SelectAll(Json::Value* images);
		bool SelectOne(int32_t image_id,Json::Value* image);
		bool Delete(int image_id);
	};
}

服务器的基本框架

#include "httplib.h"

int main()
{
	using namespace httplib;
	Server server;
	server.Get("/",[](const Request& req,Response& resp){
	(void) req;
	resp.set_content("<html>hello</html>","text/html");});
	server.set_base_dir("./wwwroot");
	server.listen("0.0.0.0",9094);
	return 0;
}

构建与http服务器约定的API接口

#include <signal.h> 
#include <jsoncpp/json/json.h> 
#include "util.hpp" 
#include "db.hpp" 
#include "httplib.h" 
#include <openssl/md5.h> 
 
std::string StringMD5(const std::string& str); 
 
const std::string base_path = "./image_data/"; 
 
MYSQL* mysql = NULL; 
 
int main() { 
  using namespace httplib;  
  using namespace image_system; 
  Server server; 
   
  // 1. 数据库客户端初始化和释放 
  mysql = MySQLInit(); 
  signal(SIGINT, [](int) { MySQLRelease(mysql); exit(0);}); 
  ImageTable image_table(mysql); 
 
  // 2. 先按照 cpp-httplib 的文档演示基本的图片上传处理过程 
  server.Post("/image_test", [](const Request& req, Response& resp) { 
     
  }); 
 
  // 3. 新增图片. 
  server.Post("/image", [&image_table](const Request& req, Response& resp) { 
     
  }); 
 
  // 4. 查看所有图片的元信息 
  server.Get("/image", [&image_table](const Request& req, Response& resp) { 
  
  }); 
   
 
  // 5. 查看图片元信息 
  // raw string(c++ 11), 转义字符不生效. 用来表示正则表达式正好合适 
  // 关于正则表达式, 只介绍最基础概念即可. \d+ 表示匹配一个数字 
  // http://help.locoy.com/Document/Learn_Regex_For_30_Minutes.htm 
  server.Get(R"(/image/(\d+))", [&image_table](const Request& req, Response& resp) { 
 
  }); 
 
  // 6. 查看图片内容 
  server.Get(R"(/image/show/(\d+))", [&image_table](const Request& req, Response& resp) { 
 
  }); 
 
  // 设置静态文件目录 
  server.set_base_dir("./wwwroot"); 
 
  server.listen("0.0.0.0", 9094); 
  return 0; 
} 
 
// 需要包含头文件  
// #include <openssl/md5.h> 
// Makefile 需要 -lcrypto 
std::string StringMD5(const std::string& str) { 
  const int MD5LENTH = 16; 
  unsigned char MD5result[MD5LENTH]; 
  // 调用 openssl 的函数计算 md5 
  MD5((const unsigned char*)str.c_str(),str.size(),MD5result); 
  // 转换成字符串的形式方便存储和观察 
  char output[1024] = {0}; 
  int offset = 0; 
  for (int i = 0; i < MD5LENTH; ++i) { 
    offset += sprintf(output + offset, "%x", MD5result[i]); 
  } 
  return std::string(output); 
}

测试上传图片,实现一个测试页面upload.html,生成一个按钮,点击之后弹出文件选择框,发送按钮,就会给服务器发送一个特殊的http请求。验证上传的图片是否能成功。

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
</head>
<body>
	<form method="POST" enctype="multipart/form-data" action="http://0.0.0.0:9094/image">
		<table>
			<tr>
				<td>文件上传:</td>
				<td><input type="file" name="filename"/></td>	
			</tr>
			<tr>
				<td></td>
				<td><input type="submit" value="上传"/></td>
			</tr>
		</table>
	</form>
</body>
</html>

正则表达式的简单实用
raw string(C++11),作用是使得转移字符不生效,用来表示正则表达式。
正则表达式是一个带有特殊符号的字符串,描述了一个字符串的特征,(字符串应该包含什么信息,某个信息开头,以某个信息结尾,某个信息重复出现多少次),代码中使用的\d+表示匹配一个数字。

项目扩展

  • 对相同的图片可以只存储一份,利用md5校验两张图片是否相同,然后通过计数器实现同一个图片只存储一份
  • 支持一些简单图片的处理功能,例如在请求参数中带上参数w=50&h=50,得到一个50*50的图片
  • 防盗链,其实就是权限控制,只能让图片被特定的用户使用,借助cookie,实现相关账户的验证功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值