RabbitMQ Golang 语言实现

1、代码实现

git clone https://github.com/nengbai/rabbitmq.git

1.1、 简单队列

  1. Producer 端代码
package main

import (
 "log"
 "os"
 "rabbitmq/lib"
 "strings"
)

func bodyForm(args []string) string {
 var s string
 if (len(args) < 2) || os.Args[1] == "" {
  s = "no Task"
 } else {
  s = strings.Join(args[1:], " ")
 }
 return s
}

func main() {
 conn, err := lib.RabbitMQConn()
 lib.ErrorHanding(err, "failed to connect to RabbitMQ")
 defer conn.Close()
 ch, err := conn.Channel()
 lib.ErrorHanding(err, "failed to open a channel")
 defer ch.Close()
 q, err := ch.QueueDeclare(
  "simple:queue", // name
  false,       // durable
  false,       // delete when unused
  false,       // exclusive
  false,       // no-wait
  nil,         // arguments
 )
 lib.ErrorHanding(err, "Failed to declare a queue")

 msgs, err := ch.Consume(
  q.Name, // queue
  "",  // consumer
  true,// auto-ack
  false,  // exclusive
  false,  // no-local
  false,  // no-wait
  nil, // args
 )
 lib.ErrorHanding(err, "Failed to register a consumer")

 var forever chan struct{}

 go func() {
  for d := range msgs {
log.Printf("Received a message: %s", string(d.Body))
  }
 }()

 log.Printf(" [*] Waiting for messages. To exit press CTRL+C\n")
 <-forever
}

2.Comsumer 端代码

package main

import (
 "log"
 "os"
 "rabbitmq/lib"
 "strings"
)

func bodyForm(args []string) string {
 var s string
 if (len(args) < 2) || os.Args[1] == "" {
  s = "no Task"
 } else {
  s = strings.Join(args[1:], " ")
 }
 return s
}

func main() {
 conn, err := lib.RabbitMQConn()
 lib.ErrorHanding(err, "failed to connect to RabbitMQ")
 defer conn.Close()
 ch, err := conn.Channel()
 lib.ErrorHanding(err, "failed to open a channel")
 defer ch.Close()
 q, err := ch.QueueDeclare(
  "simple:queue", // name
  false,          // durable
  false,          // delete when unused
  false,          // exclusive
  false,          // no-wait
  nil,            // arguments
 )
 lib.ErrorHanding(err, "Failed to declare a queue")

 msgs, err := ch.Consume(
  q.Name, // queue
  "",     // consumer
  true,   // auto-ack
  false,  // exclusive
  false,  // no-local
  false,  // no-wait
  nil,    // args
 )
 lib.ErrorHanding(err, "Failed to register a consumer")

 var forever chan struct{}

 go func() {
  for d := range msgs {
   log.Printf("Received a message: %s", string(d.Body))
  }
 }()

 log.Printf(" [*] Waiting for messages. To exit press CTRL+C\n")
 <-forever
}

3.测试结果

消费端之行程序produncer.go

cd sample
go run produncer.go

消费端之行程序 Comsucer.go

cd sample
go run Comsucer.go

1.2、 工作队列模式

  1. Producer 端代码
package main

import (
 "log"
 "os"
 "rabbitmq/lib"
 "strings"

 "github.com/streadway/amqp"
)

func bodyForm(args []string) string {
 var s string
 if (len(args) < 2) || os.Args[1] == "" {
  s = "no Task"
 } else {
  s = strings.Join(args[1:], " ")
 }
 return s
}

func main() {
 conn, err := lib.RabbitMQConn()
 lib.ErrorHanding(err, "failed to connect to RabbitMQ")
 defer conn.Close()
 ch, err := conn.Channel()
 lib.ErrorHanding(err, "failed to open a channel")
 defer ch.Close()
 q, err := ch.QueueDeclare(
  "task:queue", // name
  false,        // durable
  false,        // delete when unused
  false,        // exclusive
  false,        // no-wait
  nil,          // arguments
 )
 lib.ErrorHanding(err, "Failed to declare a queue")
 // 定义一个消费者
 body := bodyForm(os.Args)
 err = ch.Publish(
  "",
  q.Name,
  false,
  false,
  amqp.Publishing{
   ContentType:  "text/plain",
   DeliveryMode: amqp.Persistent,
   Body:         []byte(body),
  },
 )
 lib.ErrorHanding(err, "Fail to publish a message !")
 log.Println("send message: s%", body)
}

2. Comsumer 端代码

package main

import (
 "log"
 "rabbitmq/lib"
)

func main() {
 conn, err := lib.RabbitMQConn()
 lib.ErrorHanding(err, "failed to connect to RabbitMQ")
 defer conn.Close()
 ch, err := conn.Channel()
 lib.ErrorHanding(err, "failed to open a channel")
 defer ch.Close()
 q, err := ch.QueueDeclare(
  "task:queue", // name
  false,        // durable
  false,        // delete when unused
  false,        // exclusive
  false,        // no-wait
  nil,          // arguments
 )
 lib.ErrorHanding(err, "Failed to declare a queue")
 err = ch.Qos(
  1,
  0,
  false,
 )
 lib.ErrorHanding(err, "Fail to set Qos!")
 msgs, err := ch.Consume(
  q.Name,
  "",
  false,
  false,
  false,
  false,
  nil,
 )
 lib.ErrorHanding(err, "Fail to Register a comsumer!")
 forever := make(chan bool)
 go func() {
  for d := range msgs {
   log.Printf("Reviced a message:%s\n", string(d.Body))
   log.Println("Done")
   d.Ack(false)
  }

 }()
 log.Println(" [*] Wait for message.To text Press CTRL + C")
 <-forever
}

3. 测试结果

生产端之行程序: task.go

cd task
go run task.go

消费端之行程序 worker.go

cd task
go run worker.go

1.3、 Fanout(发布/订阅)

  1. Producer 端代码
package main

import (
 "log"
 "os"
 "rabbitmq/lib"
 "strings"

 "github.com/streadway/amqp"
)

func main() {
 conn, err := lib.RabbitMQConn()
 lib.ErrorHanding(err, "failed to connect to RabbitMQ")
 defer conn.Close()
 ch, err := conn.Channel()
 lib.ErrorHanding(err, "failed to open a channel")
 defer ch.Close()

 err = ch.ExchangeDeclare(
  "exchange_logs", // name
  "fanout",        // type
  true,            // durable
  false,           // auto-deleted
  false,           // internal
  false,           // no-wait
  nil,             // arguments
 )
 lib.ErrorHanding(err, "Failed to declare an exchange")

 //ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 //defer cancel()

 body := bodyFrom(os.Args)

 err = ch.Publish(
  "exchange_logs", // exchange
  "",              // routing key
  false,           // mandatory
  false,           // immediate
  amqp.Publishing{
   ContentType: "text/plain",
   Body:        []byte(body),
  })
 lib.ErrorHanding(err, "Failed to publish a message")

 log.Printf(" [x] Sent %s\n", body)
}

func bodyFrom(args []string) string {
 var s string
 if (len(args) < 2) || os.Args[1] == "" {
  s = "hello"
 } else {
  s = strings.Join(args[1:], " ")
 }
 return s
}

2. Consumer 端代码

package main

import (
 "log"
 "rabbitmq/lib"
)

func main() {
 conn, err := lib.RabbitMQConn()
 lib.ErrorHanding(err, "failed to connect to RabbitMQ")
 defer conn.Close()
 ch, err := conn.Channel()
 lib.ErrorHanding(err, "failed to open a channel")
 defer ch.Close()

 err = ch.ExchangeDeclare(
  "exchange_logs", // exchange name
  "fanout",        // type
  true,            // durable
  false,           // auto-deleted
  false,           // internal
  false,           // no-wait
  nil,             // arguments
 )
 lib.ErrorHanding(err, "Failed to declare an exchange")

 q, err := ch.QueueDeclare(
  "",    // name
  false, // durable
  false, // delete when unused
  true,  // exclusive
  false, // no-wait
  nil,   // arguments
 )
 lib.ErrorHanding(err, "Failed to declare a queue")

 err = ch.QueueBind(
  q.Name,          // queue name
  "",              // routing key
  "exchange_logs", // exchange
  false,
  nil,
 )
 lib.ErrorHanding(err, "Failed to bind a queue")

 msgs, err := ch.Consume(
  q.Name, // queue
  "",     // consumer
  true,   // auto-ack
  false,  // exclusive
  false,  // no-local
  false,  // no-wait
  nil,    // args
 )
 lib.ErrorHanding(err, "Failed to register a consumer")

 var forever chan struct{}

 go func() {
  for d := range msgs {
   log.Printf(" [x] %s", string(d.Body))
  }
 }()

 log.Println(" [*] Waiting for logs. To exit press CTRL+C")
 <-forever
}

3. 测试结果

消费端之行程序 receive_logs.go

cd fanout
go run receive_logs.go

生产端之行程序: emit_log.go

cd fanout
go run emit_log.go 1
go run emit_log.go 2
go run emit_log.go 3
go run emit_log.go 4
go run emit_log.go 5

1.4、 Routing模式

  1. Producer 端代码
package main

import (
 "log"
 "os"
 "rabbitmq/lib"
 "strings"

 "github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
 if err != nil {
  log.Panicf("%s: %s", msg, err)
 }
}

func main() {
 conn, err := lib.RabbitMQConn()
 lib.ErrorHanding(err, "failed to connect to RabbitMQ")
 defer conn.Close()
 ch, err := conn.Channel()
 lib.ErrorHanding(err, "failed to open a channel")
 defer ch.Close()

 err = ch.ExchangeDeclare(
  "logs_direct", // name
  "direct",      // type
  true,          // durable
  false,         // auto-deleted
  false,         // internal
  false,         // no-wait
  nil,           // arguments
 )
 lib.ErrorHanding(err, "Failed to declare an exchange")

 //ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 //defer cancel()

 body := bodyFrom(os.Args)
 err = ch.Publish(
  "logs_direct",         // exchange
  severityFrom(os.Args), // routing key
  false,                 // mandatory
  false,                 // immediate
  amqp.Publishing{
   ContentType: "text/plain",
   Body:        []byte(body),
  })
 failOnError(err, "Failed to publish a message")

 log.Printf(" [x] Sent %s", body)
}

func bodyFrom(args []string) string {
 var s string
 if (len(args) < 3) || os.Args[2] == "" {
  s = "hello"
 } else {
  s = strings.Join(args[2:], " ")
 }
 return s
}

func severityFrom(args []string) string {
 var s string
 if (len(args) < 2) || os.Args[1] == "" {
  s = "info"
 } else {
  s = os.Args[1]
 }
 return s
}

2、 Consumer 端代码

package main

import (
 "log"
 "os"
 "rabbitmq/lib"
)

func main() {
 conn, err := lib.RabbitMQConn()
 lib.ErrorHanding(err, "failed to connect to RabbitMQ")
 defer conn.Close()
 ch, err := conn.Channel()
 lib.ErrorHanding(err, "failed to open a channel")
 defer ch.Close()

 err = ch.ExchangeDeclare(
  "logs_direct", // name
  "direct",      // type
  true,          // durable
  false,         // auto-deleted
  false,         // internal
  false,         // no-wait
  nil,           // arguments
 )
 lib.ErrorHanding(err, "Failed to declare an exchange")

 q, err := ch.QueueDeclare(
  "",    // name
  false, // durable
  false, // delete when unused
  true,  // exclusive
  false, // no-wait
  nil,   // arguments
 )
 lib.ErrorHanding(err, "Failed to declare a queue")

 if len(os.Args) < 2 {
  log.Printf("Usage: %s [info] [warning] [error]\n", os.Args[0])
  os.Exit(0)
 }
 for _, s := range os.Args[1:] {
  log.Printf("Binding queue %s to exchange %s with routing key %s\n",
   q.Name, "logs_direct", s)
  err = ch.QueueBind(
   q.Name,        // queue name
   s,             // routing key
   "logs_direct", // exchange
   false,
   nil)
  lib.ErrorHanding(err, "Failed to bind a queue")
 }

 msgs, err := ch.Consume(
  q.Name, // queue
  "",     // consumer
  true,   // auto ack
  false,  // exclusive
  false,  // no local
  false,  // no wait
  nil,    // args
 )
 lib.ErrorHanding(err, "Failed to register a consumer")

 var forever chan struct{}

 go func() {
  for d := range msgs {
   log.Printf(" [x] %s", string(d.Body))
  }
 }()

 log.Printf(" [*] Waiting for logs. To exit press CTRL+C\n")
 <-forever
}

3、测试结果

消费端之行程序 receivelogsdirect.go

cd routing
go run receive_logs_direct.go warning
go run receive_logs_direct.go error

生产端之行程序: emitlogdirect.go

cd routing
go run emit_log_direct.go warning "Notice, this is Warning." 
go run emit_log_direct.go error "Run. Run. Or it will explode."

1.5、 Topics模式

  1. Producer 端代码
package main

import (
 "log"
 "os"
 "rabbitmq/lib"
 "strings"

 "github.com/streadway/amqp"
)

func main() {
 conn, err := lib.RabbitMQConn()
 lib.ErrorHanding(err, "failed to connect to RabbitMQ")
 defer conn.Close()
 ch, err := conn.Channel()
 lib.ErrorHanding(err, "failed to open a channel")
 defer ch.Close()

 err = ch.ExchangeDeclare(
  "logs_topic", // name
  "topic",      // type
  true,         // durable
  false,        // auto-deleted
  false,        // internal
  false,        // no-wait
  nil,          // arguments
 )
 lib.ErrorHanding(err, "Failed to declare an exchange")

 // ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 // defer cancel()

 body := bodyFrom(os.Args)
 err = ch.Publish(
  "logs_topic",          // exchange
  severityFrom(os.Args), // routing key
  false,                 // mandatory
  false,                 // immediate
  amqp.Publishing{
   ContentType: "text/plain",
   Body:        []byte(body),
  })
 lib.ErrorHanding(err, "Failed to publish a message")

 log.Printf(" [x] Sent %s", body)
}

func bodyFrom(args []string) string {
 var s string
 if (len(args) < 3) || os.Args[2] == "" {
  s = "hello"
 } else {
  s = strings.Join(args[2:], " ")
 }
 return s
}

func severityFrom(args []string) string {
 var s string
 if (len(args) < 2) || os.Args[1] == "" {
  s = "anonymous.info"
 } else {
  s = os.Args[1]
 }
 return s
}

2、Consumer 端代码

package main

import (
 "log"
 "os"
 "rabbitmq/lib"
)

func main() {
 conn, err := lib.RabbitMQConn()
 lib.ErrorHanding(err, "failed to connect to RabbitMQ")
 defer conn.Close()
 ch, err := conn.Channel()
 lib.ErrorHanding(err, "failed to open a channel")
 defer ch.Close()

 err = ch.ExchangeDeclare(
  "logs_topic", // name
  "topic",      // type
  true,         // durable
  false,        // auto-deleted
  false,        // internal
  false,        // no-wait
  nil,          // arguments
 )
 lib.ErrorHanding(err, "Failed to declare an exchange")

 q, err := ch.QueueDeclare(
  "",    // name
  false, // durable
  false, // delete when unused
  true,  // exclusive
  false, // no-wait
  nil,   // arguments
 )
 lib.ErrorHanding(err, "Failed to declare a queue")

 if len(os.Args) < 2 {
  log.Printf("Usage: %s [binding_key]...", os.Args[0])
  os.Exit(0)
 }
 for _, s := range os.Args[1:] {
  log.Printf("Binding queue %s to exchange %s with routing key %s",
   q.Name, "logs_topic", s)
  err = ch.QueueBind(
   q.Name,       // queue name
   s,            // routing key
   "logs_topic", // exchange
   false,
   nil)
  lib.ErrorHanding(err, "Failed to bind a queue")
 }

 msgs, err := ch.Consume(
  q.Name, // queue
  "",     // consumer
  true,   // auto ack
  false,  // exclusive
  false,  // no local
  false,  // no wait
  nil,    // args
 )
 lib.ErrorHanding(err, "Failed to register a consumer")

 var forever chan struct{}

 go func() {
  for d := range msgs {
   log.Printf(" [x] %s", string(d.Body))
  }
 }()

 log.Printf(" [*] Waiting for logs. To exit press CTRL+C\n")
 <-forever
}

3、测试结果

消费端之行程序 receivelogstopic.go

cd topic
# shell1
go run receive_logs_topic.go "#"
​
# shell2
go run receive_logs_topic.go "kern.*"
​
# shell3
go run receive_logs_topic.go "*.critical"
​
# shell4
go run receive_logs_topic.go "kern.*" "*.critical"
​
# shell5 
go run emit_log_topic.go "kern.critical" "A critical kernel error"

生产端之行程序: emitlogtopic.go

cd topic
go run emit_log_topic.go "kern.critical" "A critical kernel error"

1.6、 RPC模式

  1. Server 端代码
package main

import (
 "log"
 "rabbitmq/lib"
 "strconv"

 "github.com/streadway/amqp"
)

func fib(n int) int {
 if n == 0 {
  return 0
 } else if n == 1 {
  return 1
 } else {
  return fib(n-1) + fib(n-2)
 }
}

func main() {
 conn, err := lib.RabbitMQConn()
 lib.ErrorHanding(err, "failed to connect to RabbitMQ")
 defer conn.Close()
 ch, err := conn.Channel()
 lib.ErrorHanding(err, "failed to open a channel")
 defer ch.Close()

 q, err := ch.QueueDeclare(
  "rpc_queue", // name
  false,       // durable
  false,       // delete when unused
  false,       // exclusive
  false,       // no-wait
  nil,         // arguments
 )
 lib.ErrorHanding(err, "Failed to declare a queue")

 err = ch.Qos(
  1,     // prefetch count
  0,     // prefetch size
  false, // global
 )
 lib.ErrorHanding(err, "Failed to set QoS")

 msgs, err := ch.Consume(
  q.Name, // queue
  "",     // consumer
  false,  // auto-ack
  false,  // exclusive
  false,  // no-local
  false,  // no-wait
  nil,    // args
 )
 lib.ErrorHanding(err, "Failed to register a consumer")

 var forever chan struct{}

 go func() {
  // ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  // defer cancel()
  for d := range msgs {
   n, err := strconv.Atoi(string(d.Body))
   lib.ErrorHanding(err, "Failed to convert body to integer")

   log.Printf(" [.] fib(%d)", n)
   response := fib(n)

   err = ch.Publish(
    "",        // exchange
    d.ReplyTo, // routing key
    false,     // mandatory
    false,     // immediate
    amqp.Publishing{
     ContentType:   "text/plain",
     CorrelationId: d.CorrelationId,
     Body:          []byte(strconv.Itoa(response)),
    })
   lib.ErrorHanding(err, "Failed to publish a message")

   d.Ack(false)
  }
 }()

 log.Printf(" [*] Awaiting RPC requests")
 <-forever
}

2、Client 端代码

package main

import (
 "log"
 "math/rand"
 "os"
 "rabbitmq/lib"
 "strconv"
 "strings"
 "time"

 "github.com/streadway/amqp"
)

func randomString(l int) string {
 bytes := make([]byte, l)
 for i := 0; i < l; i++ {
  bytes[i] = byte(randInt(65, 90))
 }
 return string(bytes)
}

func randInt(min int, max int) int {
 return min + rand.Intn(max-min)
}

func fibonacciRPC(n int) (res int, err error) {
 conn, err := lib.RabbitMQConn()
 lib.ErrorHanding(err, "failed to connect to RabbitMQ")
 defer conn.Close()
 ch, err := conn.Channel()
 lib.ErrorHanding(err, "failed to open a channel")
 defer ch.Close()

 q, err := ch.QueueDeclare(
  "",    // name
  false, // durable
  false, // delete when unused
  true,  // exclusive
  false, // noWait
  nil,   // arguments
 )
 lib.ErrorHanding(err, "Failed to declare a queue")

 msgs, err := ch.Consume(
  q.Name, // queue
  "",     // consumer
  true,   // auto-ack
  false,  // exclusive
  false,  // no-local
  false,  // no-wait
  nil,    // args
 )
 lib.ErrorHanding(err, "Failed to register a consumer")

 corrId := randomString(32)

 // ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 // defer cancel()

 err = ch.Publish(
  "",          // exchange
  "rpc_queue", // routing key
  false,       // mandatory
  false,       // immediate
  amqp.Publishing{
   ContentType:   "text/plain",
   CorrelationId: corrId,
   ReplyTo:       q.Name,
   Body:          []byte(strconv.Itoa(n)),
  })
 lib.ErrorHanding(err, "Failed to publish a message")

 for d := range msgs {
  if corrId == d.CorrelationId {
   res, err = strconv.Atoi(string(d.Body))
   lib.ErrorHanding(err, "Failed to convert body to integer")
   break
  }
 }

 return
}

func main() {
 rand.Seed(time.Now().UTC().UnixNano())

 n := bodyFrom(os.Args)

 log.Printf(" [x] Requesting fib(%d)", n)
 res, err := fibonacciRPC(n)
 lib.ErrorHanding(err, "Failed to handle RPC request")

 log.Printf(" [.] Got %d", res)
}

func bodyFrom(args []string) int {
 var s string
 if (len(args) < 2) || os.Args[1] == "" {
  s = "30"
 } else {
  s = strings.Join(args[1:], " ")
 }
 n, err := strconv.Atoi(s)
 lib.ErrorHanding(err, "Failed to convert arg to integer")
 return n
}

3、测试结果

服务器端之行程序: rpc_server.go

cd rpc
go run rpc_server.go

客户端之行程序 rpc_client.go

cd rpc
go run rpc_server.go 5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值