Ubuntu 18.04/20.04/22.04: libcrypto.so.1.0.0: cannot open shared object file: No such file or directory

这是因为高版本的ubuntu没有低版本的libcrypto.so1.0 libcrypto.so.1.1文件。

可以下载指定版本并安装,即可解决找不到文件的问题。

1. 直接下载deb包
wget https://debian.mirror.ac.za/debian/pool/main/o/openssl/libssl1.1_1.1.1w-0%2Bdeb11u1_amd64.deb
sudo dpkg -i libssl1.1_1.1.1o-1_amd64.deb

2. 在官网下载源码
#从官网下载
# wget https://www.openssl.org/source/openssl-1.1.1g.tar.gz
 
#腾讯云提供的镜像wget https://mirrors.cloud.tencent.com/openssl/source/openssl-1.1.1g.tar.g

#安装
tar -xvf openssl-1.1.1g.tar.gz
cd openssl-1.1.1g
./config shared --openssldir=/usr/local/openssl --prefix=/usr/local/openssl
make && make install
Go语言教程之边写边学:数据结构与算法:汉诺塔Tower of Hanoi

汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

实现代码:

package main
 
import "fmt"

type solver interface {
    play(int)
}
  
// towers is example of type satisfying solver interface
type towers struct {
    // an empty struct
}
 
// play is sole method required to implement solver type
func (t *towers) play(n int) {    
    t.moveN(n, 1, 2, 3)
}
 
// recursive algorithm
func (t *towers) moveN(n, from, to, via int) {
    if n > 0 {
        t.moveN(n-1, from, via, to)
        t.moveM(from, to)
        t.moveN(n-1, via, to, from)
    }
}

func (t *towers) moveM(from, to int) {
    fmt.Println("Move disk from rod", from, "to rod", to)
}

func main() {
    var t solver    
    t = new(towers) // type towers must satisfy solver interface
    t.play(4)
}

输出:

Move disk from rod 1 to rod 3
Move disk from rod 1 to rod 2
Move disk from rod 3 to rod 2
Move disk from rod 1 to rod 3
Move disk from rod 2 to rod 1
Move disk from rod 2 to rod 3
Move disk from rod 1 to rod 3
Move disk from rod 1 to rod 2
Move disk from rod 3 to rod 2
Move disk from rod 3 to rod 1
Move disk from rod 2 to rod 1
Move disk from rod 3 to rod 2
Move disk from rod 1 to rod 3
Move disk from rod 1 to rod 2
Move disk from rod 3 to rod 2
nginx:no resolver defined to resolve xxx.xxx”

这是因为无法解析proxy_pass部分的域名,

在nginx.conf配置文件中的http{}部分添加一行resolver 8.8.8.8;

git:fatal: Not possible to fast-forward, aborting.

执行git pull origin xxx(分支) --rebase之后先push上远程分支。

npm错误信息:error:0308010C:digital envelope routines::unsupported

这是因为 node.js V17版本中最近发布的OpenSSL3.0, 而OpenSSL3.0对允许算法和密钥大小增加了严格的限制,可能会对生态系统造成一些影响。故此以前的项目在升级 nodejs 版本后会报错。

修改package.json,在相关构建命令之前加入SET NODE_OPTIONS=--openssl-legacy-provider,然后正常运行npm run serve即可。

"scripts": {
   "serve": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve",
   "build": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build"
},
php imagck读取pdf错误:attempt to perform an operation not allowed by the security policy PDF

这是ImageMagic中有权限配置文件,需要修改PDF相关的读写权限。

# 打开policy.xml文件

sudo nano /etc/ImageMagick-6/policy.xml

# 修改PDF相关权限,由none改为read|write

<policy domain="coder" rights="none" pattern="PDF" />

# 改为

<policy domain="coder" rights="read|write" pattern="PDF" />

 

让notepad根据编辑器窗口大小自动换行的方法

 默认的notepad设置是文本超长时,是横向无线延申,查看内容时非常麻烦,使用工具栏的word wrap按钮即可实现根据窗口大小自动换行。

 

Nano游戏框架源码分析-应用

# 入口函数

```

func main() {

    // cli框架:https://cli.urfave.org/

app := cli.NewApp()


// APP基础信息

app.Name = "mahjong server"

app.Author = "MaJong"

app.Version = "0.0.1"

app.Copyright = "majong team reserved"

app.Usage = "majiang server"


// 需要解析的flag

app.Flags = []cli.Flag{

cli.StringFlag{

Name:  "config, c",

Value: "./configs/config.toml",

Usage: "load configuration from `FILE`",

},

cli.BoolFlag{

Name:  "cpuprofile",

Usage: "enable cpu profile",

},

}


    // 核心:主要功能方法

app.Action = serve

app.Run(os.Args)

}


// server方法

func serve(c *cli.Context) error {

    // viper:https://github.com/spf13/viper

    // 解析配置文件

viper.SetConfigType("toml")

viper.SetConfigFile(c.String("config"))

viper.ReadInConfig()


    // 日志配置

log.SetFormatter(&log.TextFormatter{DisableColors: true})

if viper.GetBool("core.debug") {

log.SetLevel(log.DebugLevel)

}


    // 记录cpu信息

if c.Bool("cpuprofile") {

filename := fmt.Sprintf("cpuprofile-%d.pprof", time.Now().Unix())

f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE, os.ModePerm)

if err != nil {

panic(err)

}

pprof.StartCPUProfile(f)

defer pprof.StopCPUProfile()

}


    // 开启2个goroutine

wg := sync.WaitGroup{}

wg.Add(2)


    // 核心:goroutine:游戏服务

go func() { defer wg.Done(); game.Startup() }() // 开启游戏服

    // 核心:goroutine:网页服务

go func() { defer wg.Done(); web.Startup() }()  // 开启web服务器


    // 等待gorounite结束

wg.Wait()

    

return nil

}

```


## 核心:goroutine:游戏服务

```

# 启动游戏服务

func Startup() {

    // 随机数种子

rand.Seed(time.Now().Unix())

    // 获取版本号

version = viper.GetString("update.version")

    // 获取心跳配置

heartbeat := viper.GetInt("core.heartbeat")

if heartbeat < 5 {

heartbeat = 5

}


// 房卡消耗配置

csm := viper.GetString("core.consume")

SetCardConsume(csm)

forceUpdate = viper.GetBool("update.force")


logger.Infof("当前游戏服务器版本: %s, 是否强制更新: %t, 当前心跳时间间隔: %d秒", version, forceUpdate, heartbeat)

logger.Info("game service starup")


// 核心:注册游戏handler/component

comps := &component.Components{}

comps.Register(defaultManager)

comps.Register(defaultDeskManager)

comps.Register(new(ClubManager))


// 核心:加密管道

c := newCrypto()

pip := pipeline.New()

pip.Inbound().PushBack(c.inbound)

pip.Outbound().PushBack(c.outbound)


    // 打印信息

addr := fmt.Sprintf(":%d", viper.GetInt("game-server.port"))

nano.Listen(addr,

nano.WithPipeline(pip),

nano.WithHeartbeatInterval(time.Duration(heartbeat)*time.Second),

nano.WithLogger(log.WithField("component", "nano")),

nano.WithSerializer(json.NewSerializer()),

nano.WithComponents(comps),

)

}

```


### 核心:component管理


```

// Components定义


// 一个component和option数组

type CompWithOptions struct {

Comp Component

Opts []Option

}

// CompWithOptions数组

type Components struct {

comps []CompWithOptions

}


// 注册方法

func (cs *Components) Register(c Component, options ...Option) {

cs.comps = append(cs.comps, CompWithOptions{c, options})

}


// 返回component列表

func (cs *Components) List() []CompWithOptions {

return cs.comps

}

```

```

// component定义

type Component interface {

Init()

AfterInit()

BeforeShutdown()

Shutdown()

}

```

#### defaultManager:游戏component

```

var defaultManager = NewManager()


// manager定义

type (

Manager struct {

component.Base               // 空实现

group      *nano.Group       // 核心:广播channel

players    map[int64]*Player // 核心:所有的玩家

chKick     chan int64        // 退出队列

chReset    chan int64        // 重置队列

chRecharge chan RechargeInfo // 充值信息

}


RechargeInfo struct {

Uid  int64 // 用户ID

Coin int64 // 房卡数量

}

)


// 创建manager

func NewManager() *Manager {

return &Manager{

group:      nano.NewGroup("_SYSTEM_MESSAGE_BROADCAST"),

players:    map[int64]*Player{},

chKick:     make(chan int64, kickResetBacklog),

chReset:    make(chan int64, kickResetBacklog),

chRecharge: make(chan RechargeInfo, 32),

}

}

```

##### nano的Group模块

```

nano/Group.go

```

##### 麻将游戏的player逻辑

```

internal/game/player.go

```


#### defaultDeskManager:桌牌component

```

type (

DeskManager struct {

component.Base

//桌子数据

desks map[room.Number]*Desk // 所有桌子

}

)


var defaultDeskManager = NewDeskManager()

```


#### ClubManager: 俱乐部component

```

type ClubManager struct {

component.Base

}


func (c *ClubManager) ApplyClub(s *session.Session, payload *protocol.ApplyClubRequest) error {

mid := s.LastMid()

logger.Debugf("玩家申请加入俱乐部,UID=%d,俱乐部ID=%d", s.UID(), payload.ClubId)

async.Run(func() {

if err := db.ApplyClub(s.UID(), payload.ClubId); err != nil {

s.ResponseMID(mid, &protocol.ErrorResponse{

Code:  -1,

Error: err.Error(),

})

} else {

s.ResponseMID(mid, &protocol.SuccessResponse)

}

})

return nil

}

```


### 核心:加密

```

// Crypto

// github.com/xxtea/xxtea-go/xxtea

type Crypto struct {

key []byte

}


func newCrypto() *Crypto {

return &Crypto{xxteaKey}

}


func (c *Crypto) inbound(s *session.Session, msg *pipeline.Message) error {

out, err := base64.StdEncoding.DecodeString(string(msg.Data))

if err != nil {

logger.Errorf("Inbound Error=%s, In=%s", err.Error(), string(msg.Data))

return err

}


out = xxtea.Decrypt(out, c.key)

if out == nil {

return fmt.Errorf("decrypt error=%s", err.Error())

}

msg.Data = out

return nil

}


func (c *Crypto) outbound(s *session.Session, msg *pipeline.Message) error {

out := xxtea.Encrypt(msg.Data, c.key)

msg.Data = []byte(base64.StdEncoding.EncodeToString(out))

return nil

}

```


### 核心:管道

```

type (

// Message is the alias of `message.Message`

Message = message.Message


Func func(s *session.Session, msg *message.Message) error


Pipeline interface {

Outbound() Channel

Inbound() Channel

}


pipeline struct {

outbound, inbound *pipelineChannel

}


Channel interface {

PushFront(h Func)

PushBack(h Func)

Process(s *session.Session, msg *message.Message) error

}


pipelineChannel struct {

mu       sync.RWMutex

handlers []Func

}

)


func New() Pipeline {

return &pipeline{

outbound: &pipelineChannel{},

inbound:  &pipelineChannel{},

}

}


func (p *pipeline) Outbound() Channel { return p.outbound }

func (p *pipeline) Inbound() Channel  { return p.inbound }


// PushFront push a function to the front of the pipeline

func (p *pipelineChannel) PushFront(h Func) {

p.mu.Lock()

defer p.mu.Unlock()

handlers := make([]Func, len(p.handlers)+1)

handlers[0] = h

copy(handlers[1:], p.handlers)

p.handlers = handlers

}


// PushFront push a function to the end of the pipeline

func (p *pipelineChannel) PushBack(h Func) {

p.mu.Lock()

defer p.mu.Unlock()

p.handlers = append(p.handlers, h)

}


// Process process message with all pipeline functions

func (p *pipelineChannel) Process(s *session.Session, msg *message.Message) error {

p.mu.RLock()

defer p.mu.RUnlock()

if len(p.handlers) < 1 {

return nil

}

for _, h := range p.handlers {

err := h(s, msg)

if err != nil {

return err

}

}

return nil

}


```


### 核心:消息定义

```

package message


import (

"encoding/binary"

"errors"

"fmt"

"strings"


"github.com/lonng/nano/internal/log"

)


// Type represents the type of message, which could be Request/Notify/Response/Push

type Type byte


// Message types

const (

Request  Type = 0x00

Notify        = 0x01

Response      = 0x02

Push          = 0x03

)


const (

msgRouteCompressMask = 0x01

msgTypeMask          = 0x07

msgRouteLengthMask   = 0xFF

msgHeadLength        = 0x02

)


var types = map[Type]string{

Request:  "Request",

Notify:   "Notify",

Response: "Response",

Push:     "Push",

}


func (t Type) String() string {

return types[t]

}


var (

routes = make(map[string]uint16) // route map to code

codes  = make(map[uint16]string) // code map to route

)


// Errors that could be occurred in message codec

var (

ErrWrongMessageType  = errors.New("wrong message type")

ErrInvalidMessage    = errors.New("invalid message")

ErrRouteInfoNotFound = errors.New("route info not found in dictionary")

)


// Message represents a unmarshaled message or a message which to be marshaled

type Message struct {

Type       Type   // message type

ID         uint64 // unique id, zero while notify mode

Route      string // route for locating service

Data       []byte // payload

compressed bool   // is message compressed

}


// New returns a new message instance

func New() *Message {

return &Message{}

}


// String, implementation of fmt.Stringer interface

func (m *Message) String() string {

return fmt.Sprintf("%s %s (%dbytes)", types[m.Type], m.Route, len(m.Data))

}


// Encode marshals message to binary format.

func (m *Message) Encode() ([]byte, error) {

return Encode(m)

}


func routable(t Type) bool {

return t == Request || t == Notify || t == Push

}


func invalidType(t Type) bool {

return t < Request || t > Push


}


// Encode marshals message to binary format. Different message types is corresponding to

// different message header, message types is identified by 2-4 bit of flag field. The

// relationship between message types and message header is presented as follows:

// ------------------------------------------

// |   type   |  flag  |       other        |

// |----------|--------|--------------------|

// | request  |----000-|<message id>|<route>|

// | notify   |----001-|<route>             |

// | response |----010-|<message id>        |

// | push     |----011-|<route>             |

// ------------------------------------------

// The figure above indicates that the bit does not affect the type of message.

// See ref: https://github.com/lonnng/nano/blob/master/docs/communication_protocol.md

func Encode(m *Message) ([]byte, error) {

if invalidType(m.Type) {

return nil, ErrWrongMessageType

}


buf := make([]byte, 0)

flag := byte(m.Type) << 1


code, compressed := routes[m.Route]

if compressed {

flag |= msgRouteCompressMask

}

buf = append(buf, flag)


if m.Type == Request || m.Type == Response {

n := m.ID

// variant length encode

for {

b := byte(n % 128)

n >>= 7

if n != 0 {

buf = append(buf, b+128)

} else {

buf = append(buf, b)

break

}

}

}


if routable(m.Type) {

if compressed {

buf = append(buf, byte((code>>8)&0xFF))

buf = append(buf, byte(code&0xFF))

} else {

buf = append(buf, byte(len(m.Route)))

buf = append(buf, []byte(m.Route)...)

}

}


buf = append(buf, m.Data...)

return buf, nil

}


// Decode unmarshal the bytes slice to a message

// See ref: https://github.com/lonnng/nano/blob/master/docs/communication_protocol.md

func Decode(data []byte) (*Message, error) {

if len(data) < msgHeadLength {

return nil, ErrInvalidMessage

}

m := New()

flag := data[0]

offset := 1

m.Type = Type((flag >> 1) & msgTypeMask)


if invalidType(m.Type) {

return nil, ErrWrongMessageType

}


if m.Type == Request || m.Type == Response {

id := uint64(0)

// little end byte order

// WARNING: must can be stored in 64 bits integer

// variant length encode

for i := offset; i < len(data); i++ {

b := data[i]

id += uint64(b&0x7F) << uint64(7*(i-offset))

if b < 128 {

offset = i + 1

break

}

}

m.ID = id

}


if routable(m.Type) {

if flag&msgRouteCompressMask == 1 {

m.compressed = true

code := binary.BigEndian.Uint16(data[offset:(offset + 2)])

route, ok := codes[code]

if !ok {

return nil, ErrRouteInfoNotFound

}

m.Route = route

offset += 2

} else {

m.compressed = false

rl := data[offset]

offset++

m.Route = string(data[offset:(offset + int(rl))])

offset += int(rl)

}

}


m.Data = data[offset:]

return m, nil

}


// SetDictionary set routes map which be used to compress route.

// TODO(warning): set dictionary in runtime would be a dangerous operation!!!!!!

func SetDictionary(dict map[string]uint16) {

for route, code := range dict {

r := strings.TrimSpace(route)


// duplication check

if _, ok := routes[r]; ok {

log.Println(fmt.Sprintf("duplicated route(route: %s, code: %d)", r, code))

}


if _, ok := codes[code]; ok {

log.Println(fmt.Sprintf("duplicated route(route: %s, code: %d)", r, code))

}


// update map, using last value when key duplicated

routes[r] = code

codes[code] = r

}

}


```

### Listen

```

nano.Listen(addr,

nano.WithPipeline(pip),

nano.WithHeartbeatInterval(time.Duration(heartbeat)*time.Second),

nano.WithLogger(log.WithField("component", "nano")),

nano.WithSerializer(json.NewSerializer()),

nano.WithComponents(comps),

```

```

func Listen(addr string, opts ...Option) {

if atomic.AddInt32(&running, 1) != 1 {

log.Println("Nano has running")

return

}


// application initialize

app.name = strings.TrimLeft(filepath.Base(os.Args[0]), "/")

app.startAt = time.Now()


// environment initialize

if wd, err := os.Getwd(); err != nil {

panic(err)

} else {

env.Wd, _ = filepath.Abs(wd)

}


opt := cluster.Options{

Components: &component.Components{},

}

for _, option := range opts {

option(&opt)

}


// Use listen address as client address in non-cluster mode

if !opt.IsMaster && opt.AdvertiseAddr == "" && opt.ClientAddr == "" {

log.Println("The current server running in singleton mode")

opt.ClientAddr = addr

}


// Set the retry interval to 3 secondes if doesn't set by user

if opt.RetryInterval == 0 {

opt.RetryInterval = time.Second * 3

}


node := &cluster.Node{

Options:     opt,

ServiceAddr: addr,

}

err := node.Startup()

if err != nil {

log.Fatalf("Node startup failed: %v", err)

}

runtime.CurrentNode = node


if node.ClientAddr != "" {

log.Println(fmt.Sprintf("Startup *Nano gate server* %s, client address: %v, service address: %s",

app.name, node.ClientAddr, node.ServiceAddr))

} else {

log.Println(fmt.Sprintf("Startup *Nano backend server* %s, service address %s",

app.name, node.ServiceAddr))

}


go scheduler.Sched()

sg := make(chan os.Signal)

signal.Notify(sg, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM)


select {

case <-env.Die:

log.Println("The app will shutdown in a few seconds")

case s := <-sg:

log.Println("Nano server got signal", s)

}


log.Println("Nano server is stopping...")


node.Shutdown()

runtime.CurrentNode = nil

scheduler.Close()

atomic.StoreInt32(&running, 0)

}

```

  • 当前日期:
  • 北京时间:
  • 时间戳:
  • 今年的第:18周
  • 我的 IP:3.136.26.17
农历
五行
冲煞
彭祖
方位
吉神
凶神
极简任务管理 help
+ 0 0 0
Task Idea Collect