day10协程 练习8.1

master
独孤伶俜 2022-12-22 11:01:23 +08:00
parent c77a5ee483
commit 29620426c2
3 changed files with 177 additions and 0 deletions

View File

@ -0,0 +1,94 @@
package main
import (
"fmt"
"io"
"log"
"net"
"os"
"strings"
"sync"
"time"
)
// 定义一个*data类型切片
var dSlice []*data
func main() {
// 1. 从控制台读取要记录的时区服务器地址
// 2. 启动一个goroutine每隔一秒钟向服务器发送一个请求获取当前时间
// 3. 将服务器返回的时间输出到控制台
var wg sync.WaitGroup
wg.Add(len(os.Args[1:]))
// 获取服务器地址
// Tokyo=localhost:8020 London=localhost:8030
var server = make(map[int][]string)
for i, v := range os.Args[1:] {
// 处理输入
server[i] = strings.Split(v, "=")
}
// 启动时钟
for i, server := range server {
// 创建一个data类型的指针
dSlice = append(dSlice, new(data))
// 启动时钟
go clock(server[1], dSlice[i], &wg)
}
// 输出
// $ go run 8.1.go China=localhost:8000 Tokyo=localhost:8010
//====================================
//Tokyo localhost:8010 13:55:32
//China localhost:8000 12:55:32
// 输出前等待1s, 保证数据已经接收到并且写入到data类型的指针中
time.Sleep(1 * time.Second)
for {
fmt.Println("====================================")
for i, s := range server {
go output(s, dSlice[i])
}
time.Sleep(1 * time.Second)
}
// 尽管上面的死循环会阻塞主协程
// 但是还是写上吧
// 调试也方便
wg.Wait()
}
func output(ser []string, data *data) {
fmt.Println(ser[0], ser[1], data)
}
// data 类型
type data string
// 输出*data的时候直接输出解引用data的值
func (d *data) String() string {
return string(*d)
}
// 实现Writer接口, 用于将数据写入到data类型的指针中
func (d *data) Write(p []byte) (n int, err error) {
// 写入数据
*d = data(p)
//fmt.Println(d)
return len(p), nil
}
// 编写监听多个服务器的时钟函数
func clock(server string, data *data, wg *sync.WaitGroup) {
defer wg.Done()
//fmt.Println(server)
conn, err := net.Dial("tcp", server)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
mustCopy(data, conn)
}
func mustCopy(dst io.Writer, src io.Reader) {
if _, err := io.Copy(dst, src); err != nil {
log.Fatalln(err)
}
}

View File

@ -0,0 +1,57 @@
package main
import (
"flag"
"fmt"
"io"
"log"
"net"
"time"
)
// go run exampleClock.go -p 8010 -loc Asia/Tokyo
func main() {
// 设置flag
locstr := flag.String("loc", "Asia/Shanghai", "请输入完整的时区名称")
listenstr := flag.String("p", "8000", "请输入监听端口")
flag.Parse()
// 设置时区
loc, err := time.LoadLocation(*locstr)
if err != nil {
log.Fatal(err)
}
// 监听8000端口
listener, err := net.Listen("tcp", ":"+*listenstr)
if err != nil {
log.Fatal(err)
}
for {
conn, err := listener.Accept()
if err != nil {
log.Print(err) // e.g., connection aborted
continue
}
//handleConn(conn) // handle one connection at a time
// 在调用handleConn时加上go关键字就可以同时处理多个客户端连接
go handleConn(conn, loc) // handle connections concurrently
}
}
var num = 0
func handleConn(c net.Conn, loc *time.Location) {
num++
defer c.Close()
fmt.Println("handleConn", num)
for {
_, err := io.WriteString(c, time.Now().In(loc).Format("15:04:05"))
if err != nil {
return // e.g., client disconnected
}
time.Sleep(1 * time.Second)
}
}

View File

@ -0,0 +1,26 @@
// Netcat1 is a read-only TCP client.
package main
import (
"io"
"log"
"net"
"os"
)
func main() {
// 连接到8000端口
conn, err := net.Dial("tcp", "localhost:8000")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
// 从标准输入读取数据
mustCopy(os.Stdout, conn)
}
func mustCopy(dst io.Writer, src io.Reader) {
if _, err := io.Copy(dst, src); err != nil {
log.Fatal(err)
}
}