Golang-C1-10

作业

tcp讲解

ftp存储

file_client.go

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

import (
	"fmt"
	"log"
	"net"
)

func main() {
	conn, err := net.Dial("tcp", "127.0.0.1:8021")
	if err != nil {
		log.Fatal(err)
	}

	conn.Write([]byte("GET /home/bingan/a.txt\n"))
	buf := make([]byte, 1024)
	n, _ := conn.Read(buf)
	fmt.Println(buf[:n])
}

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
83
package main

import (
	"bufio"
	"flag"
	"io"
	"log"
	"net"
	"os"
	"path/filepath"
	"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

// 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()
		io.Copy(conn, f)
	} else if cmd == "STORE" {
		// 创建name文件
		// io.Copy
		// 关闭连接和文件
		os.MkdirAll(filepath.Dir(name), 0755)
		f, err := os.Create(name)
		if err != nil {
			log.Print(err)
			return
		}
		io.Copy(f, r)
		f.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_server1.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
package main

import (
	"bufio"
	"flag"
	"log"
	"net"
)

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) {
	r := bufio.NewReader(conn)
	line, err := r.ReadString('\n')

	var content []byte
	// 读取文件内容到content

	conn.Write(content)
}

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
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
package main

import (
	"bufio"
	"fmt"
	"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) {
	_, ok := r.users[user]
	if ok {
		r.Leave(user)
	}
	r.users[user] = conn
}

func (r *Room) Leave(user string) {
	// 关闭连接
	// users里面删掉
	conn, ok := r.users[user]
	if !ok {
		return
	}
	conn.Close()
	delete(r.users, user)
}

func (r *Room) Broadcast(who string, msg string) {
	// 遍历所有的用户,发送消息
	tosend := fmt.Sprintf("%s:%s\n", who, msg)
	for user, conn := range r.users {
		if user == who {
			continue
		}
		log.Print(user)
		conn.Write([]byte(tosend))
	}
}

// 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
	}

	globalRoom.Join(user, conn)
	globalRoom.Broadcast("system", fmt.Sprintf("%s join room", user))
	for {
		// 获取用户输入
		line, err := r.ReadString('\n')
		if err != nil {
			break
		}
		line = strings.TrimSpace(line)
		// broadcast
		globalRoom.Broadcast(user, line)
	}

	globalRoom.Broadcast("system", fmt.Sprintf("%s leave room", user))
	globalRoom.Leave(user)
}

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)
	}
}

代理

proxy.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
package main

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

var (
	target = flag.String("target", "www.baidu.com:80", "target host")
)

func handleConn(conn net.Conn) {
	// 建立到目标服务器的连接
	var remote net.Conn
	var err error
	remote, err = net.Dial("tcp", *target)
	if err != nil {
		log.Print(err)
		conn.Close()
		return
	}

	wg := new(sync.WaitGroup)
	wg.Add(2)
	// go 读取(conn)的数据,发送到remote,直到conn的EOF, 关闭remote
	go func() {
		defer wg.Done()
		io.Copy(remote, conn)
		remote.Close()
	}()
	// go 读取remote的数据,发送到客户端(conn),直到remote的EOF,关闭conn
	go func() {
		defer wg.Done()
		io.Copy(conn, remote)
		conn.Close()
	}()

	// 等待两个协程结束
	wg.Wait()
}

func main() {
	flag.Parse()

	l, err := net.Listen("tcp", ":8021")
	if err != nil {
		log.Fatal(err)
	}

	for {
		conn, _ := l.Accept()
		go handleConn(conn)
	}
}

proxy.go.log

 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
package main

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

var (
	target = flag.String("target", "www.baidu.com:80", "target host")
)

func handleConn(conn net.Conn) {
	// 建立到目标服务器的连接
	var remote net.Conn
	var err error
	remote, err = net.Dial("tcp", *target)
	if err != nil {
		log.Print(err)
		conn.Close()
		return
	}

	wg := new(sync.WaitGroup)
	wg.Add(2)
	// go 读取(conn)的数据,发送到remote,直到conn的EOF, 关闭remote
	go func() {
		defer wg.Done()
		io.Copy(remote, conn)
		remote.Close()
	}()
	// go 读取remote的数据,发送到客户端(conn),直到remote的EOF,关闭conn
	go func() {
		defer wg.Done()
		io.Copy(conn, remote)
		conn.Close()
	}()

	// 等待两个协程结束
	wg.Wait()
}

func main() {
	flag.Parse()

	l, err := net.Listen("tcp", ":8021")
	if err != nil {
		log.Fatal(err)
	}

	for {
		conn, _ := l.Accept()
		go handleConn(conn)
	}
}

socks

socks5.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
91
92
93
94
95
96
package main

import (
	"bufio"
	"encoding/binary"
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
)

// 1.握手
// 2.获取客户端代理的请求
// 3.开始代理

func readAddr(r *bufio.Reader) (string, error) {
	version, _ := r.ReadByte()
	log.Printf("version:%d", version)
	if version != 5 {
		return "", errors.New("bad version")
	}
	cmd, _ := r.ReadByte()
	log.Printf("cmd:%d", cmd)

	if cmd != 1 {
		return "", errors.New("bad cmd")
	}

	// skip rsv字段
	r.ReadByte()

	addrtype, _ := r.ReadByte()
	log.Printf("addr type:%d", addrtype)
	if addrtype != 3 {
		return "", errors.New("bad addr type")
	}

	// 读取一个字节的数据,代表后面紧跟着的域名的长度
	// 读取n个字节得到域名,n根据上一步得到的结果来决定
	addrlen, _ := r.ReadByte()
	addr := make([]byte, addrlen)
	io.ReadFull(r, addr)
	log.Printf("addr:%s", addr)

	var port int16
	binary.Read(r, binary.BigEndian, &port)

	return fmt.Sprintf("%s:%d", addr, port), nil
}

func handshake(r *bufio.Reader, conn net.Conn) error {
	version, _ := r.ReadByte()
	log.Printf("version:%d", version)
	if version != 5 {
		return errors.New("bad version")
	}
	nmethods, _ := r.ReadByte()
	log.Printf("nmethods:%d", nmethods)

	buf := make([]byte, nmethods)
	io.ReadFull(r, buf)
	log.Printf("%v", buf)

	resp := []byte{5, 0}
	conn.Write(resp)
	return nil
}

func handleConn(conn net.Conn) {
	defer conn.Close()
	r := bufio.NewReader(conn)

	handshake(r, conn)
	addr, _ := readAddr(r)
	log.Printf("addr:%s", addr)
	resp := []byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
	conn.Write(resp)

	// 开始代理
}

func main() {
	flag.Parse()

	l, err := net.Listen("tcp", ":8022")
	if err != nil {
		log.Fatal(err)
	}

	for {
		conn, _ := l.Accept()
		go handleConn(conn)
	}
}

rc4加密

rc4.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
package main

import (
	"crypto/md5"
	"crypto/rc4"
	"flag"
	"io"
	"log"
	"os"
)

var (
	key = flag.String("k", "", "secret key")
)

func crypto(w io.Writer, r io.Reader, key string) {
	// 创建cipher
	md5sum := md5.Sum([]byte(key))
	cipher, err := rc4.NewCipher(md5sum[:])
	if err != nil {
		log.Fatal(err)
	}
	buf := make([]byte, 4096)
	for {
		// r里面读取数据到buf
		n, err := r.Read(buf)
		if err == io.EOF {
			break
		}
		// 加密buf
		cipher.XORKeyStream(buf[:n], buf[:n])
		// buf写入到w里面
		w.Write(buf[:n])
	}
}

func main() {
	flag.Parse()
	crypto(os.Stdout, os.Stdin, *key)
}

总结

homework