云vscode搭建--使用容器化部署

2023-11-16

        Vscode作为一个轻量级的IDE,其支持丰富的插件,而通过这些插件我们就可以实现在Vscode中写任何语言的代码。Code-Server是Vscode的网页版,启动Code-Server之后我们就可以在浏览器中打开vscode来愉快的编写代码了。这种方式非常适合我们做linux编程。使用C/C++的时候,在windows上编写的代码在linux上可能跑不了,而且安装linux图形界面,然后在图像界面中使用vscode又很麻烦。当然也可以使用vscode的远程开发。但是我认为启动code-server来在浏览器上使用vscode也是非常方便的。

        随着容器化的发展,现在涌现出了很多云IDE,比如腾讯的Cloud Studio,但是其也是基于Code-Server进行开发部署的,用了它的云IDE后,我便产生出了自己部署一个这样的云IDE的想法。

 

1、Code-Server下载部署

1.1 Code-Server下载

下载地址:https://github.com/coder/code-server/releases/

在这里插入图片描述

 

在上面的网址中下载code-server,并将其传输到linux服务器上。

也可以在linux服务器中直接使用命令来下载:

wget https://github.com/coder/code-server/releases/download/v4.6.1/code-server-4.6.1-linux-amd64.tar.gz

 

1.2 Code-Server部署

  1. 解压tar.gz文件:
 tar -zxvf code-server-4.6.1-linux-amd64.tar.gz
  1. 进入code-server目录:
cd code-server-4.6.1-linux-amd64
  1. 设置密码到环境变量中
export PASSWORD="xxxx"
  1. 启动code-server
./code-server --port 8888 --host 0.0.0.0 --auth password 
  1. 在浏览器中输入ip:8888来访问如下:

在这里插入图片描述

后台运行的方式:

nohup ./code-server --port 8888 --host 0.0.0.0 --auth password &

 

1.3 Docker部署Code-Server

接下来将介绍使用Docker的方式来部署Code-Server:

下面的Dockerfile创建了一个带有Golang开发环境的容器,然后在容器中运行Code-Server,将Dockerfile放在跟code-server-4.4.0-linux-amd64.tar.gz同目录。

  1. 创建名为Dockerfile的文件(Dockerfile要跟code-server的tar.gz文件在同一目录中),将下面内容复制进去
FROM golang

WORKDIR /workspace

RUN cp /usr/local/go/bin/* /usr/local/bin

COPY code-server-4.4.0-linux-amd64.tar.gz .
RUN tar zxvf code-server-4.4.0-linux-amd64.tar.gz

ENV GO111MODULE on 
ENV GOPROXY https://goproxy.cn

ENV PASSWORD abc123

WORKDIR /workspace/code-server-4.4.0-linux-amd64

EXPOSE 9999


CMD ["./code-server", "--port", "9999", "--host", "0.0.0.0", "--auth", "password"]
  1. 然后执行命令构建Docker镜像:
docker build -t code-server .
  1. 运行容器
docker run -d --name code-server -p 9999:9999 code-server

 

2. 一个小问题

下面的内容针对Docker部署的Code-Server。

        想象这样一个场景,我们开发了一个类似Cloud Studio的云IDE,每启动一个工作空间我们就通过Docker或者Kubernetes来创建一个容器,然后在容器中部署一个Code-Server,最后通过将端口暴露出去给用户使用。

        云IDE使用起来很方便,打开和销毁的很迅速,即开即用。用户使用Golang在云IDE中写了一个http服务器,想要在他电脑的浏览器上访问,却发现访问不了。那么为什么Code-Server的端口就可以访问,其它端口无法访问呢。因为我们在启动容器的时候就已经预想到要访问这个端口,然后将端口暴露出去了,也就是建立了端口映射。在容器中新启动的端口并没有建立映射,因此只能在服务器内部访问,而不能在用户电脑上访问。

       那么如何让用户也可以访问到呢,我们可以在主机上部署一个代理服务器,用户访问这个代理服务器,然后转发请求到容器中,再将响应转发给用户。

        那么如何发现用户启动服务器监听了哪个端口呢,首先我能想到的就是启动一个程序每隔一段时间查询一下是否有新的端口被监听。获取端口信息可以使用netstat命令或者lsof命令,在此我选择了netstat,就有了下面的一个程序:

 

2.1 端口监听

这个程序会每隔一秒获取一下有哪些端口处于LISTEN状态,然后对比上一次的状态,看是否有新的端口被监听。当我们监听了新的80端口后,就会输出:Find new port: 80

package main

import (
	"bytes"
	"fmt"
	"os/exec"
	"strconv"
	"time"
)

func main() {
	listener := NewPortListener()
	pc := listener.GetPortChan()
	go listener.FindNewPortLoop()
	for {
		port := <-pc
		fmt.Println("Find new port:", port)
	}
}

type PortListener struct {
	portChan chan uint16
}

func NewPortListener() *PortListener {
	return &PortListener{
		portChan: make(chan uint16, 1),
	}
}

func (p *PortListener) GetPortChan() <-chan uint16 {
	return p.portChan
}

func (p *PortListener) FindNewPortLoop() {
	ports := p.getListeningPorts()          // 程序启动后先获取一次处于Listen状态的端口
	set := map[uint16]struct{}{}
	for _, port := range ports {
		set[port] = struct{}{}
	}

	for {                                   // 然后每隔一秒获取一次,并与前一次的信息进行对比,查找是否启动了新的端口
		tmpSet := map[uint16]struct{}{}     
		ports = p.getListeningPorts()
		for _, port := range ports {
			if _, ok := set[port]; !ok {
				p.portChan <- port
			}
			tmpSet[port] = struct{}{}
		}
		set = tmpSet
		time.Sleep(time.Second * 3)
	}
}

func (p *PortListener) getListeningPorts() []uint16 {
	cmd := exec.Command("netstat", "-ntlp")          // 运行netstat命令获取处于Listen状态的端口信息
	res, err := cmd.CombinedOutput()                 // 获取结果 
	fmt.Println(string(res))
	if err != nil {
		fmt.Println("Execute netstat failed")
		return nil
	}

	return p.parsePort(res)                         // 对结果进行解析
}

func (p *PortListener) parsePort(msg []byte) []uint16 {       // 解析出处于LISTEN状态的端口,只要端口号
	idx := bytes.Index(msg, []byte("tcp"))
	colums := bytes.Split(msg[idx:], []byte("\n"))
	res := make([]uint16, 0, len(colums)-1)
	for i := 0; i < len(colums)-1; i++ {
		item := p.findThirdItem(colums[i])
		if item != nil {
			m := bytes.IndexByte(item, ':') + 1
			for item[m] == ':' {
				m++
			}
			p, err := strconv.Atoi(string(item[m:]))
			if err == nil {
				res = append(res, uint16(p))
			} else {
				fmt.Println(err)
			}
		}
	}

	return res
}

func (p *PortListener) findThirdItem(colum []byte) []byte {
	count := 0
	for i := 0; i < len(colum); {
		if colum[i] == ' ' {
			for colum[i] == ' ' {
				i++
			}
			count++
			continue
		}
		if count == 3 {
			start := i
			for colum[i] != ' ' {
				i++
			}
			return colum[start:i]
		}
		i++
	}

	return nil
}

 

2.2 使用VS-Code插件

但是上面的程序也无法通知到用户,在使用Cloud Studio的时候,启动了新的端口,这个云IDE就会提醒发现了新的端口,是否要在浏览器中访问。因此我就想到了实现这样一个插件,因此下面部分就是实现一个vscode的插件来发现是否有新的端口被监听了,然后提醒用户是否在浏览器中访问。

下面只是简单介绍,想要了解vscode插件的详细开发过程的自行搜索。

  1. 首先安装yeoman脚手架工具,以及官方提供的脚手架工具:
npm install -g yo generator-code
  1. 创建项目,选择要创建的项目以及其它信息
yo code
  1. 创建完成后,就可以编写插件了
// extension.js
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
const vscode = require('vscode');

// this method is called when your extension is activated
// your extension is activated the very first time the command is executed

/**
 * @param {vscode.ExtensionContext} context
 */
function activate(context) {

	// Use the console to output diagnostic information (console.log) and errors (console.error)
	// This line of code will only be executed once when your extension is activated
	

	// The command has been defined in the package.json file
	// Now provide the implementation of the command with  registerCommand
	// The commandId parameter must match the command field in package.json
	let disposable = vscode.commands.registerCommand('port-finder.helloWorld', function () {
		// The code you place here will be executed every time your command is executed

		// Display a message box to the user
		vscode.window.showInformationMessage('Hello World from port_finder!');
	});

	context.subscriptions.push(disposable);

	initGetPorts()
}

var s = new Set() 

function initGetPorts() {
    getListeningPorts(function(ports) {
        ports.forEach(p => {
            s.add(p)
        })

        setInterval(function() {        // 设置定时器,每隔一秒获取一次
            listenPortChange()
        }, 1000)
    })
}

function listenPortChange() {
    // 获取处于LISTEN状态的端口
    getListeningPorts(function(ports) {
        var tmpSet = new Set()     
        ports.forEach(p => {
            if (!s.has(p)) {
                // 发现新的端口被监听就提醒用户是否在浏览器中打开
                vscode.window.showInformationMessage("发现新开启的端口:" + p + ",是否在浏览器中访问?", "是", "否", "不再提示")
                .then(result=> {
                    if (result === "是") {
                        // 在浏览器中打开来访问代理服务器,后面带上端口信息,以便代理服务器知道访问容器的哪个端口
                        vscode.env.openExternal(vscode.Uri.parse(`http://192.168.44.100/proxy/` + p))
                    } 
                })
            }
            tmpSet.add(p)
        })
        s = tmpSet
    })
}

function getListeningPorts(callback) {
    var exec = require('child_process').exec;
    
    exec('netstat -nlt', function(error, stdout, stderr){
        if(error) {
            console.error('error: ' + error);
            return;
        }
        
        var ports = parsePort(stdout)
        callback(ports)
    })
}

function parsePort(msg) {
    var idx = msg.indexOf("tcp")
    msg = msg.slice(idx, msg.length)
    var colums = msg.split("\n")
    var ret = new Array()
    colums = colums.slice(0, colums.length - 1)
    colums.forEach(element => {
        
        var port = findPort(element)
        if (port != -1) {
            ret.push(port)
        }
    });

    return ret;
}

function findPort(colum) {
    var idx = colum.indexOf(':')
    var first = colum.slice(0, idx)
    while (colum[idx] == ':') {
        idx++
    }
    var second = colum.slice(idx, colum.length)
    var fidx = first.lastIndexOf(' ')
    var sidx = second.indexOf(' ')
    var ip = first.slice(fidx + 1, first.length)
    var port = second.slice(0, sidx)

    if (ip == "127.0.0.1") {
        return -1
    } else {
        return Number(port)
    }
}

// this method is called when your extension is deactivated
function deactivate() {}

module.exports = {
	activate,
	deactivate
}
  1. 然后构建项目,首先安装vsce库,再打包
npm i -g vsce

vsce package
  1. 打包后生成了vsix文件,将vsix文件上传到服务器,然后再拷贝到docker容器中
# docker拷贝命令
docker cp 主机文件名 容器ID或容器名:/容器内路径
  1. 然后在浏览器中的vscode中选择vsix文件来安装插件

在这里插入图片描述

安装完之后,我们的插件在vscode打开后就会启动,然后每隔一秒查询一个端口情况。

测试

接下来,测试一下插件:

在vscode中写了一个http服务器,然后启动这个服务器,看插件是否能发现这个端口被监听了

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

type KK struct {
	Name          string `json:"name"`
	Prictice_time string `json:"prictice time"`
	Hobby         string `json:"hobby"`
}

func main() {
	engine := gin.Default()
	engine.GET("/", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, &KK{
			Name:          "kunkun",
			Prictice_time: "two and a half years",
			Hobby:         "sing jump and rap",
		})
	})

	engine.Run(":8080")
}

运行http服务器:

go run main.go

可以看到,它弹出了提示,提示我们是否在浏览器中打开

在这里插入图片描述

但是现在在浏览器中打开是访问不了容器中的http服务器的,因为端口没有被映射到主机端口上。

 

2.3 代理服务器实现

在此,为了验证我的想法是否能成功,只是实现了一个简单的代理服务器,它将请求转发的容器中,然后再转发容器中服务器的响应。(因为代理服务器是直接运行在主机上的,因此可以通过容器IP+端口来访问)

代码如下:

package main

import (
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
)

func main() {
	engine := gin.Default()
	engine.GET("/proxy/*all", func(ctx *gin.Context) {
		all := ctx.Param("all")                    // 获取/proxy后面的参数 
		if len(all) <= 0 {
			ctx.Status(http.StatusBadRequest)
			return
		}
		all = all[1:]                             // 丢弃第一个'/'
		idx := strings.Index(all, "/")
		var url string
		if idx < 0 {                              // 只有端口
			url = fmt.Sprintf("http://172.17.0.3:%s", all)
		} else {                                 // 有端口和其它访问路径
			port := all[:idx]
			url = fmt.Sprintf("http://172.17.0.3:%s%s", port, all[idx:])
		}
		resp, err := http.Get(url)               // 访问容器中的服务器
		if err != nil {
			ctx.Status(http.StatusBadRequest)
			return
		}
		io.Copy(ctx.Writer, resp.Body)            // 转发响应
	})

	engine.Run(":80")
}

在主机服务器上运行代理服务器,不要使用容器来启动:

go build 
nohup ./porxy_server &           # 后台运行

然后我们再启动浏览器vscode中的服务器看是否可以访问到:

在这里插入图片描述

选择"是",然后在新弹出的窗口中就可以访问到容器中的服务了:

在这里插入图片描述
 

2.4 nginx实现代理服务器

        nginx的性能非常好,而且功能特别强大。因此如果使用nginx来做为反向代理服务器,那么性能会提升一大截。但是我们平常在配置nginx反向代理的时候使用的都是静态的反向代理,也就是代理服务器在配置文件中写死了。但是在这里我们需要根据uri中的参数来动态选择要反向代理的服务器。

        在这里可以选择使用openresty,openresty是国人的一个项目,可以使用lua语言来为nginx实现可伸缩的web平台,我们可以使用lua语言来根据uri中的参数来动态选择要反向代理的服务器。

2.4.1 下载Openresty

  1. Openresty下载:

使用wget命令下载

wget https://openresty.org/download/openresty-1.21.4.1.tar.gz
  1. 解压
tar zxvf openresty-1.21.4.1.tar.gz
  1. 在编译前需要安装依赖
# debain和ubuntu用户:
apt-get install libpcre3-dev \
    libssl-dev perl make build-essential curl
 
# fedora和redhat用户
yum install pcre-devel openssl-devel gcc curl
  1. 编译安装
cd openresty-1.21.4.1
./configure
make & make install

默认会安装到/usr/local/openresty目录中,进入openresty/目录,有个nginx文件夹,正是nginx的可执行文件和配置文件等。

进入nginx/sbin运行nginx

可以将nginx加入环境变量:

vim /etc/profile

# 在最下面添加
export PATH=$PATH:/usr/local/openresty/nginx/sbin

# 执行下面命令使其生效
source /etc/profile

2.4.2 配置动态反向代理

安装完成后,就可以配置动态反向代理了,修改配置文件添加配置:

# 代码的步骤如下:
# 1.获取请求路径中的uri
# 2.将uri中的端口和其余路径拼凑到新的url中
# 3.设置反向代理
location /proxy {
    set $backend '';
    rewrite_by_lua_block {
        local req_uri = ngx.var.request_uri;
        local _, en = string.find(req_uri, "/proxy/");
        local nuri = string.sub(req_uri, en + 1);
        ngx.var.backend = "172.17.0.3:"..nuri.."/";
    }
    proxy_pass http://$backend;
    proxy_redirect     off;
    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
}

然后得到的效果就跟上面自己写的代理服务器一样了。
 
这里实现的只是一个非常简易的版本,只是提供了一个这样的思路。如何要实现一个类似Cloud Studio的云IDE要考虑的还要更多。
最终效果如下:

在这里插入图片描述

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

云vscode搭建--使用容器化部署 的相关文章

  • 使用 sed 将 old-link-url 替换为 new-link-url

    我正在 bash 中编写一个脚本 将 old link url 替换为 new link url 我的问题是 sed 由于斜杠而无法替换 url 如果我只输入一些文字就可以了 my code sed e s old link new lin
  • 原生 Linux 应用程序可像 ResHacker 一样编辑 Win32 PE

    我想运行自动修改 dll服务 用户提交特定的 dll 我在服务器上修改它 然后用户可以下载 dll的修改版本 是否有任何本机 Linux 应用程序提供常见的 Win32 PE 修改功能 例如图标 字符串 加速器 对话等 至少提供命令行或脚本
  • Docker DNS 设置

    我尝试使用自定义网络和 dos 设置创建 docker 容器 docker网络创建 driver bridge opt com docker network bridge enable ip masquerade true opt com
  • 静态链接共享对象?或者损坏的文件?

    我有一个从专有来源获得的库 我正在尝试链接它 但出现以下错误 libxxx so 文件无法识别 文件格式无法识别 Collect2 ld 返回 1 退出状态 确实 ldd libxxx so statically linked 这究竟意味着
  • 如何阅读shell命令的源代码?

    我想阅读编写linux命令的实际源代码 我已经获得了一些使用它们的经验 现在我认为是时候与我的机器进行更深层次的交互了 我在这里找到了一些命令http directory fsf org wiki GNU http directory fs
  • UDP 广播发送失败:在 Linux 2.6.30 上“网络无法访问”

    我用udp广播写了一个程序 代码段如下 struct sockaddr in broadcast addr socklen t sock len sizeof broadcast addr bzero broadcast addr sock
  • 设置 Emacs 进行 Erlang 编程

    Emacs 是 Erlang 编程的首选 IDE 有很多好的模式 distel erlware mode 默认的 erlang 模式 但是您对设置 Emacs 进行专业 Erlang 开发有何建议 按照中所述设置 erlang mode自述
  • Bash 脚本 - 迭代 find 的输出

    我有一个 bash 脚本 其中需要迭代 find 命令输出的每一行 但似乎我正在迭代 find 命令中的每个单词 以空格分隔 到目前为止我的脚本看起来像这样 folders find maxdepth 1 type d for i in f
  • Emacs:在缓冲区求值期间将参数传递给下级 Python shell

    最近我开始使用 Emacs 作为 Python IDE 它不太直观 我现在遇到的问题是当使用 C c C c 评估缓冲区时如何将命令行参数传递给下级 python shell 感谢帮助 这似乎并不容易实现 管理的劣质流程python el模
  • 如何从类似于 eclipse 的命令行创建可运行的 jar 文件

    我知道 eclipse 会生成一个可运行的 jar 文件 其中提取并包含在该 jar 文件中的所有库 jar 文件 从命令提示符手动创建 jar 文件时如何执行类似的操作 我需要将所有 lib jar 解压到类文件夹中吗 目前我正在使用 j
  • CentOS目录结构是树形的吗?

    CentOS 上有相当于树的东西吗 如果你的 Centos 系统上没有安装 tree 无论如何我通常建议服务器设置使用最小安装磁盘 你应该在命令行中输入以下内容 yum install tree y 如果没有安装 那是因为您没有正确的存储库
  • Linux 上的 Python 3.6 tkinter 窗口图标错误

    我正在从 Python GUI 编程手册 学习 Python GUI 某项任务要求我通过将以下代码添加到我的配方中来更改窗口图标 Change the main windows icon win iconbitmap r C Python3
  • 如何查明 Ubuntu 上安装了哪个版本的 GTK+?

    我需要确定 Ubuntu 上安装了哪个版本的 GTK 男人似乎不帮忙 这个建议 https stackoverflow com a 126145 会告诉您安装了哪个 2 0 的次要版本 不同的主要版本将具有不同的包名称 因为它们可以在系统上
  • 防止 Visual Studio Code 或 IDE 泄露 Python 类私有方法

    只是想问一个简单的问题 本质上 我想知道是否可以从 Visual Studio Code 或其他 IDE 提供的建议列表中隐藏 Python 类私有方法 例如 假设我们有一个类 A Creating a class class A Decl
  • 如何获取 linux 实用程序 tail 的源代码?

    这个命令确实非常有用 但是我可以在哪里获取源代码以查看内部发生的情况 thanks tail 实用程序是 Linux 上 coreutils 的一部分 源压缩包 ftp ftp gnu org gnu coreutils coreutils
  • 如何让 clangd 转向 c++20

    当没有其他信息时 如何让 clangd 回退到 c 20 例如 在第一次构建之前 cmake 可以生成一个 这是在带有最新 LLVM 的 Arch Linux 上 这是通过 Emacs LSP 运行的 但这应该没有什么区别 你可以加 Com
  • 构建 makefile 依赖/继承树

    如果我解释得不好或者问了一些明显的问题 我很抱歉 但我是 Linux 内核的新手 而且有点深入 我们有一个嵌入式 Linux 系统 它附带一个 文档非常糟糕的 SDK 其中包含数百个文件夹stuff 大多数文件夹包含rules make m
  • gentoo crontab:为什么这个简单的 crontab 不起作用?

    我使用 GENTOO 发行版 crontab e 35 12 root php5 home www cron php 当我手动运行时 php5 php5 home www cron php 这有效 它向我发送了一封电子邮件 然后我检查日期
  • git在Windows和Linux之间切换后强制刷新索引

    我有一个Windows和Linux共享的磁盘分区 格式 NTFS 它包含一个 git 存储库 约 6 7 GB 如果我只使用Windows or 只使用Linux操作 git 存储库一切正常 但是每次切换系统的时候git status命令将
  • 无法执行'x86_64-conda_cos6-linux-gnu-gcc':没有这样的文件或目录(pysam安装)

    我正在尝试安装 pysam 执行后 python path to pysam master setup py build 这个错误的产生是 unable to execute x86 64 conda cos6 linux gnu gcc

随机推荐

  • 集训第一周 Linux

    1 创建一个用户user1 用root身份给user1修改密码为redhat 提示 创建用户用useradd user1 2 切换到user1用户 给自己修改一个密码 密码任意 3 在 root 目录中创建一个以自己的汉语拼音为名字的文件
  • QML学习一:QtCreator编译器主题背景设置

    效果如下 QML学习一 QtCreator编译器主题背景设置 前言 一 工具栏菜单栏背景设置 二 文本编辑区域设置 总结 前言 工欲善其事必先利其器 为了更好地开发代码 我们先将QtCreator界面改为模仿Vs2019主题样式 这样开发起
  • Unity3d中所有特殊的文件夹

    1 Editor Editor文件夹可以在根目录下 也可以在子目录里 只要名子叫Editor就可以 比如目录 xxx xxx Editor 和 Editor 是一样的 无论多少个叫Editor的文件夹都可以 Editor下面放的所有资源文件
  • svn清理本地已经删除的文件,注意事项

    点击项目目录下空白处点击trotoiseSVN后点击检查修改 在里面删除你想要删除的已删除文件即可 分支操作注意事项 在切换分支前记得提交本地代码的修改 否则会合并到切换后的分支去 切记 哎
  • Java使用MongoTemplate实现多条件、模糊查询、排序、范围、分页查询

    场景 查询客户列表 不同条件之间取交集 且的关系 单个条件内取并集 或的关系 实现细节如下 1 全等于 手机号全字匹配 2 模糊查询 客户名称模糊搜索 3 单个条件查询多个字段 客户编号 4 日期范围 近期消费时间 5 数值范围 消费总金额
  • Ubuntu使用haar+adaboost训练进行手势识别

    手势识别开源代码千千万 为啥我要用此方法 原因有三 首先 我们项目要求这个手势识别是不分环境的 也就是半夜三更黑灯瞎火也能用 这一下子就把纯RGB的方式给去除了 而且也要考虑用户戴手套 手套颜色不限制 使用 那么肤色过滤什么的咱们再见 其次
  • 毕业设计 2023-2024年最新python毕设选题题目推荐汇总

    文章目录 0 前言 1 python 算法类 毕设选题 2 python 数据挖掘 毕设选题 3 python 大数据处理 云计算 区块链 毕设选题 4 python 网络安全 毕设选题 5 python 游戏设计 动画设计类 毕设选题 适
  • Java实现Kruskal算法

    一 kruskal算法简介 克鲁斯卡尔算法是求连通网的最小生成树的另一种方法 与prim算法不同 它的时间复杂度为O eloge e为网中的边数 所以 适合于求边稀疏的网的最小生成树 二 实现步骤 部分流程图 废话不多说 直接上代码 这张图
  • python绘制余弦曲线图_Python可视化中的Matplotlib绘图(1.画图,网格,子图,画正余弦图,坐标轴界限,画圆,)...

    1 一张基本的图标包含的元素 x轴和y轴 以及他们的刻度线 标签 绘图区域 import matplotlib pyplot as plt 导入绘图模块 import numpy as np 导入需要生成数据的numpy模块 只有一个曲线图
  • 计算机网络常见面试题总结(二)

    本文主要内容转载自 http blog csdn net u013408431 article details 62442670 locationNum 10 fps 1 面试中网络方面的知识被问到的概率很大 尤其是互联网公司 要熟悉osi
  • 垃圾短信识别python步骤详细_python数据挖掘第三篇-垃圾短信文本分类

    文本分类总体上包括8个步骤 数据探索分析 数据抽取 文本预处理 分词 去除停用词 文本向量化表示 分类器 模型评估 重要python库包括numpy 数组 pandas 用于处理结构化数据 matplotlib 绘制词云 便于直观表示 sk
  • java压缩包打不开_java.util.zip.ZipException: error in opening zip file 问题处理

    java util zip ZipException error in opening zip file 这个问题的字面意思是压缩包打不开 我这出现的问题是jar包损坏 打不开 linux系统可以使用命令判断jar 是否正常 jar vtf
  • Axure RP 万能的标签切换面板-动态面板切换

    切换面板在网页中算是非常常见的 如视频网站的电视剧分类标签 资讯网站的资讯分类等 这些交互效果都可以利用动态面板的几个状态来进行相互切换得来 下面来介绍一下如何制作这样的标签 步骤1 从部件库中拖拽一个动态面板到线框图编辑区中 并在 部件交
  • STM32Cube HAL库——ADC电压采集

    STM32Cube HAL库 ADC电压采集 一 ADC基本介绍 模拟数字转换器 即A D转换器 或简称ADC Analog to Digital Converter 通常是指一个将模拟信号转变为数字信号的电子元件 通常的模数转换器是将一个
  • 斗地主游戏

    牌属性类 package Java project 1 import java util Objects public class Card private String size 点数 private String color 花色 pr
  • UE4:自定义Slate 点击保存 出现USlot ReleaseSlateResources() 异常

    Error AssetLog Test uasset Leak Detected CustomWidget 43 CustomWidget still has living Slate widgets it or the parent Ca
  • pyQt5 学习笔记(19)QFrame 边框设置

    文章目录 一 QFrame 简介 二 QFrame 的创建 三 组合效果图 四 QFrame 的功能 API 1 功能 2 QFrame 结构 3 使用总结 1 挑选目标样式 2 根据参数写程序 五 信号 一 QFrame 简介 QFram
  • mysql 数组_MySQL如何实现数组功能

    前段时间想要用数组功能实现某些需求 结果发现mysql不支持数组 这个确实让人很头痛 查阅官方文档 也没有这一方面的资料 结果在网上 看到了某仁兄贴出了变相实现的一种方法 代码如下 DELIMITER DROP DATABASE IF EX
  • 【Ubuntu】使用grub2挂载NFS根文件系统(rootfs)

    经常调试arm开发板的同学应该比较熟悉uboot 它可以使用tftp自动下载内核并通过nfs挂载rootfs 其实 作为x86平台常见的bootloader grub也可以做到通过nfs挂载rootfs 安装grub2 目前新版的ubunt
  • 云vscode搭建--使用容器化部署

    Vscode作为一个轻量级的IDE 其支持丰富的插件 而通过这些插件我们就可以实现在Vscode中写任何语言的代码 Code Server是Vscode的网页版 启动Code Server之后我们就可以在浏览器中打开vscode来愉快的编写