Go 语言圣经 练习8.1

Go语言圣经 练习8.1

练习 8.1: 修改clock2来支持传入参数作为端口号,然后写一个clockwall的程序,这个程序可以同时与多个clock服务器通信,从多个服务器中读取时间,并且在一个表格中一次显示所有服务器传回的结果,类似于你在某些办公室里看到的时钟墙。如果你有地理学上分布式的服务器可以用的话,让这些服务器跑在不同的机器上面;或者在同一台机器上跑多个不同的实例,这些实例监听不同的端口,假装自己在不同的时区。像下面这样:

$ TZ=US/Eastern    ./clock2 -port 8010 &
$ TZ=Asia/Tokyo    ./clock2 -port 8020 &
$ TZ=Europe/London ./clock2 -port 8030 &
$ clockwall NewYork=localhost:8010 Tokyo=localhost:8020 London=localhost:8030

服务端clock

首先修改clock2的代码以支持命令行参数,支持命令行参数主要有两种方式:

  1. 直接使用os.Args[1:]读取命令行参数,自行对读取到的字段进行解析。
  2. 使用之前 7.4节介绍的flag.Value接口来读取命令行参数

本文使用第二种方法实现,这样既可以熟悉之前章节的知识,也较为方便。 然后对应不同port 做不同的处理(handleConn中执行swtich分支处理)

package main

import (
	"flag"
	"io"
	"log"
	"net"
	"time"
)

var port = flag.String("port", "8000", "timeZone")

func main() {
	flag.Parse()
	listener, err := net.Listen("tcp", "localhost:"+*port)
	if err != nil {
		log.Fatal(err)
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Print(err) // e.g., connection aborted
			continue
		}
		go handleConn(*port, conn) // handle one connection at a time
	}
}

func handleConn(port string, c net.Conn) {
	defer c.Close()
	var timeZone string
	switch port {
	case "8010":
		timeZone = "US/Eastern "
	case "8020":
		timeZone = "Asia/Tokyo "
	case "8030":
		timeZone = "Europe/London "
	}

	for {
		_, err := io.WriteString(c, "TZ="+timeZone+time.Now().Format("15:04:05\n"))
		if err != nil {
			return // e.g., client disconnectedn
		}
		time.Sleep(1 * time.Second)
	}
}

为了更方便的运行,写了个shell

#!/bin/zsh
TZ=US/Eastern    go run clock2.go -port 8010 &
TZ=Asia/Tokyo    go run clock2.go -port 8020 &
TZ=Europe/London go run clock2.go -port 8030 &
#clockwall NewYork=localhost:8010 Tokyo=localhost:8020 London=localhost:8030

客户端clockwall

根据题意,客户端同时访问多个服务端,并将多个返回结果一并返回。我在看到这个题目的时候其实挺疑惑的,并不是很清楚作者的要求是什么,是将结果直接返回至终端(乱序),还是按端口顺序一一排列的整行输出。根据作者对时钟墙的举例,我倾向于一一排列的整行输出(看过网上的几个案例,都没有实现)。在思考一段时间之后,发现仅用8.2节之前的内容无法实现(本人无法实现😮‍💨),最后使用channels来实现。

package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"os"
	"strings"
	"time"
)

//var list [3]string

func main() {
	var chs = make([]chan string, 3)
	for i, url := range os.Args[1:] {
		chs[i] = make(chan string, 1)
		go connet(url, chs[i])
	}
	for {
		fmt.Println(<-chs[0], <-chs[1], <-chs[2])
	}
}

func connet(url string, ch chan string) {
	_, url, ok := strings.Cut(url, "=")
	if !ok {
		fmt.Println("url format error")
		return
	}
	conn, err := net.Dial("tcp", url)
	if err != nil {
		log.Fatal(err)
	}
	sc := bufio.NewScanner(conn)
	for sc.Scan() {
		s := sc.Text()
		ch <- s
	}
	time.Sleep(1 * time.Second)
	defer close(ch)
	defer conn.Close()
}

运行结果

clockwall

最近开始Go语言,记录一下学习过程,有一起学Go的小伙伴可以和我交流啊

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值