简易的站内搜索引擎 (万字长文!!绝对值得一看!!)

article/2025/9/9 15:07:16

搜索引擎的实现

  • 项目简介
    • 项目背景
    • 项目开始前
      • 开始前的准备
    • 四个模块
      • 预处理模块
      • 索引模块
      • 搜索模块
      • 服务器模块

项目简介

这里所实现的并非如同百度、谷歌一样的全网搜索,我们的硬件条件达不到,并且技术实力也不够,但是我们可以按照搜索引擎的基本原理,来实现一个站内搜索,实现原理也算是大同小异,此项目分为四个模块预处理模块索引模块搜索模块服务器模块
在这里插入图片描述

项目背景

想要写一个搜索引擎也是源于偶然,在知乎上看到一篇文章,说是百度搜索为什么可以那么快?回答里说了很多方面的技术,其中最核心的就是倒排索引,这让我产生了浓厚的兴趣,但是因为实力和设备都有欠缺,没法做一个像是百度和搜狗一样的全网搜索,但我可以做一个站内搜索,来理解相应的技术。

项目开始前

虽然我们要实现的是站内搜索,但是与全网搜索大同小异,那么我们可以看一看搜索应该要包含什么
在这里插入图片描述
我们可以看到当我们在上面的文本框输入关键字之后点击搜索,在下面会显示出许多具有相关性的搜索结果,而这些搜索结果中至少需要包含以下四个部分:
标题
描述(网页正文摘要出一部分)
展示url
点击url,点击标题会跳转到另外一个url中
因此我们可以仿照百度的方式,来实现我们的搜索引擎

开始前的准备

httplib
g++版本必须得是4.9以上

jieba分词的库
用这个库的时候直接用include是不够的,需要将deps目录下的limonp也拷贝到include目录下

boost: yum install boost-devel.x86_64

jsoncpp: yum install jsoncpp-devel.x86_64

在这里插入图片描述
创建这样的一个目录结构

四个模块

预处理模块

这里就要提一下我为什么会选择boost网站来实现站内搜索了,

  1. 我们暂时无法实现一个全网搜索,只能完成站内搜索
  2. boost官方文档没有一个搜索功能,但是boost文档很常用,没有搜索功能比较麻烦
  3. boost文档提供了两个版本,离线版本在线版本
    boost提供了离线版本,那么我们就可以基于离线版本,分析文档页面的内容,为搜索功能提供支持。点击搜索结果的标题的时候,就能够跳转到在线版本的文档上,而如果网站内容无法直接下载,就必须使用爬虫来抓取页面到本地。

boost 在线文档.

我为什么选择1.53版本的boost呢?其实主要是因为我用的Linux版本是contos7,它默认就是1.53

那么我们现在得到了boost文档的离线版本之后需要干什么呢?
我们下载下来的boost文档,其实就是一个个的html,而这些html里面是有很多内容和标签混合在一起的,而我们需要的只是其中的标题正文url,而我们预处理阶段所要做的就是读取原始的html文档内容,提取我们所要的,整理成一个行文本,以供下面的模块使用
接下来我们就开始写预处理模块的代码了
首先我们需要定义两个变量来表示从哪里读数据和要把最后生成的行文本放到哪个路径下面展示一些 内联代码片

这个变量表示从哪个目录中读取boost文档的html

string g_input_path ="../data/input";

这个变量表示预处理模块输出结果放到哪里

string g_output_path ="../data/tmp/raw_input";

我们还需要一个结构体,来表示一个个的html

struct DocInfo{string title;//文档的标题string url;//文档的urlstring content;//文档的正文};

既然我们要将所有的html都解析成行文件,那么我们首要做的就是将所下载的所有html都枚举加载进来,那么我们就可以封装一个函数

bool EnumFile(const string &input_path, vector<string> *file_list)

其中input_path为输入参数,file_list是输出参数,将上面定义的输入变量传进来,然后将所有的html都枚举到输出参数file_list中。我们的枚举过程中是会遇到目录的,而我们只要枚举html,C++的标准库中没有能做到这个的,但是boost库中可以。

//把boost::filesystem这个命名空间定义一个别名39     namespace fs = boost::filesystem;40     fs::path root_path(input_path);41     if(!fs::exists(root_path)){42       std::cout << "当前的目录不存在" << std::endl;43     }4445     //递归目录迭代器,迭代器使用循环实现的时候可以自动完成递归4647     fs::recursive_directory_iterator end_iter;48     for(fs::recursive_directory_iterator begin_iter(root_path); begin_iter != end_iter; ++begin_iter){49         //需要判定当前的路径对应的是不是一个普通文件50         //如果是目录直接跳过51         if(!fs::is_regular_file(*begin_iter))52         {53             continue;54         }55         //当前路径对应的文件是不是一个html文件,如果不是也跳过56         if(begin_iter->path().extension() != ".html"){57           continue;58         }59 60         //把得到的html加入到最终结果的vector中                                                                                                          61         file_list->push_back(begin_iter->path().string());

接下来就是遍历vector里面的html了,打开每一个html,然后解析其中的内容,解析出标题、正文、url,对应我们之前创建好的结构体
找到标题

70 //找到html中的title标签71 bool ParseTitle(const string& html, string *title){72     size_t beg = html.find("<title>");73     if(beg == string::npos){74         std::cout << "标题未找到" << std::endl;75         return false;76     }77     size_t end = html.find("</title>");78     if(end == string::npos){79         std::cout <<"标签未找到" <<std::endl;80         return false;81     }82     beg += string("<title>").size();83     if(beg >= end){84         std::cout <<"标题位置不合法" <<std::endl;85         return false;86     }87     *title = html.substr(beg, end-beg);88     return true;89 90 }

获取url

 70 //找到html中的title标签71 bool ParseTitle(const string& html, string *title){72     size_t beg = html.find("<title>");73     if(beg == string::npos){74         std::cout << "标题未找到" << std::endl;75         return false;76     }77     size_t end = html.find("</title>");78     if(end == string::npos){79         std::cout <<"标签未找到" <<std::endl;80         return false;81     }82     beg += string("<title>").size();83     if(beg >= end){84         std::cout <<"标题位置不合法" <<std::endl;85         return false;86     }87     *title = html.substr(beg, end-beg);88     return true;89 90 }

找到正文

101 //获取正文
102 bool ParseContent(const string& html, string* content){
103     //这里引入一个bool变量,当进入标签之后,此值为false
104     //判断这个变量就能知道是在标签内还是在标签外了
105     bool is_content = true;
106     for(auto c : html){
107         if(is_content){
108             //当前是正文
109             if(c == '<'){
110                 is_content = false;
111             }
112             else{
113                 //当前是普通字符,就把结果写入到content中
114                 if(c == '\n'){
115                     c = ' ';    
116                 }
117                 content->push_back(c);
118             }
119         }
120         else{
121             //当前是在标签内
122             if(c == '>')
123             {
124                 //标签结束
125                 is_content = true;
126             }                                                                                                                                           
127             //标签里的其他内容都直接忽略掉
128         }
129     }
130     return true;
131 }

最后只需要将我们解析出来的结果写入到我们最开始设置好的输出文件中就可以了,不过要记得选择一个不可见分隔符对标题、正文、url进行分割!!不然会出现粘包问题!!
以上就是预处理模块的全部内容了,可以编译运行一下,看看输出文件中是否如愿解析出来了。

索引模块

现在我们已经有了解析好的行文本了,那么我们接下来就要进入索引模块了,索引模块是最核心的部分,在这个模块我们就要引入倒排索引了!!!
不管是站内搜索还是全网搜索,面对大量的数据,最核心的点就是效率,我们需要在大量的数据中,快速而准确的找出我们所要的数据,那么解决这个问题,最核心的就是倒排索引。
那么什么是倒排索引呢?
我们来看一个经典的例子,我所学习倒排索引的时候,就是看的这个例子
在这里插入图片描述
中文和英文等语言不同,单词之间没有明确分隔符号,所以首先要用分词系统将文档自动切分成单词序列。这样每个文档就转换为由单词序列所组成,然后对每个不同的单词赋予唯一的单词编号,同时记录下哪些文档包含这个单词,在如此处理结束后,我们可以得到最简单的倒排索引。
在这里插入图片描述
我们可以概括性的理解为:正排索引就是利用文档id来得到文本内容,倒排索引就是根据文本内容来得到文本id
那么我们的基本逻辑就是构建出正排索引,并且对字符串进行分词切割,然后切分出来的单词,再根据切分的单词和正排索引构建倒排索引,通过倒排索引找到对应的文档id,再通过文档id查找正排索引,从正排索引找到文档的内容。
因此我们现在要做的就是:构建正排索引构建倒排索引进行分词查找倒排索引查找正排索引
下面我们构建一下正排索引和倒排索引的基本结构体

 23 struct DocInfo {                                                        24     int64_t doc_id;25     string title;26     string url;27     string content;28 };29 30 // 倒排索引是给定词, 映射到包含该词的文档 id 列表. (此处不光要有文档 id,31 // 还得有权重信息, 以及该词的内容)32 struct Weight {33     // 该词在哪个文档中出现34     int64_t doc_id;35     // 对应的权重是多少36     int weight;37     // 词是什么                                                                                                                                       38     string word;                                                                                                                            39 };                                                                                                                     

这就是我们需要做的所有操作

 37 typedef vector<Weight> InvertedList;38 39 // Index 类用于表示整个索引结构, 并且提供一些供外部调用的 API40 class Index {41   private:42     // 索引结构43     // 正排索引, 数组下标就对应到 doc_id44     vector<DocInfo> forward_index;45     // 倒排索引, 使用一个 hash 表来表示这个映射关系46     unordered_map<string, InvertedList> inverted_index;47 48   public:49     Index();50     // 提供一些对外调用的函数51     // 1. 查正排52     const DocInfo* GetDocInfo(int64_t doc_id);53     // 2. 查倒排54     const InvertedList* GetInvertedList(const string& key);55     // 3. 构建索引56     bool Build(const string& input_path);57     // 4. 分词函数58     void CutWord(const string& input, vector<string>* output);59 60   private:                                                                                                                                            61     DocInfo* BuildForward(const string& line);62     void BuildInverted(const DocInfo& doc_info);63 64     cppjieba::Jieba jieba;65 };

接下来就具体实现一下,咱们先挑简单的查正排和查倒排来实现一下

   28 const DocInfo* Index::GetDocInfo(int64_t doc_id) {                             29     if (doc_id < 0 || doc_id >= forward_index.size()) {                                                                          30         return nullptr;                                                                                                               31     }                                                                                                 32     return &forward_index[doc_id];                                                  33 }                                                                                                                34                                                                                 35 const InvertedList* Index::GetInvertedList(const string& key) {                36     auto it = inverted_index.find(key);                                                                                                       37     if (it == inverted_index.end()) {                                                                                 38         return nullptr;                                                                                             39     }                                                                                                 40     return &it->second;                                                             41 }                                                                                                     

这俩就是查找正排和倒排,查不到就返回nullptr,查到了就返回对应的指针即可
接下来要做的就是构建索引了

   43 bool Index::Build(const string& input_path) {44     // 1. 按行读取输入文件内容(上个环节预处理模块生成的 raw_input 文件)45     //    每一行又分成三个部分, 使用 \3 来切分, 分别是标题, url, 正文46     std::cerr << "开始构建索引" << std::endl;47     std::ifstream file(input_path.c_str());48     if (!file.is_open()) { 49         std::cout << "raw_input 文件打开失败" << std::endl;50         return false;      51     }                      52     string line;           53     while (std::getline(file, line)) {54         // 2. 解析成 正排结构的DocInfo 对象, 并构造为正排索引55         DocInfo* doc_info = BuildForward(line);56         if (doc_info == nullptr) {57             std::cout << "构建正排失败!" << std::endl;58             continue;      59         }                  60         // 3.构造成倒排索引.61         BuildInverted(*doc_info);62                            63         //此时需要知道进度是多少,但是如果每一个都进行打印64         //每个数据都进行I/O操作的话过于影响效率65         if (doc_info->doc_id % 100 == 0) {                                                                                                            66             std::cerr << doc_info->doc_id << std::endl;67         }68     }69     std::cerr << "结束构建索引" << std::endl;70     file.close();71     return true;72 }

这是整体的构建思路,我们接下来就分别完成倒排索引和正排索引
=正排索引=
我们要做的核心操作: 按照 设定的分隔符行文本 进行切分, 第一个部分就是标题, 第二个部分就是 url, 第三个部分就是正文,然后将这三个部分填充到正排索引对应的结构体中即可。

   77 DocInfo* Index::BuildForward(const string& line) {78     // 1. 先把 line 按照 \3 切分成 3 个部分79     vector<string> tokens;80     common::Util::Split(line, "\3", &tokens);81     if (tokens.size() != 3) {82         return nullptr;                                                                                                                               83     }                         84     // 2. 把切分结果填充到 DocInfo 对象中85     DocInfo doc_info;                    86     doc_info.doc_id = forward_index.size();87     doc_info.title = tokens[0];            88     doc_info.url = tokens[1];              89     doc_info.content = tokens[2];90     forward_index.push_back(std::move(doc_info));91     return &forward_index.back();                92 }                                                

这里的切分,在C++的标准库中并没有,但是boost库中是有的,因此我们用boost库中的split函数,不过这里我将split封装了一下,比boost库中的split函数少了一个参数,也就是boost::token_compress_on:将连续多个分隔符当一个,默认没有打开,当用的时候一般是要打开的。
boost:: token_compress_off:不会压缩分割结果,连续的分隔符时会返回 ""字符串
我默认选择了compress_off因为也许有的html中的字段是空的,那我们也不能将其压缩。
并且最后我选择了将doc_info转化成了右值(将亡值)进行了右值引用(效率就是一点点省出来的哦)
接下来就是构建倒排索引了,而我们构建倒排索引要做的首先就是构建正排和分词,现在正排已经构建完毕了,那我们就需要分词了,分词我们选择了cppjieba分词库来帮我们完成

  147 void Index::CutWord(const string& input, vector<string>* output) {148     jieba.CutForSearch(input, *output);149 }

那么我们现在终于可以开始期待已久的倒排索引了

   97 void Index::BuildInverted(const DocInfo& doc_info) {98     // 创建专门用于统计词频的结构99     struct WordCnt {       100         int title_cnt;     101         int content_cnt;   102         WordCnt() : title_cnt(0), content_cnt(0) {103         }                  104     };                     105     unordered_map<string, WordCnt> word_cnt_map;106     // 针对标题进行分词    107     vector<string> title_token;108     CutWord(doc_info.title, &title_token);109     // 遍历分词结果, 统计每个词出现的次数110     for (string word : title_token) {111         //将只是大小写不同的词当作同一个词来处理112         //因此都转化成小写                                                                                                                            113         boost::to_lower(word);                                        114         ++word_cnt_map[word].title_cnt;                               115     }                                                                 116     // 针对正文进行分词                                               117     vector<string> content_token;                                     118     CutWord(doc_info.content, &content_token);                        119     // 遍历分词结果, 统计每个词出现的次数     120     for (string word : content_token) {                            121         boost::to_lower(word);122         ++word_cnt_map[word].content_cnt;123     }124     // 填充Weight对象125     for (const auto& word_pair : word_cnt_map) {126         // 构造 Weight 对象127         Weight weight;128         weight.doc_id = doc_info.doc_id;129         // 权重 = 标题出现次数 * 10 + 正文出现次数130         weight.weight = 10 * word_pair.second.title_cnt + word_pair.second.content_cnt;131         weight.word = word_pair.first;132 133         // 把 weight 对象插入到倒排索引中                                                                                                             134         InvertedList& inverted_list = inverted_index[word_pair.first];135         inverted_list.push_back(std::move(weight));                   136     }                                                                 137 }                                                  

整体思路就是将倒排索引设置成一个hash表,key是关键词,value 是倒排拉链 (包含若干个 Weight 对象),同时设置一个hash表,来统计词频key是关键词,value是WordCnt结构体,因此统计出标题的词频和正文的词频,根据这两者的词频算出权重,将权重和分词结果、文档id填入Weight对象,再将Weight对象填入到第一个hash表中。

以上就是索引部分的全部内容了。

搜索模块

上面我们构建好了索引模块,现在我们的搜索模块就是要利用上面的索引,首先我们还是将这个模块进行一个封装

   68 class Searcher {                                                                                                                       69   private:                                                                                                                                 70     Index* index;                                                                                                  71                                                                                                                                           72   public:                                                               73     Searcher() : index(new Index()) {                                                                          74     }                                                                                                                                     75     bool Init(const string& input_path);                                                                                               76     bool Search(const string& query, string* results);                                                                                    77                                                                                                                                             78   private:                                                              79     string GenerateDesc(const string& content, const string& word);                                                                         80 }; 

这里的对象是Index的一个指针,因为我们要使用到上一个类,而Init初始化也是这个用处

  145 bool Searcher::Init(const string& input_path) {146     return index->Build(input_path);147 }

也就是将所有的正排索引和倒排索引都建立好,以便我们接下来使用,接下来就是查询倒排了,并且按照权重进行排序了

  149 // 搜索查询词, 得到搜索结果.                                                                                                                          150 bool Searcher::Search(const string& query, string* output) {151     // 针对查询词进行分词 152     vector<string> tokens;153     index->CutWord(query, &tokens);154     // 根据分词结果, 查倒排, 把相关的文档都获取到155     vector<Weight> all_token_result;156     for (string word : tokens) {157         boost::to_lower(word);158         auto* inverted_list = index->GetInvertedList(word);159         if (inverted_list == nullptr) {160             continue;161         }162         //  将搜索到的结果都合并到一起进行统一的排序163         all_token_result.insert(all_token_result.end(), inverted_list->begin(), inverted_list->end());164     }165     std::sort(all_token_result.begin(), all_token_result.end(), [](const Weight& w1, const Weight& w2) {166         return w1.weight > w2.weight;167     });

然后用得到的文档id,去查找正排,再将正排查到的行文本转化成json格式以便我们使用,使用 jsoncpp 这个库来实现 json 的操作.

  170     Json::Value results; 171     for (const auto& weight : all_token_result) {                                                                                                     172         // 根据 weight 中的 doc_id 查正排        173         const DocInfo* doc_info = index->GetDocInfo(weight.doc_id);174         // 把这个 doc_info 对象再进一步的包装成一个 JSON 对象      175         Json::Value result;                                        176         result["title"] = doc_info->title;                   177         result["url"] = doc_info->url;    178         result["desc"] = GenerateDesc(doc_info->content, weight.word);179         results.append(result);                                       180     }                                                                 181     // 把得到的 results 这个 JSON 对象序列化成字符串. 写入 output 中182     Json::FastWriter writer;                                        183     *output = writer.write(results);                                184     return true;                    185 }                            

而这里的desc,就是在网页上所显示的,文本的部分摘要的内容,而我们要用多少文本来作为摘要呢?
我们先根据正文, 找到 word 出现的位置. 以该位置为中心, 往前找 80 个字节, 作为描述的起始位置.
再从起始位置开始往后找 160 个字节, 作为整个描述. 这里的取值完全根据个人自定义就行

  187 string Searcher::GenerateDesc(const string& content, const string& word) {188     // 1. 先找到 word 在正文中出现的位置.189     size_t first_pos = content.find(word);190     size_t desc_beg = 0;191     if (first_pos == string::npos) {192         // 如果找不到, 就直接从头开始作为起始位置.193         if (content.size() < 160) {194             return content;195         }196         string desc = content.substr(0, 160);197         desc[desc.size() - 1] = '.';198         desc[desc.size() - 2] = '.';199         desc[desc.size() - 3] = '.';200         return desc;201     }202     // 2. 找到了 first_pos 位置, 以这个位置为基准, 往前找一些字节.203     desc_beg = first_pos < 80 ? 0 : first_pos - 80;204     if (desc_beg + 160 >= content.size()) {205         // desc_beg 后面的内容不够 160 了, 直接到末尾结束即可                                                                                         206         return content.substr(desc_beg);                     207     } else {                            208         string desc = content.substr(desc_beg, 160);209         desc[desc.size() - 1] = '.';                210         desc[desc.size() - 2] = '.';211         desc[desc.size() - 3] = '.';212         return desc;                213     }               214 }    

这就是搜索模块所实现的所有功能了,像是测试,我就不在这里写了,不过完成每一个模块的时候都要测试一下,不要最后发现出错了都不知道去哪里找

服务器模块

接下来就是最后的一个模块了,服务器模块,这里我们就用cpp-httplib库来搭建服务器了,就不自己手动用stocket套接字搭建了,根据项目文档来使用即可,这里我就不多介绍了

   25     Server server;26     server.Get("/searcher", [&searcher](const Request& req, Response& resp) {27         if (!req.has_param("query")) {28             resp.set_content("您发的请求参数错误", "text/plain");29             return;30         }31         string query = req.get_param_value("query");32         string results;33         searcher.Search(query, &results);34         resp.set_content(results, "application/json");                                                                                                35     });                                                                              

先创建Server对象,然后调用Get函数,这个函数有两个参数,第一个表示的是,你要用哪个http路径来触发get操作,第二个参数是一个lambda表达式,是一个回调函数,也就是当服务器收到第一个参数的请求的时候,会触发回调函数的操作,Request就是请求,Response就是相应,我们收到请求之后就可以解析请求,根据请求内容,来完成响应。set_content就是将我们的结果写到响应的body中,然后返回,他的第二个参数就是返回的body的数据格式,text/plain就是纯文本,application/json就是json格式。
最后将我们的所做的前端页面,也就是静态资源挂载就可以了。

   36     // 告诉服务器, 静态资源存放在 wwwroot 目录下. (html, css, js, 图片....)          37     server.set_mount_point("/", "./ShySearcher");                                    38     // 3. 启动服务器                                                                 39     server.listen("0.0.0.0", 10001);                                                 

我前端做的不太好,也就不给大家展示了。
咱们的站内搜索引擎也基本就结束了。
在这里插入图片描述在这里插入图片描述


http://chatgpt.dhexx.cn/article/w8lltHK0.shtml

相关文章

站内搜索引擎

1.什么是搜索引擎&#xff1f; 如图所示&#xff1a; 我用的是谷歌浏览器&#xff0c;但是我的搜索引擎可以跟换 。切换到bing主页 在搜索框中我们输入一段话&#xff0c;跳到一个带有搜索结果的页面如下&#xff1a; 搜索引擎的核心功能&#xff1a;查找用户输入的词/一句话 …

SecureCRT 软件完全汉化

在正常汉化包的基础上&#xff0c;删除一个菜单文件&#xff0c;然后再运行"SecureCRT_CHS.exe" 程序即可 注意&#xff1a;如果以前是英文版本&#xff0c;则需要删除菜单配置文件后才可以正常汉化。直接删除SecureCRT配置目录下的"...\Config\SCRTMenuToolbar…

secureCRT安装、破解

SecureCRT是最常用的终端仿真程序&#xff0c;简单的说就是Windows下登录UNIX或Liunx服务器主机的软件。本文讲解SecureCRT的安装、破解与使用。 下载&安装 1.从https://pan.baidu.com/s/1dGMKJF7下载 2.解压缩下载的文件&#xff0c;双击scrt736-x64.exe执行安装。 破解…

【工具】SecureCR-8.5下载、安装激活和使用教程(包含常用设置)

目录 一、安装包下载 二、安装教程 三、激活操作 四、使用教程 五、常用设置 一、安装包下载 SecureCRT8.5安装包&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1yy677I99ln_3evoHc5dMXg 提取码&#xff1a;9tyj 二、安装教程 1. 解压、双击进行安装 2. 安装进…

SecureCRT的下载、安装( 过程非常详细!!值得查看)

SecureCRT的下载、安装&#xff08; 过程非常详细&#xff01;&#xff01;值得查看&#xff09; 简单介绍下SecureCRT一、SecureCRT的下载二、SecureCRT的安装三、SecureCRT的使用 简单介绍下SecureCRT SecureCRT是一款支持SSH&#xff08;SSH1和SSH2&#xff09;的终端仿真程…

SecureCRT和SecureFX的下载和安装2022

小编在新电脑上安装SecureCRT和SecureFX&#xff0c;按照之前写的文章步骤SecureCRT和SecureFX的下载和安装2021在使用注册机SecureFX.-kg.exe安装SecureFX的时候报错了&#xff0c;提示mfc100u.dll和msvcp100.dll两个文件找不到。&#xff08;注册机keygen.exe安装SecureCRT可…

SecureCRT 64位 破解版v8.1.4及安装

securecrt 破解版是一款支持SSH1和SSH2的终端仿真程序&#xff0c;这个程序能够在windows系统中登陆UNIX或Linux的服务器主机并且还能进行管理设置&#xff0c;是一款非常强大的ssh传输软件&#xff0c;是用于连接运行包括Windows、UNIX和VMS的理想工具。并且它还有打印功能、可…

SecureCRT下载和破解

一. secureCRT下载 secureCRT是一款支持SSH的终端仿真程序&#xff0c;简单的说是Windows下登录Linux服务器的工具。下载时&#xff0c;需要下载scrt安装包和Keygen注册机包。下载链接secureCRT安装包。 1. 下载文件 2. 安装SCRT 按照指定步骤安装即可 二. 破解 安装完成之…

SecureCRT 8.5下载安装破解

SecureCRT 8.5下载安装破解 不用关闭防火墙&#xff0c;不用下载注册机&#xff0c;不用csdn下载积分 不用关闭防火墙&#xff0c;不用下载注册机&#xff0c;不用csdn下载积分 公司领导让我下载SecureCRT&#xff0c;网上找了很多教程&#xff0c;注册机也下载了&#xff0c;…

【工具使用】SecureCRT的下载、安装图文详细过程介绍

本文目录 一、SecureCRT的介绍 二、SecureCRT的下载 三、SecureCRT的安装 四、SecureCRT的使用 一、SecureCRT的介绍 SecureCRT是一款支持SSH&#xff08;SSH1和SSH2&#xff09;的终端仿真程序&#xff0c;简单地说是Windows下登录UNIX或Linux服务器主机的软件。 Secure…

2020最详细下载安装注册最新版 Secure CRT 8.7

文章目录 一.下载SecureCRT 8.7二.安装SecureCRT 8.7三.注册SecureCRT 8.7 一.下载SecureCRT 8.7 官网下载 网址:https://www.vandyke.com/products/securecrt/ 2.选择系统 3.选择64位或者32位 4.输入邮箱密码 邮箱 adminmail.bccto.me 密码 wheretogo8888 5.点击下载,下…

SecureCRT的下载安装

亲测成功了&#xff0c;按照下面的步骤完成即可&#xff01; 下载安工具包包地址连接&#xff1a;网盘地址点击即可 提取码&#xff1a;0lp7 1、下载SecureCRT 2、从百度网盘下载SecureCRT&#xff0c;页面如下 3、安装SecureCRT 4、激活SecureCRT 第一步&#xff1a;打开安装…

SecureCRT免安装版免费下载

https://yunpan.360.cn/surl_y2qdTx4jfhq &#xff08;提取码&#xff1a;4993&#xff09; 360安全云盘虽然需要充值&#xff0c;但上传下载不限速&#xff0c;个人特别推荐360安全云盘

securecrt破解版64位

securecrt 破解版是一款支持SSH1和SSH2的终端仿真程序&#xff0c;这个程序能够在windows系统中登陆UNIX或Linux的服务器主机并且还能进行管理设置&#xff0c;是一款非常强大的ssh传输软件&#xff0c;是用于连接运行包括Windows、UNIX和VMS的理想工具。并且它还有打印功能、可…

SecureCRT 免安装、绿色版、免费版本

SecureCRT远程连接Linux服务器 文章目录 1. 下载软件2. 解压软件3. 双击运行4. 选择SecureCRT5. 图标点击&#xff0c;输入用户名6. 添加密码&#xff0c;点击确定7. 连接成功 1. 下载软件 链接https://pan.baidu.com/s/1vv40uI_0uwIagPGm7FS9_g 提取码t32h 2. 解压软件 3. 双…

SecureCRT绿色版的下载和安装

SecureCRT绿色版的下载、安装 一、SecureCRT绿色版的下载 链接&#xff1a;https://pan.baidu.com/s/1ZMeWbJnatNTrBwUPkcjNOg 提取码&#xff1a;bbwt 1. 下载完成后将压缩包解压缩到自己电脑的想要压缩的安装目录下 解压后 双击运行 默认登录模式是SSH2&#xff0c;根据自…

18.CRT的绿色版安装和使用。

一、找到SecureCRT.exe点击启动。 二、在centos虚拟机中输入命令ifconfig&#xff0c;查询IP地址&#xff08;192.168.0.104&#xff09;。 三、在主机名中输入IP地址和用户名&#xff0c;点击连接。&#xff08;虚拟机查询的IP地址&#xff0c;使用的用户名&#xff09; 主机…

CentOS7 安装CloudStack4.14.0

https://blog.csdn.net/dandanfengyun/article/details/107220199#comments_13468183 按照4.13.1设置首先进行基本设置及基础软件安装完成。然后将4.13.1的安装包改成4.14.0的基本就可以了。 管理节点安装cloudsatck-management 更改cloudstack安装源&#xff0c;尽管是将安装…

CentOS7下搭建CloudStack4.10.0云平台

一篇学习性质的文章&#xff0c;关于CloudStack怎么实现这些功能一概不了解。只是跟着他人博客学着搭建一下。如有侵权&#xff0c;立删。 建议&#xff08;使用4.11.0 更好&#xff0c;4.10.0 添加主机经常失败&#xff0c;不知是不是个人问题&#xff09; http://docs.clouds…

cloudstack java api_CloudStack核心类ApiServlet、ApiServer、ApiDispatcher、GenericDaoBase源码分析...

ApiServlet 首先从整体上看下ApiServlet&#xff0c;Outline视图如下&#xff0c; 一、注意Inject依赖的是javax.inject.jar&#xff0c;它和spring的Autowired的区别在于使用它时变量不用生成相应的set方法。 二、CloudStack所有的请求都会被ApiSerlet拦截处理&#xff0c;进入…