Golang-C1-9

作业

buf.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
)

func main() {
	f, err := os.Open("a.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	r := bufio.NewReaderSize(f, 10)
	line, _ := r.ReadString('\n')
	fmt.Print(line)

	io.Copy(os.Stdout, f)
}

协程

协程池

pool.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import (
	"log"
	"net/http"
	"sync"
)

func work(ch chan string, wg *sync.WaitGroup) {
	for u := range ch {
		resp, err := http.Get(u)
		if err != nil {
			log.Print(err)
			return
		}
		log.Printf("%s:%s", u, resp.Status)
		resp.Body.Close()
	}
	wg.Done()
}

func main() {
	wg := new(sync.WaitGroup)
	wg.Add(5)
	taskch := make(chan string)
	for i := 0; i < 5; i++ {
		go work(taskch, wg)
	}

	urls := []string{"http://www.baidu.com", "http://www.zhihu.com"}
	for _, url := range urls {
		taskch <- url
	}
	close(taskch)
	wg.Wait()
}

pool_step.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package main

import (
	"fmt"
	"log"
	"net/http"
	"sync"
)

// 给定一个url打印url和url的status
// www.baidu.com 200 OK
func printUrl(url string) {
	resp, err := http.Get(url)
	if err != nil {
		log.Print(err)
		return
	}
	defer resp.Body.Close()
	fmt.Println(url, resp.Status)
}

func work(ch chan string, wg *sync.WaitGroup) {
	defer wg.Done()
	for url := range ch {
		printUrl(url)
	}

	// 等价于
	for {
		url, ok := <-ch
		if !ok {
			break
		}
		printUrl(url)
	}
}

// 1. 只要不close可以永远发送数据和接受数据
// 2. 如果channel里面没有数据,接收方会阻塞
// 3. 如果没有人正在等待channel的数据,发送方会阻塞
// 4. 从一个close的channle取数据永远不会阻塞,同时获取的是默认值

// 主协程启动一个work协程,同时传递一个channel
// 主协程向channel里面发送一个url
// work协程从channel里面获取url,之后调用printUrl打印url

// 启动3个协程
// 主协程向channel里面发送多个url,发送完毕之后关闭channel
// work协程从channel里面获取url,之后调用printUrl打印url
// work协程不停重复第三条,直到channel关闭

// 创建一个WaitGroup
// 调用Add
// 调用Wait等待work协程结束
func main() {
	ch := make(chan string)
	wg := new(sync.WaitGroup)
	//wg.Add(3)
	for i := 0; i < 3; i++ {
		wg.Add(1)
		go work(ch, wg)
	}

	for i := 0; i < 5; i++ {
		url := "http://www.baidu.com"
		ch <- url
	}
	close(ch)

	wg.Wait()
}

客户端

client.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

import (
	"fmt"
	"io"
	"log"
	"net"
	"os"
)

func main() {
	addr := "www.baidu.com:80"
	// connection
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(conn.RemoteAddr().String())
	fmt.Println(conn.LocalAddr().String())
	n, err := conn.Write([]byte("GET / HTTP/1.1\r\n\r\n"))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("write size", n)

	// buf := make([]byte, 10)
	// n, err = conn.Read(buf)
	// if err != nil && err != io.EOF {
	// 	log.Fatal(err)
	// }
	// fmt.Println(string(buf[:n]))
	io.Copy(os.Stdout, conn)
	conn.Close()
}

服务端

server.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package main

import (
	"log"
	"net"
)

var content = `HTTP/1.1 200 OK
Date: Sat, 29 Jul 2017 06:18:23 GMT
Content-Type: text/html
Connection: Keep-Alive
Server: BWS/1.1
X-UA-Compatible: IE=Edge,chrome=1
BDPAGETYPE: 3
Set-Cookie: BDSVRTM=0; path=/

<html>
<body>
<h1 style="color:red">hello golang</h1>
</body>
</html>
`

func handleConn(conn net.Conn) {
	conn.Write([]byte(content))
	conn.Close()
}

func main() {
	addr := ":8021"
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal(err)
	}
	defer listener.Close()

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal(err)
		}

		go handleConn(conn)
	}
}

文件服务

file_server.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package main

import (
	"bufio"
	"flag"
	"io/ioutil"
	"log"
	"net"
	"os"
	"strings"
)

var (
	root = flag.String("root", "/", "root of ftp server data dir")
)

// client -> GET /home/binggan/a.txt\n
// server -> content of /home/bingan/a.txt

// client -> STORE /home/bingan/a.txt\n content of file EOF
// server -> OK

// client -> LS /home/bingan\n
// server -> content of dir /home/bingan

func handleConn(conn net.Conn) {
	// conn里面读取一行内容
	// 按空格分割指令和文件名
	// 打开文件
	// 读取内容
	// 发送内容
	// 关闭连接和文件
	defer conn.Close()
	r := bufio.NewReader(conn)
	line, _ := r.ReadString('\n')
	line = strings.TrimSpace(line)
	fields := strings.Fields(line)
	if len(fields) != 2 {
		conn.Write([]byte("bad input"))
		return
	}
	cmd := fields[0]
	name := fields[1]
	if cmd == "GET" {
		f, err := os.Open(name)
		if err != nil {
			log.Print(err)
			return
		}
		defer f.Close()
		buf, err := ioutil.ReadAll(f)
		if err != nil {
			log.Print(err)
			return
		}
		conn.Write(buf)
	} else if cmd == "STORE" {
		// r读取文件内容直到err为io.EOF
		// 创建name文件
		// 向文件写入数据
		// conn写入OK
		// 关闭连接和文件
	}
}

func main() {
	addr := ":8021"
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal(err)
	}
	defer listener.Close()

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal(err)
		}

		go handleConn(conn)
	}
}

聊天服务

chat_server.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package main

import (
	"bufio"
	"log"
	"net"
	"strings"
)

var globalRoom *Room = NewRoom()

type Room struct {
	users map[string]net.Conn
}

func NewRoom() *Room {
	return &Room{
		users: make(map[string]net.Conn),
	}
}

func (r *Room) Join(user string, conn net.Conn) {
	conn, ok := r.users[user]
	if ok {
		r.Leave(user)
	}
	r.users[user] = conn
}

func (r *Room) Leave(user string) {
	// 关闭连接
	// users里面删掉
}

func (r *Room) Broadcast(user string, msg string) {
	// 遍历所有的用户,发送消息
}

// client -> binggan 123456
// client -> hello golang
// client -> close

// 接收新的连接
// 验证用户的账号和密码
// 等待用户输入
// 向所有在线的用户广播用户的输入
func handleConn(conn net.Conn) {
	defer conn.Close()
	r := bufio.NewReader(conn)
	line, _ := r.ReadString('\n')
	line = strings.TrimSpace(line)
	fields := strings.Fields(line)
	if len(fields) != 2 {
		conn.Write([]byte("bad input"))
		return

	}
	user := fields[0]
	password := fields[1]
	if password != "123456" {
		return
	}

	// join用户

	for {
		// 获取用户输入
		// broadcast
	}

	// leave用户
}

func main() {
	addr := ":8021"
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal(err)
	}
	defer listener.Close()

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal(err)
		}

		go handleConn(conn)
	}
}

总结

homework