提示: 您可以先看结论,结论在文章最后。
start…
我们先看两段代码:
测试代码 a.php
-
<?php
-
-
while($i++ < 1000) {
-
$a = fsockopen("10.55.38.18",11211);
-
unset($a);
-
sleep(3);
-
}
-
-
?>
测试代码 b.php
-
<?php
-
-
while($i++ < 1000) {
-
$a = fsockopen("10.55.38.18",11211);
-
sleep(3);
-
}
-
-
?>
分析:
- 两段测试代码只有一个unset的区别,我们只是在测试unset是否是必要的
- 因为我们打开的连接根本就没有关闭,在变量被unset或被重新赋值时,该变量所使用的连接是否会自动关闭呢?如果不能自动关闭,代码一直运行将会产生大量的连接,这是我们最担心的。
- 其实我们完全可以不必做这种测试,我们可以在销毁变量前显示关闭连接的,我们也最好这么做,虽然多了几行代码,但是代码的可读性就提高了很多
测试:
1.
strace -tt php a.php
10:57:43.474622 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
10:57:43.474705 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
10:57:43.474787 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
10:57:43.474898 connect(3, {sa_family=AF_INET, sin_port=htons(11211), sin_addr=inet_addr("10.55.38.18")}, 16) = –1 EINPROGRESS (Operation now in progress)
10:57:43.474984 poll([{fd=3, events=POLLIN|POLLOUT|POLLERR|POLLHUP, revents=POLLOUT}], 1, 60000) = 1
10:57:43.523892 getsockopt(3, SOL_SOCKET, SO_ERROR, [29042414236729344], [4]) = 0
10:57:43.523974 fcntl(3, F_SETFL, O_RDWR) = 0
10:57:43.524046 close(3) = 0
10:57:43.524124 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
10:57:43.524201 rt_sigaction(SIGCHLD, NULL, {SIG_DFL}, 8) = 0
10:57:43.524269 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
10:57:43.524331 nanosleep({3, 0}, {3, 0}) = 0
2.
strace -tt php b.php
11:13:24.554959 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
11:13:24.554998 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
11:13:24.555029 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
11:13:24.555063 connect(3, {sa_family=AF_INET, sin_port=htons(11211), sin_addr=inet_addr("10.55.38.18")}, 16) = –1 EINPROGRESS (Operation now in progress)
11:13:24.555131 poll([{fd=3, events=POLLIN|POLLOUT|POLLERR|POLLHUP, revents=POLLOUT}], 1, 60000) = 1
11:13:24.615839 getsockopt(3, SOL_SOCKET, SO_ERROR, [339302416384], [4]) = 0
11:13:24.615924 fcntl(3, F_SETFL, O_RDWR) = 0
11:13:24.616017 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
11:13:24.616098 rt_sigaction(SIGCHLD, NULL, {SIG_DFL}, 8) = 0
11:13:24.616173 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
11:13:24.616250 nanosleep({3, 0}, {3, 0}) = 0
…
…
11:13:27.618228 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 4
11:13:27.618302 fcntl(4, F_GETFL) = 0x2 (flags O_RDWR)
11:13:27.618368 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0
11:13:27.618453 connect(4, {sa_family=AF_INET, sin_port=htons(11211), sin_addr=inet_addr("10.55.38.18")}, 16) = –1 EINPROGRESS (Operation now in progress)
11:13:27.618598 poll([{fd=4, events=POLLIN|POLLOUT|POLLERR|POLLHUP, revents=POLLOUT}], 1, 60000) = 1
11:13:27.676299 getsockopt(4, SOL_SOCKET, SO_ERROR, [339302416384], [4]) = 0
11:13:27.676381 fcntl(4, F_SETFL, O_RDWR) = 0
11:13:27.676679 close(3) = 0
11:13:27.676776 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
11:13:27.676858 rt_sigaction(SIGCHLD, NULL, {SIG_DFL}, 8) = 0
11:13:27.676934 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
11:13:27.677013 nanosleep({3, 0}, <unfinished …>
分析:
- 测试1中,我们观察 4~8行,打开的连接时立即被关闭的,因为遇到了unset函数,说明: 在变量被unset时,变量所标示的连接立即关闭
- 测试2中,我们观察14~21行,发现打开的连接是4,但是关闭的连接是3,但是3是上次sleep之前的一个连接,说明: 在变量被重新赋值时,变量所标示的连接立即关闭
结论:
- 在变量被重新赋值时,变量所标示的连接立即关闭
- 在变量被unset时,变量所标示的连接立即关闭
- 不要写这么含蓄的代码。
- 如果你是一个连接变量,重新赋值前最好close一下;
- 如果你是一个对象,在析构函数中关闭你的连接;当然如果你使用的是长连接,就不必这么做了