作业点评
完善http.go和c10k.go
要求:
编译通过
编译成windows,linux和mac三个平台的文件,有条件的可以运行观察结果。二进制不用提交。
分析课堂上的代码,说明原因
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func main () {
var x int
var y int
x = 1
y = 1
swap ( & x , & y )
fmt . Println ( "x=" , x , "y=" , y )
}
func swap ( p * int , q * int ) {
var t int
t = * p
* p =* q
* q = t
}
参考分析
https://github.com/51reboot/golang-01-homework/blob/master/lesson1/CHECK.md
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 "fmt"
func main () {
var x int
x = 1 // 把 1 赋给变量 x
var y int
y = 2 // 把 2 赋给变量 y
swap ( & x , & y ) // 把 x和y的内存地址作为参数传给swap函数
fmt . Println ( x , y )
}
func swap ( p * int , q * int ) {
// 指针变量 p里面存的是变量x的内存地址 ,指针变量 q存的是y的内存地址
var t = * p
// p里面存的是x的内存地址 , * p是取指针指向的内容 , * p也就是变量x里面存的值1 , 1 赋给 t
* p = * q
// q里面存的y的内存地址 , * q是变量y里面存的值2 ,把 2 赋值给 x变量里面的值 , x里面的值变成了2
* q = t
// 变量 t里面存的值是1 , 1 赋给了 y里面的值 , y的值变成了1
// 最终结果, x是2 , y是1
}
https://github.com/cnjllin/golang-01-homework/blob/master/lesson1/wujianjian/pointer.png
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
mulinux@WIN-MANAGER:~$ python
Python 2.7.6 (default, Oct 26 2016, 20:30:19)
[GCC 4.8.4] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 1
>>> b = 1
>>> id(a)
16445784
>>> id(b)
16445784
>>> a="hello"
>>> for i in range(10):
... print i
...
0
1
2
3
4
5
6
7
8
9
学员博客
www.cnblogs.com/yinzhengjie/p/6482675.html
指针解析
&符号的意思是对变量取地址,如:变量a的地址是&a
*符号的意思是对指针取值,如:*&a,就是a变量所在地址的值,当然也就是a的值了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main
import "fmt"
func main () {
var x int
x = 1 // 把 1 赋给变量 x
var y int
y = 2 // 把 2 赋给变量 y
swap ( & x , & y ) // 把 x和y的内存地址作为参数传给swap函数
fmt . Println ( x , y )
}
func swap ( p * int , q * int ) {
// 指针变量 p里面存的是变量x的内存地址 ,指针变量 q存的是y的内存地址
var t = * p
// p里面存的是x的内存地址 , * p是取指针指向的内容 , * p也就是变量x里面存的值1 , 1 赋给 t
* p = * q
// q里面存的y的内存地址 , * q是变量y里面存的值2 ,把 2 赋值给 x变量里面的值
, x里面的值变成了2
* q = t
// 变量 t里面存的值是1 , 1 赋给了 y里面的值 , y的值变成了1
// 最终结果, x是2 , y是1
}
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
package main
import "fmt"
func main () {
var x int
x = 1
var y int
y = 2
fmt . Println ( x , y )
// x和y的初始化指针
fmt . Println ( & x , & y )
swap ( & x , & y )
fmt . Println ( x , y )
// x和y的值对调后
fmt . Println ( & x , & y )
swap_a ( & x , & y )
// x和y的指针对调后
fmt . Println ( & x , & y )
fmt . Println ( x , y )
}
//
// 将 x和y的值对调
func swap ( p * int , q * int ) {
var t = * p
* p = * q
* q = t
}
// x和y的指针对调 ,值不变
func swap_a ( p * int , q * int ) {
var t = p
p = q
q = t
}
package
go程序的结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main
import (
"fmt"
"os"
)
func main () {
var s , sep string
for i : = 1 ; i < len ( os . Args ); i ++ {
s += sep + os . Args [ i ]
sep = " "
}
fmt . Println ( s )
}
go通过package组织
package关键字
放在程序的第一行
两种package,一种是库package,一种是二进制package
二进制package使用main来表示,库package的名字跟go文件所在的目录名一样
二进制package
以package main作为文件的第一行
有且只有一个main函数,如echo.go所表示
引入package
通过关键字import来引入其他package
多个package可以用括号包含起来
引入但没有使用的package会引起编译错误
thirdlib/main.go
1
2
3
4
5
6
7
8
9
10
package main
import (
"fmt"
"github.com/icexin/golib"
)
func main () {
fmt . Println ( golib . Add ( 1 , 2 ))
}
查看包函数方式
https://godoc.org/fmt
https://godoc.org/github.com/go-redis/redis
go doc
1
2
3
go install golang . org / x / tools / cmd / godoc
godoc - http = : 9000
访问: ip : port / pkg / github . com / mulinux / golib /
faq
go run 跟go build或go install区别
在myecho目录下go install出错,提示no install location for directory GOPATH
go install 成功,但执行myecho出错
变量声明和指针
main函数
二进制程序的入口
main函数结束了整个程序就结束了
整个main package只能有一个
代码风格
所有的代码只有一种,gofmt的风格
gofmt不是任何人的风格,但所有人都喜欢gofmt的风格
使用gofmt -w xx.go来格式化代码
变量:godoc_ip:port/pkg/os/#pkg-variables
练习:编写cat命令
cat辅助函数
1
2
3
4
5
6
7
8
func printFile ( name string ) {
buf , err : = ioutil . ReadFile ( name )
if err != nil {
fmt . Println ( err )
return
}
fmt . Println ( string ( buf ))
}
变量声明
1
2
3
4
5
6
7
8
var x int
var y string = "hello"
var x , y int
var (
x int
y int
z string
)
零值初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main
import "fmt"
func main () {
var (
x int
y float32
z string
p * int
)
fmt . Printf ( "%v \n " , x )
fmt . Printf ( "%v \n " , y )
fmt . Printf ( "%v \n " , z )
fmt . Printf ( "%v \n " , p )
}
短变量
1
2
3
i := 0 //int
s := "hello" //string
i, j := 0, 1 //批量初始化
指针
*T即为类型T的指针
&t即为去变量t的地址
*p即为取指针变量所指向的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
package main
import "fmt"
func main () {
var x int
var p * int
fmt . Println ( "&x=" , & x )
p = & x
fmt . Println ( "p=" , p )
fmt . Println ( "*p=" , * p )
}
命令行参数
args.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main
import (
"fmt"
"os"
)
func main () {
var s , sep string
for i : = 1 ; i < len ( os . Args ); i ++ {
s += sep + os . Args [ i ]
sep = " "
}
fmt . Println ( s )
}
echo.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main
import (
"fmt"
"os"
)
var i int
func main () {
var s , sep string
// var i int
for i : = 1 ; i < len ( os . Args ); i ++ {
s += sep + os . Args [ i ]
sep = " "
}
if true {
i : = 4
fmt . Println ( i )
}
fmt . Println ( s )
}
echo2.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main
import (
"flag"
"fmt"
"strings"
)
var sep = flag . String ( "s" , " " , "separator" )
var newline = flag . Bool ( "n" , false , "append newline" )
func main () {
flag . Parse ()
fmt . Print ( strings . Join ( flag . Args (), * sep ))
if * newline {
fmt . Println ()
}
}
程序分享
spider.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 (
"container/list"
"errors"
"fmt"
"net/http"
"net/url"
"os"
"strings"
"github.com/PuerkitoBio/goquery"
)
func isurlok ( uri * url . URL ) bool {
if strings . HasPrefix ( uri . Hostname (), "www.zhihu.com" ) {
return true
}
return false
}
func fetch ( target string ) ([] string , string , error ) {
uri , err : = url . Parse ( target )
if err != nil {
return nil , "" , err
}
if ! isurlok ( uri ) {
return nil , "" , errors . New ( "skip " + target )
}
resp , err : = http . Get ( target )
if err != nil {
return nil , "" , err
}
defer resp . Body . Close ()
doc , err : = goquery . NewDocumentFromResponse ( resp )
if err != nil {
return nil , "" , err
}
var urls [] string
doc . Find ( "a" ) . Each ( func ( i int , s * goquery . Selection ) {
link , ok : = s . Attr ( "href" )
if ! ok {
return
}
if len ( link ) > 0 && link [ 0 ] == '/' {
u : = uri
u . Path = link
u . RawQuery = ""
u . Fragment = ""
urls = append ( urls , u . String ())
} else {
urls = append ( urls , link )
}
})
body , err : = doc . Html ()
if err != nil {
return urls , "" , nil
}
return urls , body , nil
}
func main () {
root : = os . Args [ 1 ]
visited : = make ( map [ string ] bool )
l : = list . New ()
l . PushBack ( root )
for l . Len () != 0 {
front : = l . Front ()
l . Remove ( front )
url : = front . Value . ( string )
if visited [ url ] {
continue
}
visited [ url ] = true
urls , body , err : = fetch ( url )
if err != nil {
// log . Print ( err )
continue
}
fmt . Printf ( " %s %0.2f k \n " , url , float32 ( len ( body )) / 1024.0 )
for _ , url : = range urls {
l . PushBack ( url )
}
}
}
spider.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
package main
import (
"github.com/PuerkitoBio/goquery" // 解析 html
"os"
"container/list"
"github.com/gogather/com/log"
"fmt"
"strings"
"net/url"
"net/http"
"errors"
)
func isurlok ( uri * url . URL , prefix string ) bool {
if strings . HasPrefix ( uri . Hostname (), prefix ) {
return true
}
return false
}
func fetch ( target , prefix string ) ([] string , string , error ) {
uri , err : = url . Parse ( target )
if err != nil {
return nil , "" , err
}
if ! isurlok ( uri , prefix ) {
return nil , "" , errors . New ( "skip " + target )
}
resp , err : = http . Get ( target )
if err != nil {
return nil , "" , err
}
defer resp . Body . Close ()
doc , err : = goquery . NewDocumentFromResponse ( resp )
if err != nil {
return nil , "" , err
}
var urls [] string
doc . Find ( "a" ) . Each ( func ( i int , s * goquery . Selection ) {
link , ok : = s . Attr ( "href" )
if ! ok {
return
}
if len ( link ) > 0 && link [ 0 ] == '/' {
u : = uri
u . Path = link
u . RawQuery = ""
u . Fragment = ""
urls = append ( urls , u . String ())
} else {
urls = append ( urls , link )
}
})
body , err : = doc . Html ()
if err != nil {
return urls , "" , nil
}
return urls , body , nil
}
func main () {
// 广度优先搜索
// 爬到一个网页后,爬该页面的所有的子链接。优先搜索本站,再搜索外站。大部分使用广度优先。
webroot : = os . Args [ 1 ]
prefix : = os . Args [ 2 ]
visited : = make ( map [ string ] bool )
// 创建一个双向链表
lst : = list . New ()
lst . PushBack ( webroot )
for lst . Len () != 0 {
front : = lst . Front ()
lst . Remove ( front )
url : = front . Value . ( string )
if visited [ url ]{
continue
}
visited [ url ] = true
urls , body , err : = fetch ( url , prefix )
if err != nil {
log . Println ( err )
continue
}
fmt . Printf ( " %s %0.2f k \n " , url , float32 ( len ( body )) / 1024.0 )
for _ , url : = range urls {
lst . PushBack ( url )
}
}
}
编译好的可执行程序: https : // download . csdn . net / download / mypc2010 / 10407523
用法: spider . exe http : // www . jd . com jd . com
拓展阅读: https : // www . zhihu . com / question / 23011311
gotty
https://github.com/yudai/gotty
1
2
3
tar zxf gotty_linux_amd64.tar.gz
./gotty -w bash
./gotty -p 8090 -w bash
https://github.com/ghantoos/lshell
1
2
lshell
./gotty -p 8090 -w lshell
1
2
go get github.com/icexin/markdown
markdown -server -addr=:9091
gossh
说明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 百行代码实现的ssh客户端和服务端
## 编译
`go get github.com/cnjllin/golang-01-homework/lesson2/binggan/gossh`
**提示**:需要翻墙
## 使用
服务端:
`gossh -addr=:8080 -s`
客户端:
`gossh -addr=:8080`
或者:
`nc 127.0.0.1 8080`
**注意**:nc作为客户端top,vi之类的命令不能用
## 致有志于hack的同学
- 增加只读功能
- 增加替换shell程序的功能
gossh.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
package main
import (
"flag"
"io"
"log"
"net"
"os"
"os/exec"
"golang.org/x/crypto/ssh/terminal"
"github.com/kr/pty"
)
var (
addr = flag . String ( "addr" , ":8080" , "address" )
isserver = flag . Bool ( "s" , false , "run as server" )
)
func handle ( conn net . Conn ) {
defer conn . Close ()
log . Printf ( "[login] %s " , conn . RemoteAddr ())
cmd : = exec . Command ( "bash" )
tty , err : = pty . Start ( cmd )
if err != nil {
log . Print ( err )
return
}
go io . Copy ( tty , conn )
go io . Copy ( conn , tty )
cmd . Wait ()
log . Printf ( "[logout] %s " , conn . RemoteAddr ())
}
func server () {
l , err : = net . Listen ( "tcp" , * addr )
if err != nil {
log . Fatal ( err )
}
for {
conn , err : = l . Accept ()
if err != nil {
log . Fatal ( err )
}
go handle ( conn )
}
}
func client () {
conn , err : = net . Dial ( "tcp" , * addr )
if err != nil {
log . Fatal ( err )
}
defer conn . Close ()
oldState , err : = terminal . MakeRaw ( 0 )
if err != nil {
panic ( err )
}
defer terminal . Restore ( 0 , oldState )
go io . Copy ( conn , os . Stdin )
io . Copy ( os . Stdout , conn )
}
func main () {
flag . Parse ()
if * isserver {
server ()
return
}
client ()
}
使用
1
2
sockget go get -v
gossh -addr=127.0.0.1:8080
homework
完成mycat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main
import (
"fmt"
"io/ioutil"
)
func printFile ( name string ) {
buf , err := ioutil . ReadFile ( name )
if err != nil {
fmt . Println ( err )
return
}
fmt . Println ( string ( buf ))
}
func main () {
// 补全缺失的代码完成cat命令
}
要求:
提示:
使用os.Args获取命令行参数,具体代码参照myecho
判断如下程序的输出,并说明原因
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 "fmt"
var x = 200
func localFunc () {
fmt . Println ( x )
}
func main () {
x := 1
localFunc ()
fmt . Println ( x )
if true {
x := 100
fmt . Println ( x )
}
localFunc ()
fmt . Println ( x )
}