Submitted by admin on 2017, April 20, 10:34 PM
http://www.cnblogs.com/anpengapple/p/5879363.html
http://blog.csdn.net/zhu_tianwei/article/details/45075577
用 BIND 搭建高可用性 DNSSEC 仅权威服务器
https://www.v2ex.com/t/143009
dns | 评论:0
| Trackbacks:0
| 阅读:420
Submitted by admin on 2017, April 17, 6:31 PM
解决办法:
因为这台虚拟机是通过克隆而来,MAC地址和源虚拟机一样,因此需要修改MAC地址
步骤如下:
1.vi /etc/sysconfig/network-scripts/ifcfg-eth0
将HWADDR修改为:

2.删除 /etc/udev/rules.d/70-persistent-net.rules 然后重启
rm /etc/udev/rules.d/70-persistent-net.rules
reboot
-------------
cat /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE="eth1"
BOOTPROTO="static"
linux | 评论:0
| Trackbacks:0
| 阅读:418
Submitted by admin on 2017, April 12, 10:05 PM
接下来我们详细叙述一下能让nginx支持多域名证书的过程,主要分为如下两个大步骤:编译安装openssl和编译安装nginx(nginx平滑升级,不影响业务)。
一、编译安装openssl
wget http://www.openssl.org/source/openssl-0.9.8l.tar.gz
tar zxvf ./openssl-0.9.8l.tar.gz
cd ./openssl-0.9.8l
#编译的时候需要加上enable-tl***t参数
./config enable-tl***t
make
make install
二、编译安装nginx(nginx平滑升级)
tar xzvf nginx-1.0.12.tar.gz
cd nginx-1.0.12
#备份原来的nginx配置
mv /usr/local/nginx /usr/local/nginx_old
#安装nginx
./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_gzip_static_module --with-http_stub_status_module --with-openssl=../openssl-0.9.8l/
make;make install
cd /usr/local/nginx
#备份新安装的配置目录
mv conf conf_bak
mv logs logs_bak
#拷贝原来的配置文件目录
cp -ar /usr/local/nginx_old/conf .
cp -ar /usr/local/nginx_old/logs .
#测试配置文件
/usr/local/nginx/sbin/nginx -t
#查找nginx主进程
ps -ef | grep "nginx: master process" | grep -v "grep" | awk -F ' ' '{print $2}'
#执行切换操作
kill -USR2 912
kill -WINCH 912
kill -QUIT 912
安装完成使用/usr/local/nginx/sbin/nginx -V查看一下是否支持TLS SNI,检测如下:
nginx version: nginx/1.0.12
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --with-http_ssl_module --with-http_gzip_static_module --with-http_stub_status_module --with-openssl=../openssl-0.9.8l/
Ok,显示已经支持了TLS SNI,在输入https访问,终于能显示正确的证书了! 注意目前如果使用xp上的IE去访问的话还是会提示证书有问题,因为xp上任何版本的IE都不支持TLS SNI。
这里说下Linux 系统怎么通过openssl命令生成 证书。
首先执行如下命令生成一个key
openssl genrsa -des3 -out ssl.key 1024
然后他会要求你输入这个key文件的密码。不推荐输入。因为以后要给nginx使用。每次reload nginx配置时候都要你验证这个PAM密码的。
由于生成时候必须输入密码。你可以输入后 再删掉。
mv ssl.key xxx.key
openssl rsa -in xxx.key -out ssl.key
rm xxx.key
然后根据这个key文件生成证书请求文件
openssl req -new -key ssl.key -out ssl.csr
以上命令生成时候要填很多东西 一个个看着写吧(可以随便,毕竟这是自己生成的证书)
最后根据这2个文件生成crt证书文件
openssl x509 -req -days 365 -in ssl.csr -signkey ssl.key -out ssl.crt
这里365是证书有效期 推荐3650哈哈。这个大家随意。最后使用到的文件是key和crt文件。
如果需要用pfx 可以用以下命令生成
openssl pkcs12 -export -inkey ssl.key -in ssl.crt -out ssl.pfx
在需要使用证书的nginx配置文件的server节点里加入以下配置就可以了。
ssl on;
ssl_certificate /home/ssl.crt;
ssl_certificate_key /home/ssl.key;
ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
然后重启nginx就大功告成了
nginx | 评论:0
| Trackbacks:0
| 阅读:454
Submitted by admin on 2017, April 12, 2:54 PM
//var url = "http://www.test.net/install.html";
var url = "http://www.test.net/t.php";
var param = "name=david&age=30";
var obj = new ActiveXObject("WinHttp.WinHttpRequest.5.1");
obj.Open("GET", url, false);
obj.Option(4) = 13056;
obj.Option(6) = false; //false可以不自动跳转,截取服务端返回的302状态。
obj.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
obj.setRequestHeader("Referer", "http://www.baidu.com");
obj.setRequestHeader("User-Agent","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322)");
//obj.setRequestHeader("REMOTE_ADDR","1.1.1.8");
//obj.setRequestHeader("CLIENT-IP","1.1.1.3");
obj.setRequestHeader("X-FORWARDED-FOR","1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.4,1.1.1.41.1.1.4");
//obj.setRequestHeader("HTTP_CLIENT_IP","1.1.1.5");
//obj.setRequestHeader("X-ClientIP","1.1.1.6");
//obj.setRequestHeader("HTTP_X_FORWARDED_FOR","1.1.1.7");
obj.setRequestHeader("REMOTE_ADDR","1.1.1.8");
obj.setRequestHeader("X-Real-IP","1.1.1.9");
obj.setRequestHeader("X-REAL-IP","1.1.1.11");
obj.Send(param);
WScript.Echo(obj.responseText);
js代码 | 评论:0
| Trackbacks:0
| 阅读:532
Submitted by admin on 2017, March 10, 11:41 AM
网站程序 | 评论:0
| Trackbacks:0
| 阅读:475
Submitted by admin on 2017, February 21, 11:49 PM
background-size
设置背景图片的大小,以长度值或百分比显示,还可以通过cover和contain来对图片进行伸缩。
语法:
background-size: auto | <长度值> | <百分比> | cover | contain
取值说明:
1、auto:默认值,不改变背景图片的原始高度和宽度;
2、<长度值>:成对出现如200px 50px,将背景图片宽高依次设置为前面两个值,当设置一个值时,将其作为图片宽度值来等比缩放;
3、<百分比>:0%~100%之间的任何值,将背景图片宽高依次设置为所在元素宽高乘以前面百分比得出的数值,当设置一个值时同上;
4、cover:顾名思义为覆盖,即将背景图片等比缩放以填满整个容器;
5、contain:容纳,即将背景图片等比缩放至某一边紧贴容器边缘为止。
提示:大家可以在右边的编辑窗口输入自己的代码尝试不同取值的效果。
杂七杂八 | 评论:0
| Trackbacks:0
| 阅读:456
Submitted by admin on 2017, February 18, 8:43 PM
- #!/bin/bash
-
- step=2 #间隔的秒数,不能大于60
-
- for (( i = 0; i < 60; i=(i+step) )); do
- echo "OK"
- sleep $step
- done
-
- exit 0
#!/bin/bash
step=3
for (( i = 0; i < 60; i=(i+step) )); do
id=`ps ax | grep ".php" | grep -v grep | awk -F" " '{print $1}'`
echo $id
if [ "$id"x = x ];then
echo "no"
else
sleep 1
nid=`ps ax | grep ".php" | grep -v grep | awk -F" " '{print $1}'`
if [ "$id" == "$nid" ];then
echo $nid
kill $id
fi
echo $id
fi
sleep $step
done
exit 0
linux | 评论:0
| Trackbacks:0
| 阅读:492
Submitted by admin on 2017, February 10, 4:29 PM
select
golang 的 select 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作。
在执行select语句的时候,运行时系统会自上而下地判断每个case中的发送或接收操作是否可以被立即执行【立即执行:意思是当前Goroutine不会因此操作而被阻塞,还需要依据通道的具体特性(缓存或非缓存)】
- 每个case语句里必须是一个IO操作
- 所有channel表达式都会被求值、所有被发送的表达式都会被求值
- 如果任意某个case可以进行,它就执行(其他被忽略)。
- 如果有多个case都可以运行,Select会随机公平地选出一个执行(其他不会执行)。
- 如果有default子句,case不满足条件时执行该语句。
- 如果没有default字句,select将阻塞,直到某个case可以运行;Go不会重新对channel或值进行求值。
select 语句用法
注意到 select 的代码形式和 switch 非常相似, 不过 select 的 case 里的操作语句只能是【IO 操作】 。
此示例里面 select 会一直等待等到某个 case 语句完成, 也就是等到成功从 ch1 或者 ch2 中读到数据,如果都不满足条件且存在default case, 那么default case会被执行。 则 select 语句结束。
示例:
package main import ( "fmt" ) func main(){ ch1 := make(chan int, 1) ch2 := make(chan int, 1) select { case e1 := <-ch1: fmt.Printf("1th case is selected. e1=%v",e1) case e2 := <-ch2: fmt.Printf("2th case is selected. e2=%v",e2) default: fmt.Println("default!.") } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
select分支选择规则
所有跟在case关键字右边的发送语句或接收语句中的通道表达式和元素表达式都会先被求值。无论它们所在的case是否有可能被选择都会这样。
求值顺序:自上而下、从左到右
示例:
package main import ( "fmt" ) var ch1 chan int var ch2 chan int var chs = []chan int{ch1, ch2} var numbers = []int{1,2,3,4,5} func main(){ select { case getChan(0) <- getNumber(2): fmt.Println("1th case is selected.") case getChan(1) <- getNumber(3): fmt.Println("2th case is selected.") default: fmt.Println("default!.") } } func getNumber(i int) int { fmt.Printf("numbers[%d]\n", i) return numbers[i] } func getChan(i int) chan int { fmt.Printf("chs[%d]\n", i) return chs[i] }
- 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
- 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
输出:
chs[0]
numbers[2]
chs[1]
numbers[3]
default!.
可以看出求值顺序。满足自上而下、自左而右这条规则。
随机执行case
如果同时有多个case满足条件,通过一个伪随机的算法决定哪一个case将会被执行。
示例:
package main import ( "fmt" ) func main(){ chanCap := 5 ch7 := make(chan int, chanCap) for i := 0; i < chanCap; i++ { select { case ch7 <- 1: case ch7 <- 2: case ch7 <- 3: } } for i := 0; i < chanCap; i++ { fmt.Printf("%v\n", <-ch7) } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
输出:(注:每次运行都会不一样)
3
3
2
3
1
一些惯用手法示例
示例一:单独启用一个Goroutine执行select,等待通道关闭后结束循环
package main import ( "fmt" "time" ) func main(){ ch11 := make(chan int, 1000) sign := make(chan int, 1) for i := 0; i < 1000; i++ { ch11 <- i } close(ch11) go func(){ var e int ok := true for{ select { case e,ok = <- ch11: if !ok { fmt.Println("End.") break } fmt.Printf("ch11 -> %d\n",e) } if !ok { sign <- 0 break } } }() <- sign }
- 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
- 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
ch11 -> 0
ch11 -> 1
…
ch11 -> 999
End.
示例二:加以改进,我们不想等到通道被关闭后再退出循环,利用一个辅助通道模拟出操作超时。
package main import ( "fmt" "time" ) func main(){ ch11 := make(chan int, 1000) sign := make(chan int, 1) for i := 0; i < 1000; i++ { ch11 <- i } close(ch11) timeout := make(chan bool,1) go func(){ time.Sleep(time.Millisecond) timeout <- false }() go func(){ var e int ok := true for{ select { case e,ok = <- ch11: if !ok { fmt.Println("End.") break } fmt.Printf("ch11 -> %d\n",e) case ok = <- timeout: fmt.Println("Timeout.") break } if !ok { sign <- 0 break } } }() <- sign }
- 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
- 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
ch11 -> 0
ch11 -> 1
…
ch11 -> 691
Timeout.
示例三:上面实现了单个操作的超时,但是那个超时触发器开始计时有点早。
package main import ( "fmt" "time" ) func main(){ ch11 := make(chan int, 1000) sign := make(chan int, 1) for i := 0; i < 1000; i++ { ch11 <- i } go func(){ var e int ok := true for{ select { case e,ok = <- ch11: if !ok { fmt.Println("End.") break } fmt.Printf("ch11 -> %d\n",e) case ok = <- func() chan bool { timeout := make(chan bool,1) go func(){ time.Sleep(time.Millisecond) timeout <- false }() return timeout }(): fmt.Println("Timeout.") break } if !ok { sign <- 0 break } } }() <- sign }
- 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
- 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
ch11 -> 0
ch11 -> 1
…
ch11 -> 999
Timeout.
非缓冲的Channel
我们在初始化一个通道时将其容量设置成0,或者直接忽略对容量的设置,那么就称之为非缓冲通道
ch1 := make(chan int, 1) ch2 := make(chan int, 0) ch3 := make(chan int)
- 向此类通道发送元素值的操作会被阻塞,直到至少有一个针对该通道的接收操作开始进行为止。
- 从此类通道接收元素值的操作会被阻塞,直到至少有一个针对该通道的发送操作开始进行为止。
- 针对非缓冲通道的接收操作会在与之相应的发送操作完成之前完成。
对于第三条要特别注意,发送操作在向非缓冲通道发送元素值的时候,会等待能够接收该元素值的那个接收操作。并且确保该元素值被成功接收,它才会真正的完成执行。而缓冲通道中,刚好相反,由于元素值的传递是异步的,所以发送操作在成功向通道发送元素值之后就会立即结束(它不会关心是否有接收操作)。
示例一
实现多个Goroutine之间的同步
package main import ( "fmt" "time" ) func main(){ unbufChan := make(chan int) go func(){ fmt.Println("Sleep a second...") time.Sleep(time.Second) num := <- unbufChan fmt.Printf("Received a integer %d.\n", num) }() num := 1 fmt.Printf("Send integer %d...\n", num) unbufChan <- num fmt.Println("Done.") }
- 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
- 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
缓冲channel输出结果如下:
Send integer 1…
Done.
======================
非缓冲channel输出结果如下:
Send integer 1…
Sleep a second…
Received a integer 1.
Done.
在非缓冲Channel中,从打印数据可以看出主Goroutine中的发送操作在等待一个能够与之配对的接收操作。配对成功后,元素值1才得以经由unbufChan通道被从主Goroutine传递至那个新的Goroutine.
select与非缓冲通道
与操作缓冲通道的select相比,它被阻塞的概率一般会大很多。只有存在可配对的操作的时候,传递元素值的动作才能真正的开始。
示例:
发送操作间隔1s,接收操作间隔2s
分别向unbufChan通道发送小于10和大于等于10的整数,这样更容易从打印结果分辨出配对的时候哪一个case被选中了。下列案例两个case是被随机选择的。
package main import ( "fmt" "time" ) func main(){ unbufChan := make(chan int) sign := make(chan byte, 2) go func(){ for i := 0; i < 10; i++ { select { case unbufChan <- i: case unbufChan <- i + 10: default: fmt.Println("default!") } time.Sleep(time.Second) } close(unbufChan) fmt.Println("The channel is closed.") sign <- 0 }() go func(){ loop: for { select { case e, ok := <-unbufChan: if !ok { fmt.Println("Closed channel.") break loop } fmt.Printf("e: %d\n",e) time.Sleep(2 * time.Second) } } sign <- 1 }() <- sign <- sign }
- 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
- 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
default! //无法配对
e: 1
default!//无法配对
e: 3
default!//无法配对
e: 15
default!//无法配对
e: 17
default!//无法配对
e: 9
The channel is closed.
Closed channel.
default case会在收发操作无法配对的情况下被选中并执行。在这里它被选中的概率是50%。
- 上面的示例给予了我们这样一个启发:使用非缓冲通道能够让我们非常方便地在接收端对发送端的操作频率实施控制。
- 可以尝试去掉default case,看看打印结果,代码稍作修改如下:
package main import ( "fmt" "time" ) func main(){ unbufChan := make(chan int) sign := make(chan byte, 2) go func(){ for i := 0; i < 10; i++ { select { case unbufChan <- i: case unbufChan <- i + 10: } fmt.Printf("The %d select is selected\n",i) time.Sleep(time.Second) } close(unbufChan) fmt.Println("The channel is closed.") sign <- 0 }() go func(){ loop: for { select { case e, ok := <-unbufChan: if !ok { fmt.Println("Closed channel.") break loop } fmt.Printf("e: %d\n",e) time.Sleep(2 * time.Second) } } sign <- 1 }() <- sign <- sign }
- 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
- 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
e: 0
The 0 select is selected
e: 11
The 1 select is selected
e: 12
The 2 select is selected
e: 3
The 3 select is selected
e: 14
The 4 select is selected
e: 5
The 5 select is selected
e: 16
The 6 select is selected
e: 17
The 7 select is selected
e: 8
The 8 select is selected
e: 19
The 9 select is selected
The channel is closed.
Closed channel.
总结:上面两个例子,第一个有default case 无法配对时执行该语句,而第二个没有default case ,无法配对case时select将阻塞,直到某个case可以运行(上述示例是直到unbufChan数据被读取操作),不会重新对channel或值进行求值。
golang | 评论:0
| Trackbacks:0
| 阅读:507