-
看代码吧~123456789//利用正则表达式压缩字符串,去除空格或制表符func compressStr(str string) string { if str == "" { return "" } //匹配一个或多个空白符的正则表达式 reg := regexp.MustCompile("\\s+") return reg.ReplaceAllString(str, "")}补充:go语言去除字符串尾部所有空格刷 leetcode 的一个算法题。要求只删除字符串尾部的所有字符串. google 只搜出通过 strings.Trim() 方法删除前后空格或者删除字符串前边和后边的固定子字符串。方法从字符串后端开始计算空格数量,然后用切片切掉:1234567891011func deleteTailBlank(str string) string { spaceNum := 0 for i := len(str)-1; i >= 0; i-- { // 去除字符串尾部的所有空格 if str[i] == ' ' { spaceNum++ } else { break } } return str[:len(str)-spaceNum]}补充:go:字符串去除空格和换行符 strings.Replace看代码吧~12345678910111213141516package main import ( "fmt" "strings") func main() { str := "这里是 www\n.runoob\n.com" fmt.Println("-------- 原字符串 ----------") fmt.Println(str) // 去除空格 str = strings.Replace(str, " ", "", -1) // 去除换行符 str = strings.Replace(str, "\n", "", -1) fmt.Println("-------- 去除空格与换行后 ----------") fmt.Println(str)}
-
## go-fastdfs编译指导 ##### 主机描述:go-fastdfs为fastdfs的go语言实现版本。 ##### 测试环境:go语言为跨平台语言,对系统不敏感。当前测试环境为UOS V20 SP1。 1. ### 安装go ```shell #下载解压 wget https://dl.google.com/go/go1.10.linux-arm64.tar.gz tar zxvf go1.10.linux-arm64.tar.gz -C /usr/local #配置环境变量 echo "export GOROOT=/usr/local/go" >> /etc/profile echo "export PATH=\$GOROOT/bin:\$PATH" >> /etc/profile source /etc/profile ```  2. ### 下载源码并编译go-fastdfs 环境: ```bash #1.创建工作目录 mkdir /root/gopath cd /root/gopath #2.下载代码 git clone https://github.com/sjqzhang/go-fastdfs.git #或者拉取gitee的源码 #git clone https://gitee.com/sjqzhang/go-fastdfs #对版本有需求的可以checkout对应的版本分支 #3.配置临时GOPATH cd go-fastdfs/ pwd=`pwd` export GOPATH=$pwd #4.修改依赖路径 mv vendor src ```  编译和测试: ```bash #编译 go build -o fileserver fileserver.go #增加权限 chmod +x fileserver #执行 ./fileserver ```   3. ### FAQ 1. cannot find package "github.com/astaxie/beego/httplib"  - **问题描述**:编译过程中,找不到相关依赖。 - **问题分析**:GOPATH配置不正确,或者依赖文件位置不正确。 - **解决方式**: 1.配置正确的GOPATH 2.修改依赖文件夹名称和路径(mv vendor src) 2. ./fileserver.go:2388: header.Size undefined  - **问题描述**:找不到header.Size - **问题分析**:Go版本过低  - **解决方式**:升级至1.10版本以上。当前测试环境为1.10版本。
-
本文是Go比较有名的一个坑,在以前面试的时候也被问过,为什么想起来写这个?因为我们线上就真实出现过这个坑,写给不了解的人在使用 if err != nil 的时候提高警惕。Go语言的interface{}在使用过程中有一个特别坑的特性,当你比较一个interface{}类型的值是否是nil的时候,这是需要特别注意避免的问题。先来看看一个demo:123456789101112131415package mainimport "fmt"type ErrorImpl struct{}func (e *ErrorImpl) Error() string { return ""}var ei *ErrorImplvar e errorfunc ErrorImplFun() error { return ei}func main() { f := ErrorImplFun() fmt.Println(f == nil)}输出:false为什么不是true?想要理解这个问题,首先需要理解interface{}变量的本质。在Go语言中,一个interface{}类型的变量包含了2个指针,一个指针指向值的在编译时确定的类型,另外一个指针指向实际的值。123456789101112131415161718192021222324// InterfaceStructure 定义了一个interface{}的内部结构type InterfaceStructure struct { pt uintptr // 到值类型的指针 pv uintptr // 到值内容的指针}// asInterfaceStructure 将一个interface{}转换为InterfaceStructurefunc asInterfaceStructure(i interface{}) InterfaceStructure { return *(*InterfaceStructure)(unsafe.Pointer(&i))}func main() { var i1, i2 interface{} var v1 int = 23 var v2 int = 23 i1 = v1 i2 = v2 fmt.Printf("sizeof interface{} = %d\n", unsafe.Sizeof(i1)) fmt.Printf("i1 %v %+v\n", i1, asInterfaceStructure(i1)) fmt.Printf("i2 %v %+v\n", i2, asInterfaceStructure(i2)) var nilInterface interface{} var str *string fmt.Printf("nil interface = %+v\n", asInterfaceStructure(nilInterface)) fmt.Printf("nil string = %+v\n", asInterfaceStructure(str)) fmt.Printf("nil = %+v\n", asInterfaceStructure(nil))}输出:sizeof interface{} = 16i1 23 {pt:4812032 pv:825741246928}i2 23 {pt:4812032 pv:825741246936}nil interface = {pt:0 pv:0}nil string = {pt:4802400 pv:0}nil = {pt:0 pv:0}当我们将一个具体类型的值赋值给一个interface{}类型的变量的时候,就同时把类型和值都赋值给了interface{}里的两个指针。如果这个具体类型的值是nil的话,interface{}变量依然会存储对应的类型指针和值指针。如何解决?方法一返回的结果进行非nil检查,然后再赋值给interface{}变量12345678910111213141516type ErrorImpl struct{}func (e *ErrorImpl) Error() string { return ""}var ei *ErrorImplvar e errorfunc ErrorImplFun() error { if ei == nil { return nil } return ei}func main() { f := ErrorImplFun() fmt.Println(f == nil)}输出:true方法二返回具体实现的类型而不是interface{}123456789101112131415package mainimport "fmt"type ErrorImpl struct{}func (e *ErrorImpl) Error() string { return ""}var ei *ErrorImplvar e errorfunc ErrorImplFun() *ErrorImpl { return ei}func main() { f := ErrorImplFun() fmt.Println(f == nil)}输出:true解决由于第三方包带来的坑由于有的error是第三方包返回的,又自己不想改第三方包,只好接收处理的时候想办法。方法一利用interface{}原理1234is:=*(*InterfaceStructure)(unsafe.Pointer(&i))if is.pt==0 && is.pv==0 { //is nil do something}将底层指向值和指向值的类型的指针打印出来如果都是0,表示是nil方法二利用断言,断言出来具体类型再判断非空123456789101112131415161718type ErrorImpl struct{}func (e ErrorImpl) Error() string { return "demo"}var ei *ErrorImplvar e errorfunc ErrorImplFun() error { //ei = &ErrorImpl{} return ei}func main() { f := ErrorImplFun() //当然error实现类型较多的话使用 //switch case方式断言更清晰 res, ok := f.(*ErrorImpl) fmt.Printf("ok:%v,f:%v,res:%v", ok, f == nil, res == nil)}输出:ok:true,f:false,res:true方法三利用反射123456789101112131415type ErrorImpl struct{}func (e ErrorImpl) Error() string { return "demo"}var ei *ErrorImplvar e errorfunc ErrorImplFun() error { //ei = &ErrorImpl{} return ei}func main() { f := ErrorImplFun() rv := reflect.ValueOf(f) fmt.Printf("%v", rv.IsNil())}输出:true注意⚠:断言和反射性能不是特别好,如果不得已再使用,控制使用有助于提升程序性能。由于函数接收类型导致的panic:12345678910111213type ErrorImpl struct{}func (e ErrorImpl) Error() string { return "demo"}var ei *ErrorImplvar e errorfunc ErrorImplFun() error { return ei}func main() { f := ErrorImplFun() fmt.Printf(f.Error())}输出:panic: value method main.ErrorImpl.Error called using nil *ErrorImpl pointer解决:123func (e *ErrorImpl) Error() string { return "demo"}输出:demo可以发现将接收类型变成指针类型就可以了。以上就是 nil 相关的坑,希望大家可以牢记,如果 ”幸运“ 的遇到了,可以想到这些可能性。补充:go 语言 interface{} 的易错点如果说 goroutine 和 channel 是 go 语言并发的两大基石,那 interface 就是 go 语言类型抽象的关键。在实际项目中,几乎所有的数据结构最底层都是接口类型。说起 C++ 语言,我们立即能想到是三个名词:封装、继承、多态。go 语言虽然没有严格意义上的对象,但通过 interface,可以说是实现了多态性。(由以组合结构体实现了封装、继承的特性)123456789101112131415161718192021package maintype animal interface { Move()}type bird struct{}func (self *bird) Move() { println("bird move")}type beast struct{}func (self *beast) Move() { println("beast move")}func animalMove(v animal) { v.Move()}func main() { var a *bird var b *beast animalMove(a) // bird move animalMove(b) // beast move}go 语言中支持将 method、struct、struct 中成员定义为 interface 类型,使用 struct 举一个简单的栗子使用 go 语言的 interface 特性,就能实现多态性,进行泛型编程。二,interface 原理如果没有充分了解 interface 的本质,就直接使用,那最终肯定会踩到很深的坑,要用就先要了解,先来看看 interface 源码1234567891011121314151617type eface struct { _type *_type data unsafe.Pointer} type _type struct { size uintptr // type size ptrdata uintptr // size of memory prefix holding all pointers hash uint32 // hash of type; avoids computation in hash tables tflag tflag // extra type information flags align uint8 // alignment of variable with this type fieldalign uint8 // alignment of struct field with this type kind uint8 // enumeration for C alg *typeAlg // algorithm table gcdata *byte // garbage collection data str nameOff // string form ptrToThis typeOff // type for pointer to this type, may be zero}可以看到 interface 变量之所以可以接收任何类型变量,是因为其本质是一个对象,并记录其类型和数据块的指针。(其实 interface 的源码还包含函数结构和内存分布,由于不是本文重点,有兴趣的同学可以自行了解)三,interface 判空的坑对于一个空对象,我们往往通过 if v == nil 的条件语句判断其是否为空,但在代码中充斥着 interface 类型的情况下,很多时候判空都并不是我们想要的结果(其实了解或聪明的同学从上述 interface 的本质是对象已经知道我想要说的是什么)123456789101112131415161718192021222324package main type animal interface { Move() } type bird struct{} func (self *bird) Move() { println("bird move") } type beast struct{} func (self *beast) Move() { println("beast move") } func animalMove(v animal) { if v == nil { println("nil animal") } v.Move() } func main() { var a *bird // nil var b *beast // nil animalMove(a) // bird move animalMove(b) // beast move }还是刚才的栗子,其实在 go 语言中 var a *bird 这种写法,a 只是声明了其类型,但并没有申请一块空间,所以这时候 a 本质还是指向空指针,但我们在 aminalMove 函数进行判空是失败的,并且下面的 v.Move() 的调用也是成功的,本质的原因就是因为 interface 是一个对象,在进行函数调用的时候,就会将 bird 类型的空指针进行隐式转换,转换成实例的 interface animal 对象,所以这时候 v 其实并不是空,而是其 data 变量指向了空。这时候看着执行都正常,那什么情况下坑才会绊倒我们呢?只需要加一段代码12345678910111213141516171819202122232425262728package main type animal interface { Move() } type bird struct { name string } func (self *bird) Move() { println("bird move %s", self.name) // panic } type beast struct { name string } func (self *beast) Move() { println("beast move %s", self.name) // panic } func animalMove(v animal) { if v == nil { println("nil animal") } v.Move() } func main() { var a *bird // nil var b *beast // nil animalMove(a) // panic animalMove(b) // panic }在代码中,我们给派生类添加 name 变量,并在函数的实现中进行调用,就会发生 panic,这时候的 self 其实是 nil 指针。所以这里坑就出来了。有些人觉得这类错误谨慎一些还是可以避免的,那是因为我们是正向思维去代入接口,但如果反向编程就容易造成很难发现的 bug123456789101112131415161718192021222324252627282930313233343536package main type animal interface { Move() } type bird struct { name string } func (self *bird) Move() { println("bird move %s", self.name) } type beast struct { name string } func (self *beast) Move() { println("beast move %s", self.name) } func animalMove(v animal) { if v == nil { println("nil animal") } v.Move() } func getBirdAnimal(name string) *bird { if name != "" { return &bird{name: name} } return nil } func main() { var a animal var b animal a = getBirdAnimal("big bird") b = getBirdAnimal("") // return interface{data:nil} animalMove(a) // bird move big bird animalMove(b) // panic }这里我们看到通过函数返回实例类型指针,当返回 nil 时,因为接收的变量为接口类型,所以进行了隐性转换再次导致了 panic(这类反向转换很难发现)。那我们如何处理上述这类问题呢。我这边整理了三个点1,充分了解 interface 原理,使用过程中需要谨慎小心2,谨慎使用泛型编程,接收变量使用接口类型,也需要保证接口返回为接口类型,而不应该是实例类型3,判空是使用反射 typeOf 和 valueOf 转换成实例对象后再进行判空
-
-
敬请期待
-
尝试了好久的helloworld,都卡在pull image环节,修改了resolve dns也没有成功,排除网络问题,应该还是配置有问题。现成的测试项目暂时用不了,那就自己写一个吧:在Go中编写了一个简单的服务器,用“Hello World”响应http请求。[root@ecs-b769 ~]# vi main.go package main import ( "fmt" "log" "net/http" "os" ) func GetEnvDefault(key, defVal string) string { val, ex := os.LookupEnv(key) if !ex { return defVal } return val } func handler(w http.ResponseWriter, r *http.Request) { log.Print("Hello world received a request.") version := GetEnvDefault("VERSION", "v1") log.Println(version) fmt.Fprintf(w, "Hello world %s\n",version) } func main() { log.Print("Hello world sample started.") http.HandleFunc("/hello", handler) port := GetEnvDefault("PORT", "80") log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil)) }从基础Go镜像开始构建Dockerfile。[root@ecs-385f ~]# vi Dockerfile #use the official Golang image to create a build artifact. # https://hub.docker.com/_/golang FROM golang:1.12.5 as builder # Copy local code to the container image. WORKDIR /go/src/app COPY . . RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o start main.go # Use a Docker multi-stage build to create a lean production image. # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds FROM alpine:3.9.4 COPY --from=builder /go/src/app/start /start RUN chmod 775 /start # Run the web service on container startup. CMD ["/start"] # Use the official Golang image to create a build artifact. # https://hub.docker.com/_/golang FROM golang:1.12.5 as builder # Copy local code to the container image. WORKDIR /go/src/app COPY . . RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o start main.go # Use a Docker multi-stage build to create a lean production image. # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds FROM alpine:3.9.4 COPY --from=builder /go/src/app/start /start RUN chmod 775 /start # Run the web service on container startup. CMD ["/start"][root@ecs-385f ~]# docker build -t hello:v1 . Sending build context to Docker daemon 17.92kB Step 1/8 : FROM golang:1.12.5 as builder ---> 1ef078f0da9e Step 2/8 : WORKDIR /go/src/app ---> Using cache ---> f95f8c547d5f Step 3/8 : COPY . . ---> b1a8ce01e3de Step 4/8 : RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o start main.go ---> Running in cee9bd3b172f Removing intermediate container cee9bd3b172f ---> 6a99fdb6ace9 Step 5/8 : FROM alpine:3.9.4 3.9.4: Pulling from library/alpine e7c96db7181b: Pull complete Digest: sha256:7746df395af22f04212cd25a92c1d6dbc5a06a0ca9579a229ef43008d4d1302a Status: Downloaded newer image for alpine:3.9.4 ---> 055936d39205 Step 6/8 : COPY --from=builder /go/src/app/start /start ---> 70fb9cff5e68 Step 7/8 : RUN chmod 775 /start ---> Running in 35630a07c2d1 Removing intermediate container 35630a07c2d1 ---> 6706473c77bb Step 8/8 : CMD ["/start"] ---> Running in 88a57f47e74a Removing intermediate container 88a57f47e74a ---> 145828adcb9b Successfully built 145828adcb9b Successfully tagged hello:v1 [root@ecs-385f ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello v1 145828adcb9b 30 seconds ago 20.2MByaml文件,其实就是需求文本,如果有人能跑通就没有问题,有问题就是环境兼容的问题。[root@ecs-385f ~]# vi hello-kubernetes.yaml labels: app: hello-kubernetes spec: containers: - name: helloworld-kubernetes image: hello:v1 imagePullPolicy: Never ports: - containerPort: 80 # hello-kubernetes.yaml apiVersion: v1 kind: Service metadata: name: hello-kubernetes spec: type: ClusterIP ports: - port: 80 targetPort: 80 selector: app: hello-kubernetes --- apiVersion: apps/v1 kind: Deployment metadata: name: hello-kubernetes spec: replicas: 1 selector: matchLabels: app: hello-kubernetes template: metadata: labels: app: hello-kubernetes spec: containers: - name: helloworld-kubernetes image: hello:v1 imagePullPolicy: Never ports: - containerPort: 80[root@ecs-b769 ~]# kubectl apply -f hello-kubernetes.yaml service/hello-kubernetes unchanged deployment.apps/hello-kubernetes unchanged [root@ecs-b769 ~]# kubectl get po NAME READY STATUS RESTARTS AGE hello-kubernetes-6c67c8c8dd-tz5kd 1/1 Running 0 33m myapp-9896ff477-949kx 0/1 ImagePullBackOff 0 44m [root@ecs-b769 ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hello-kubernetes ClusterIP 10.96.232.94 <none> 80/TCP 34m kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 37h my-service LoadBalancer 10.96.145.90 <pending> 8080:32471/TCP 51m nginx-service NodePort 10.96.226.104 <none> 80:31050/TCP 23h [root@ecs-b769 ~]# kubectl exec -it hello-kubernetes sh Error from server (NotFound): pods "hello-kubernetes" not found [root@ecs-b769 ~]# kubectl exec -it hello-kubernetes-6c67c8c8dd-tz5kd sh / # ls bin dev etc home lib media mnt opt proc root run sbin srv start sys tmp usr var / # exit [root@ecs-b769 ~]# curl hello-kubernetes/hello curl: (6) Could not resolve host: hello-kubernetes; Unknown error [root@ecs-b769 ~]# curl 10.96.232.94/hello Hello world v1
-
【我要去HDC2021③】每天锻炼30分钟,go,go
-
学会GO语言
-
2021-03-12:go中,如何确定有没有内存泄露,系统里怎么去监控整体的运行情况,日志是怎么处理的?
-
2021-03-11:go中,协程内部再启用协程,它们是没关系,对吧?外部协程奔溃,内部协程还会执行吗?外部协程执行结束的时候,如何让内部协程也停止运行?golang原生提供的包里,让内部协程停止运行,如何实现?
-
近几年,关于 Go 与 Java 还有 c 的对比和讨论愈演愈烈,但不可否认的是,在十年多的时间里,Go 语言发展势头强劲,凭借其简洁、高效的特性,在竞争激烈的编程语言市场中占据了一席之地。字节跳动已经全部转 Go 语言,腾讯、阿里等大公司纷纷选择使用 Go 语言来开发服务应用项目。在 TIOBE 近一两年的榜单中,Go 语言在前 20 位中,总体呈现稳中有升的趋势,2020年 3 月又一次冲进前十。而在国内,没有哪个大厂不做 Kubernetes,微服务和 Serverless,这些正是云原生语言 Go 的主场。目前大热的区块链,以太坊的 geth,比特币的 btcd,闪电网络的 lnd,都是 Go 语言开发。不仅如此,区块链更被列为国家战略,这也很大程度加速了Go语言的崛起,2018年5月20日工业和信息化部信息中心发布《2018中国区块链产业白皮书》,Go语言与区块链成为“数字中国”建设的重要支撑。有亲爹谷歌的扶持,有大厂背书,社区和生态持续良好发展,Go 语言的前途一片光明。因此,我们认为 Go 语言有希望越过早期采用者阶段,进入早期大众阶段。如果你是一名 PHP,或者 NET 工程师,那我建议你从今天开始,果断利用业务时间学习下 Go 语言,跟上时代的潮流走,把握住这波语言红利。如果你是一名相对成熟的 Java 工程师,我同样也建议你考虑下 Go 语言。因为在一个人都可以的情况,你可以在多种语言里都可以,做得很好,这个毫无疑问。但是如果说来了一波趋势,你能抓住的话,等于对你来说是一个加速剂。目前Go 语言就处于这样一个不错的时代中。其实,现在很多人已经开始如火如荼的学习 Go 语言了,可能在你刚刚换到这门语言的时候,你会发现之前你之前代码的那些问题全都没有了,感觉前途一片美好。遗憾的是,可能这是因为你仅仅才开始写了几个模块,还没有进入维护期。事实是如果你没有深入的去钻研软件工程的规律和技术,没有深入的了解 Go 语言的独有特色,理解 Go 语言的设计哲学,建立一套专属的使用方法论,那么是很难通过换一门新语言就解决所有的问题的。
-
2021-03-06:go中,公共变量是协程安全吗?赋值操作是原子的吗?为什么?
-
2021-03-05:go中,io密集型的应用,比如有很多文件io,磁盘io,网络io,调大GOMAXPROCS,会不会对性能有帮助?为什么?
-
介绍通常,基于Linux的服务器不附带预安装的图形用户界面(GUI)。每当您想在实例上运行 GUI 应用程序时,典型的解决方案是使用虚拟网络计算 (VNC)。不幸的是,VNC 解决方案可能缓慢且不安全:许多也需要大量的手动配置。相比之下,X2Go提供了一个工作"云桌面",它具有始终在线、远程访问和易于扩展的计算系统的所有优势,并且具有快速网络。它也比许多 VNC 解决方案响应更灵敏、更安全。在此教程中,您将使用 X2Go 创建一个XFCE桌面环境,您可以远程访问该环境。本教程中描述的设置在:您需要访问基于Linux的操作系统,该系统具有桌面环境,但无法将其安装在个人计算机上。您在多个位置(例如个人笔记本电脑、工作笔记本电脑)中使用多个设备,但需要具有相同工具、外观、文件和性能的持久工作环境。想象一下,一个场景,你忘了把你的工作笔记本电脑与你,或它发生故障,你必须发送它进行维修。由于远程桌面上的所有内容都保持不变,您不必重新安装您喜欢用于完成工作的整个套件。您只需登录到远程桌面,无论您从何种设备登录,一切都将在那里,就像您离开时一样。您的互联网服务提供商为您提供很少的带宽,但您需要访问数十或数百千兆字节的数据。例如,您可以利用服务器的快速网络下载 100GB 的数据。由于服务器本身是使用带宽的服务器,因此您不会使用您的互联网服务提供商每月分配给您的配额。相比之下,您只需支付向您发送远程桌面图像所需的网络带宽,而远程桌面的图像非常小。长期运行的工作使您本地计算机在数小时或数天内不可用。想象一下,你必须编译一个大项目,这将需要8小时在你的笔记本电脑上。在项目编制期间,您将无法观看电影或做其他资源密集型的事情。但是,如果您在服务器上运行该作业,现在您的计算机可以自由执行其他任务。您正在与一个团队合作,拥有一台通用的共享计算机对所有成员都有好处,他们可以访问该计算机来协作项目。先决条件在开始此教程之前,您需要:带 2GB 内存或更多内存的openeuler/ CentOS 8 x 64 实例。2GB是最小的,但一个4GB或以上的服务器是理想的,如果你有内存渴望的应用程序,你计划运行。具有超权限和SSH密钥的用户。第 1 步 - 在服务器上安装桌面环境随着您的服务器和防火墙的配置,您现在已准备好安装图形环境。首先,升级实例上的所有软件包:sudo dnf upgrade在此教程中,您正在将XFCE安装为桌面环境。XFCE 不使用图形效果,如合成,使其与 X2Go 更加兼容,并允许它优化屏幕更新如何通过网络发送。换句话说,它可能是最容易得到与X2Go的工作,因为一切立即工作得很好开箱即用。LXDE 也应该开箱即用。MATE 和 KDE 桌面环境可能也有效,但可能需要一些解决方法,例如,禁用合成以提高性能和响应能力。如果您喜欢不同的桌面环境,您必须将此教程中的命令替换为安装,然后将 X2Go 客户端中的会话类型配置为KDE。您还可以在彼此旁边安装多个桌面环境,然后选择您喜欢推出的环境,每次您与 X2Go 客户端一起登录时。sudo dnf groupinstall Xfcesudo dnf group install "KDE Plasma Workspaces"KDE您现在需要安装的软件包不包含在 CentOS 的默认存储库中,因此您必须启用企业 Linux (EPEL) 存储库的额外软件包:sudo dnf install epel-release某些 X2Go 服务器实用程序还依赖于 PowerTool 存储库中找到的某些包,您可以通过下一个命令启用这些软件包:sudo dnf config-manager --set-enabled PowerTools最后,您现在可以安装 XFCE 桌面环境:sudo dnf groupinstall XfceCentOS 提供了一个相当小的 XFCE 环境,但您可以添加任何其他您需要的实用程序(例如,Web 浏览器、图像编辑器),并具有简单的命令。sudo dnf install name_of_application现在安装了桌面环境,是时候在本地计算机上建立查看它的方法了。步骤2-在服务器上安装X2GoX2Go 附带两个主要组件:服务器,它启动和管理远程机器上的图形会话,以及您在当地计算机上安装以查看和控制远程桌面或应用程序的客户端。要在服务器上安装 X2Go,请键入以下命令:sudo dnf install x2goserver此时,您的服务器无需进一步设置。但是,请记住,如果您遵循了在初始服务器设置中使用 CentOS 8设置 SSH 密钥的建议,那么您需要在您打算从每个本地计算机登录到远程桌面会话的每个本地计算机上提供 SSH 私钥。如果您没有设置 SSH 私钥,请确保选择强密码。您已配置了服务器。键入或关闭终端窗口。其余步骤将侧重于在本地机器上配置客户端。exit第3步-本地安装X2Go客户端X2Go 已准备好开箱即用。如果您在本地计算机上使用 Windows 或 macOS,您可以在此处下载 X2Go 客户端软件。如果您使用 Debian 或 Ubuntu,您可以在本地计算机上安装带有此命令的 X2Go 客户端:sudo apt-get install x2goclient下载软件后,您已准备好安装它。打开安装程序并选择首选语言。现在同意许可证,让向导引导您完成其余步骤。通常,不应有任何理由在这些步骤中更改预先填充的默认值。X2Go 开箱即用,但它也非常可定制。如果您想了解更多信息,请访问 X2Go 的官方文档。现在,您已经安装了桌面客户端,您可以配置其设置并连接到 X2Go 服务器以使用远程 XFCE 桌面。第 4 步 - 连接到远程桌面当您首次打开X2Go客户端时,将显示一个窗口。如果没有,请单击左上菜单中的会话,然后选择新会话...在会话名称字段中,输入有助于区分服务器的东西。如果您计划连接到多台机器,则使用会话名称特别有用。在服务器下的主机字段中输入服务器的 IP 地址或完全合格的域名 (FQDN)。在登录字段中输入用于 SSH 连接的用户名。由于您在第二步中安装了 XFCE,请选择XFCE作为您的会话类型。最后,由于您使用 SSH 密钥连接到服务器,请单击使用 RSA/DSA 密钥旁边的文件夹图标进行 ssh 连接并浏览到您的私钥。如果您没有选择使用更安全的 SSH 密钥,请将此密钥留空:每次登录时,X2Go客户端都会要求密码。其余的默认设置现在就足够了,但是随着您对软件的熟悉程度,您可以根据个人喜好对客户端进行微调。按下"确定"按钮后,您可以通过单击框右上角包含会话名称的白色框来开始图形会话。如果您在本地机器上运行 OS X,OS X 可能会提示您安装X 石英,这是运行 X11 所必需的。如果是这样,请按照说明立即安装它。几秒钟后,您的远程桌面将出现,您可以开始与它交互。有几个有用的键盘快捷方式,您可以使用 Windows 和基于 Linux 的操作系统获得更好的体验。注意:前两个选项可以在现代 Windows 版本上显示越野车行为。此时,您仍然可以测试它们,以防 X2Go 的后期版本修复问题。如果失败,只需避免在将来使用相同的键盘快捷方式。CTRL+ALT+F将打开和关闭全屏模式。在全屏模式下工作更像是本地桌面体验。全屏模式还有助于远程机器抓住键盘快捷方式,而不是本地机器。CTRL+ALT+M将最大限度地减少远程视图,即使您处于全屏模式。CTRL+ALT+T将断开与会话的连接,但让GUI在服务器上运行。这只是一种快速断开连接的方式,无需注销或关闭服务器上的应用程序。如果您单击窗口的关闭按钮,也会发生同样的情况。最后,有两种方法可以结束远程会话并关闭其中运行的所有图形程序。您可以从 XFCE 的开始菜单远程注销,也可以单击 X2Go 屏幕主部分右下角标有圆圈和小行(如电源/待机图标)的按钮。第一种方法更清洁,但可能会让会话管理软件等程序运行。第二种方法将关闭所有内容,但如果流程无法干净地退出,则可能会强制关闭。无论哪种情况,请务必在继续之前保存您的工作。
上滑加载中
推荐直播
-
华为开发者空间玩转DeepSeek
2025/03/13 周四 19:00-20:30
马欣 山东商业职业技术学院云计算专业讲师,山东大学、山东建筑大学等多所本科学校学生校外指导老师
同学们,想知道如何利用华为开发者空间部署自己的DeepSeek模型吗?想了解如何用DeepSeek在云主机上探索好玩的应用吗?想探讨如何利用DeepSeek在自己的专有云主机上辅助编程吗?让我们来一场云和AI的盛宴。
即将直播 -
华为云Metastudio×DeepSeek与RAG检索优化分享
2025/03/14 周五 16:00-17:30
大海 华为云学堂技术讲师 Cocl 华为云学堂技术讲师
本次直播将带来DeepSeek数字人解决方案,以及如何使用Embedding与Rerank实现检索优化实践,为开发者与企业提供参考,助力场景落地。
去报名
热门标签