主頁 >  其他 > 三、區分存盤物件的不同版本

三、區分存盤物件的不同版本

2021-10-26 07:39:57 其他

架構

(架構圖源于參考書籍)

Elasticsearch 環境搭建

官方簡介:Elasticsearch 是一個分布式、RESTful 風格的搜索和資料分析引擎,能夠解決不斷涌現出的各種用例, 作為 Elastic Stack 的核心,它集中存盤您的資料,幫助您發現意料之中以及意料之外的情況,

下載安裝

# 下載
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.15.1-linux-x86_64.tar.gz

# 解壓
tar xzvf elasticsearch-7.15.1-linux-x86_64.tar.gz

# 以非 root 用戶啟動
cd /elasticsearch-7.15.1/bin/
./elasticsearch

# 檢驗是否啟動成功,172.16.16.4 為 elasticsearch.yml 配置系結的 IP 地址
curl 172.16.16.4:9200

若無法正常啟動,則修改配置:

/home/sam/elasticsearch-7.15.1/config

修改 jvm.options 中記憶體配置:
-Xms256m
-Xmx256m

修改 vim elasticsearch.yml :
cluster.name: my-application
node.name: node-1
network.host: 172.16.16.4
http.port: 9200
discovery.seed_hosts: ["172.26.26.4", "::1"]
cluster.initial_master_nodes: ["node-1"]

配置開機啟動

# 創建開機啟動檔案
vim  /usr/lib/systemd/system/elasticsearch.service

內容如下:

[Unit]
Description=elasticsearch
[Service]
User=sam #啟動用戶
LimitNOFILE=100000
LimitNPROC=100000
ExecStart=/home/sam/elasticsearch-7.15.1/bin/elasticsearch #安裝路徑
[Install]
WantedBy=multi-user.target

# 重新加載檔案配置
systemctl daemon-reload

# 設定開機啟動
systemctl enable elasticsearch

# 關掉之前啟動的 es
lsof -i tcp:9200
kill -9 pid

# 啟動 es
systemctl start elasticsearch

開啟遠程連接

# 放行埠
iptables -I INPUT 4 -p tcp -m state --state NEW -m tcp --dport 9200 -j ACCEPT

# 保存 iptables 規則
service iptables save

# 遠程測驗
curl 公網IP:9200

elasticsearch-head 插件

# github 地址
https://github.com/mobz/elasticsearch-head

# npm 啟動方式
git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
npm install
npm run start
open http://localhost:9100/

# 搭建 node 環境 

# 查看當前有那些可供選擇的版本
# dnf module list node.js

# 選擇一個版本
# dnf module edable nodejs:14

# 安裝 nodejs
dnf install nodejs

# 查看當前的版本
node --version
npm --version

# 進入目錄并安裝
cd elasticsearch-head
npm install

vim elasticsearch.yml
# 配置跨域
http.cors.enabled: true
http.cors.allow-origin: "*"

# 重啟 es 服務
sudo systemctl restart elasticsearch.service

# 放行埠
iptables -I INPUT 4 -p tcp -m state --state NEW -m tcp --dport 9100 -j ACCEPT

# 保存 iptables 規則
service iptables save

# 啟動
npm run start

遠程訪問:

創建映射

創建 metadata 索引以及 objects 型別的映射:

curl -H "Content-Type: application/json" -XPUT 172.16.16.4:9200/metadata?include_type_name=true -d'{"mappings":{"objects":{"properties":{"name":{"type":"text","index":"false"},"version":{"type":"integer"},"size":{"type":"integer"},"hash":{"type":"text"}}}}}'

ES包封裝

該 ES 包封裝了以 HTTP 訪問 ES 的各種 API 的操作,

package es

/* 該 ES 包封裝了以 HTTP 訪問 ES 的各種 API 的操作 */
import (
	"demo/sys"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
)

/* 元資料結構體 */
type Metadata struct {
	Name    string
	Version int
	Size    int64
	Hash    string
}

type hit struct {
	Source Metadata `json:"_source"`
}

type searchResult struct {
	Hits struct {
		Total int
		Hits  []hit
	}
}

/*根據物件的名稱和版本號來獲取元資料*/
func getMetadata(name string, versionId int) (meta Metadata, e error) {
	// 索引為 metadata ,型別為 objects,檔案 id 為物件名稱和版本號的拼接
	url := fmt.Sprintf(sys.GetMetadataUrl, os.Getenv(sys.EsServer), name, versionId)
	// 通過 GET URL 可以直接獲取該物件的元資料,免除了耗時的搜索操作
	r, e := http.Get(url)
	if e != nil {
		return
	}
	if r.StatusCode != http.StatusOK {
		e = fmt.Errorf(sys.FailToGetMetadata, name, versionId, r.StatusCode)
		return
	}
	result, _ := ioutil.ReadAll(r.Body)
	// 將請求結果反序列化為元資料結構
	json.Unmarshal(result, &meta)
	return
}

/*根據物件名稱獲取最新版本的元資料*/
func SearchLatestVersion(name string) (meta Metadata, e error) {
	// 構建 url 時需要將名稱轉移成 url 字符
	url := fmt.Sprintf(sys.SearchLatestVersionUrl, os.Getenv(sys.EsServer), url.PathEscape(name))
	r, e := http.Get(url)
	if e != nil {
		return
	}
	if r.StatusCode != http.StatusOK {
		e = fmt.Errorf(sys.FailToSearchLatestMetadata, r.StatusCode)
		return
	}
	result, _ := ioutil.ReadAll(r.Body)
	var sr searchResult
	// 請求結果反序列化
	json.Unmarshal(result, &sr)
	// 如果長度為 0 則沒有搜索結果,直接回傳
	if len(sr.Hits.Hits) != 0 {
		meta = sr.Hits.Hits[0].Source
	}
	return
}

/*根據物件的名稱和版本號來獲取元資料*/
func GetMetadata(name string, version int) (Metadata, error) {
	// 沒有指定版本號時默認回傳最新版本的元資料
	if version == 0 {
		return SearchLatestVersion(name)
	}
	return getMetadata(name, version)
}

/*向 ES 服務上傳一個新的元資料*/
func PutMetadata(name string, version int, size int64, hash string) error {
	doc := fmt.Sprintf(sys.MetadataJson, name, version, size, hash)
	client := http.Client{}
	url := fmt.Sprintf(sys.PutMetadataUrl, os.Getenv(sys.EsServer), name, version)
	request, _ := http.NewRequest(http.MethodPut, url, strings.NewReader(doc))
	r, e := client.Do(request)
	if e != nil {
		return e
	}
	if r.StatusCode == http.StatusConflict {
		return PutMetadata(name, version+1, size, hash)
	}
	if r.StatusCode != http.StatusCreated {
		result, _ := ioutil.ReadAll(r.Body)
		return fmt.Errorf(sys.FailToPutMetadata, r.StatusCode, string(result))
	}
	return nil
}

/*版本號加一*/
func AddVersion(name, hash string, size int64) error {
	// 獲取目前最新的版本
	version, e := SearchLatestVersion(name)
	if e != nil {
		return e
	}
	// 創建一個最新的版本號
	return PutMetadata(name, version.Version+1, size, hash)
}

/*搜索物件的全部版本*/
func SearchAllVersions(name string, from, size int) ([]Metadata, error) {
	// 不指定名字時則搜索全部物件的全部版本,指定名字時則搜索某個物件的全部版本
	url := fmt.Sprintf(sys.SearchAllVersionsUrl, os.Getenv(sys.EsServer), from, size)
	if name != "" {
		url += "&q=name:" + name
	}
	r, e := http.Get(url)
	if e != nil {
		return nil, e
	}
	metas := make([]Metadata, 0)
	result, _ := ioutil.ReadAll(r.Body)
	var sr searchResult
	json.Unmarshal(result, &sr)
	for i := range sr.Hits.Hits {
		metas = append(metas, sr.Hits.Hits[i].Source)
	}
	return metas, nil
}

/*洗掉指定的版本*/
func DelMetadata(name string, version int) {
	client := http.Client{}
	url := fmt.Sprintf(sys.DelMetadataUrl, os.Getenv(sys.EsServer), name, version)
	request, _ := http.NewRequest(http.MethodDelete, url, nil)
	client.Do(request)
}

type Bucket struct {
	Key         string
	Doc_count   int
	Min_version struct {
		Value float32
	}
}

type aggregateResult struct {
	Aggregations struct {
		Group_by_name struct {
			Buckets []Bucket
		}
	}
}

/*搜索版本狀態*/
func SearchVersionStatus(min_doc_count int) ([]Bucket, error) {
	client := http.Client{}
	url := fmt.Sprintf(sys.SearchVersionStatusUrl, os.Getenv(sys.EsServer))
	body := fmt.Sprintf(sys.SearchVersionStatusJson, min_doc_count)
	request, _ := http.NewRequest(http.MethodGet, url, strings.NewReader(body))
	r, e := client.Do(request)
	if e != nil {
		return nil, e
	}
	b, _ := ioutil.ReadAll(r.Body)
	var ar aggregateResult
	json.Unmarshal(b, &ar)
	return ar.Aggregations.Group_by_name.Buckets, nil
}

func HasHash(hash string) (bool, error) {
	url := fmt.Sprintf(sys.HasHashUrl, os.Getenv(sys.EsServer), hash)
	r, e := http.Get(url)
	if e != nil {
		return false, e
	}
	b, _ := ioutil.ReadAll(r.Body)
	var sr searchResult
	json.Unmarshal(b, &sr)
	return sr.Hits.Total != 0, nil
}

func SearchHashSize(hash string) (size int64, e error) {
	url := fmt.Sprintf(sys.SearchHashSizeUrl, os.Getenv(sys.EsServer), hash)
	r, e := http.Get(url)
	if e != nil {
		return
	}
	if r.StatusCode != http.StatusOK {
		e = fmt.Errorf(sys.FailToSearchHashSize, r.StatusCode)
		return
	}
	result, _ := ioutil.ReadAll(r.Body)
	var sr searchResult
	json.Unmarshal(result, &sr)
	if len(sr.Hits.Hits) != 0 {
		size = sr.Hits.Hits[0].Source.Size
	}
	return
}

版本資訊搜索

package version

import (
	"demo/es"
	"encoding/json"
	"log"
	"net/http"
	"strings"
)

/*處理版本搜索*/
func Handler(w http.ResponseWriter, r *http.Request) {
	// 非 GET 方法時回應方法不允許
	m := r.Method
	if m != http.MethodGet {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	// 其實是分頁引數,一頁最多有 1000 條記錄,默認從第 0 條開始往后取資料
	// 當回傳值的長度不等于 1000 時,則說明后續沒有資料了,直接回傳
	// 當回傳值等于 1000 時,說明后續可能有資料, from 則從 1000 條開始往后取資料
	from := 0
	size := 1000
	// 若未指定名字,則切割 URL 之后名字為空字串
	name := strings.Split(r.URL.EscapedPath(), "/")[2]
	for {
		metas, e := es.SearchAllVersions(name, from, size)
		if e != nil {
			log.Println(e)
			// 服務器內部錯誤
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		// 遍歷結果集
		for i := range metas {
			// 格式化為 json 回傳
			b, _ := json.Marshal(metas[i])
			w.Write(b)
			w.Write([]byte("\n"))
		}

		if len(metas) != size {
			return
		}
		from += size
	}
}

散列(hash)工具類封裝

package utils

import (
"crypto/sha256"
"encoding/base64"
"io"
"net/http"
"strconv"
"strings"
)

/*從 header 獲取偏移量*/
func GetOffsetFromHeader(h http.Header) int64 {
	byteRange := h.Get("range")
	if len(byteRange) < 7 {
		return 0
	}
	if byteRange[:6] != "bytes=" {
		return 0
	}
	bytePos := strings.Split(byteRange[6:], "-")
	offset, _ := strconv.ParseInt(bytePos[0], 0, 64)
	return offset
}

/*從 header 獲取散列值*/
func GetHashFromHeader(h http.Header) string {
	digest := h.Get("digest")
	if len(digest) < 9 {
		return ""
	}
	if digest[:8] != "SHA-256=" {
		return ""
	}
	return digest[8:]
}

/*從 header 獲取內容長度*/
func GetSizeFromHeader(h http.Header) int64 {
	size, _ := strconv.ParseInt(h.Get("content-length"), 0, 64)
	return size
}

/*計算散列值*/
func CalculateHash(r io.Reader) string {
	h := sha256.New()
	io.Copy(h, r)
	return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

PUT、GET、DELETE 處理函式

package objects

import (
	"demo/apiServer/heartbeat"
	"demo/apiServer/locate"
	"demo/apiServer/objectStream"
	"demo/es"
	"demo/sys"
	"demo/utils"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

/*介面服務的 PUT 和 GET 請求是將 HTTP 請求轉發到資料服務,實際上是呼叫資料服務的 PUT 和 GET 方法*/
func Handler(w http.ResponseWriter, r *http.Request) {
	m := r.Method

	// PUT 方法時,創建或者替換資源
	if m == http.MethodPut {
		put(w, r)
		return
	}

	// GET 方法時,獲取資源
	if m == http.MethodGet {
		get(w, r)
		return
	}

	// 版本洗掉
	if m == http.MethodDelete {
		del(w,r)
		return
	}
	// 其他方式時,回傳狀態碼,方法不允許
	w.WriteHeader(http.StatusMethodNotAllowed)
}

/*處理介面服務 PUT 請求*/
func put(w http.ResponseWriter, r *http.Request) {
	// 按以前的步驟,這里應該獲取存盤物件名字,不過從 header 中取物件的散列值作為名字
	hash := utils.GetHashFromHeader(r.Header)
	if hash == "" {
		log.Println(sys.MissingObjectHash)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	// 存盤請求資料,散列值要作轉義
	httpStatus, e := storeObject(r.Body, url.PathEscape(hash))
	if e != nil {
		log.Println(e)
		w.WriteHeader(httpStatus)
		return
	}
	if httpStatus != http.StatusOK {
		w.WriteHeader(httpStatus)
		return
	}

	// 獲取名字和大小,新增一個物件版本
	name := strings.Split(r.URL.EscapedPath(), "/")[2]
	size := utils.GetSizeFromHeader(r.Header)
	e = es.AddVersion(name, hash, size)
	if e != nil {
		log.Println(e)
		w.WriteHeader(http.StatusInternalServerError)
	}

	// 回傳結果
	w.WriteHeader(httpStatus)
}

func storeObject(r io.Reader, obj string) (int, error) {
	// 獲取介面服務節點存盤物件的流
	stream, e := putStream(obj)
	if e != nil {
		return http.StatusServiceUnavailable, e
	}
	// 將請求資料體拷貝到流 stream
	io.Copy(stream, r)
	// 關閉流
	e = stream.Close()
	if e != nil {
		return http.StatusInternalServerError, e
	}
	// 回傳成功狀態碼
	return http.StatusOK, nil
}

func putStream(obj string) (*objectStream.PutStream, error) {
	// 隨機選擇一個資料服務節點
	server := heartbeat.ChooseRandomDataServer()
	// 若沒有可用的資料服務節點則回傳錯誤資訊
	if server == "" {
		return nil, fmt.Errorf(sys.DataServerNotFound)
	}
	// 回傳資料服務節點存盤物件的流
	return objectStream.NewPutStream(server, obj), nil
}

/*處理介面服務 GET 請求*/
func get(w http.ResponseWriter, r *http.Request) {
	// 獲取存盤物件名稱和版本號
	name := strings.Split(r.URL.EscapedPath(), "/")[2]
	versionId := r.URL.Query()["version"]
	version := 0
	var e error
	if len(versionId) != 0 {
		// 版本號字串轉數字
		version, e = strconv.Atoi(versionId[0])
		if e != nil {
			log.Println(e)
			w.WriteHeader(http.StatusBadRequest)
			return
		}
	}
	// 根據名字和版本號來獲取元資料
	meta, e := es.GetMetadata(name, version)
	if e != nil {
		log.Println(e)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	// 元資料散列值為空則無該物件
	if meta.Hash == "" {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	// 散列值要作 URL 轉移
	object := url.PathEscape(meta.Hash)
	// 根據散列值獲取物件資料
	stream, e := getStream(object)
	if e != nil {
		log.Println(e)
		w.WriteHeader(http.StatusNotFound)
		return
	}
	// 將資料流拷貝到回應流 w
	io.Copy(w, stream)
}

func getStream(obj string) (io.Reader, error) {
	// 根據存盤物件名稱進行定位
	server := locate.Locate(obj)
	// 未找到該存盤物件時回傳定位失敗錯誤
	if server == "" {
		return nil, fmt.Errorf(sys.DataServerLocateFail, obj)
	}
	// 定位到存盤物件時,回傳該物件的資料流
	return objectStream.NewGetStream(server, obj)
}


/*處理介面服務 DELETE 請求*/
func del(w http.ResponseWriter, r *http.Request) {
	// 獲取名字
	name := strings.Split(r.URL.EscapedPath(),"/")[2]
	v,e := es.SearchLatestVersion(name)
	if e != nil {
		log.Println(e)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	// 插入一條新的元資料作洗掉標記
	e = es.PutMetadata(name,v.Version + 1,0,"")
	if e != nil {
		log.Println(e)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
}

測驗

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/336186.html

標籤:其他

上一篇:C++還在用printf/cout進行Debug?學習一下如何自己寫日志庫吧(上篇)

下一篇:大資料Spark MLlib推薦演算法

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more