在 php 中,`socket_connect` 遍历为给定主机名返回的多个 IP 地址的实现在哪里?
Where in php it's implemented that `socket_connect` iterates over multiple IP addresses returned for a given hostname?
我有这样的代码:
if (!socket_connect($this->sock, $this->host, $this->port)) {
其中 $this->host
是主机名,解析为 2 个 IP 地址。
如果我strace
这段代码,我会看到类似
的东西
1456868407.567615 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
1456868407.567805 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
1456868407.568081 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
1456868407.568264 connect(3, {sa_family=AF_INET, sin_port=htons(5672), sin_addr=inet_addr("192.168.1.111")}, 16) = -1 EINPROGRESS (Operation now in progress)
1456868407.568763 poll([{fd=3, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, 3000) = 1 ([{fd=3, revents=POLLIN|POLLOUT|POLLERR|POLLHUP}])
1456868408.724034 getsockopt(3, SOL_SOCKET, SO_ERROR, [111], [4]) = 0
1456868408.724699 fcntl(3, F_SETFL, O_RDWR) = 0
1456868408.725414 close(3) = 0
1456868408.725901 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
1456868408.726408 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
1456868408.727032 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
1456868408.727727 connect(3, {sa_family=AF_INET, sin_port=htons(5672), sin_addr=inet_addr("192.168.1.112")}, 16) = -1 EINPROGRESS (Operation now in progress)
1456868408.728484 poll([{fd=3, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, 1842) = 1 ([{fd=3, revents=POLLOUT}])
1456868408.729281 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
1456868408.729590 fcntl(3, F_SETFL, O_RDWR) = 0
因此在第一个地址 192.168.1.111
为连接返回 ECONNREFUSED
(111
) 之后 - php 尝试下一个地址。
我检查了我正在处理的版本的相应 php 源代码:https://github.com/php/php-src/blob/php-5.5.9/ext/sockets/sockets.c#L1376 并没有找到它循环的任何地方:
通过if (! php_set_inet_addr(&sin, addr, php_sock TSRMLS_CC)) {
解析域名
这反过来只设置返回的 hostent
结构 memcpy(&(sin->sin_addr.s_addr), host_entry->h_addr_list[0], host_entry->h_length);
的第一个地址在 https://github.com/php/php-src/blob/php-5.5.9/ext%2Fsockets%2Fsockaddr_conv.c#L106
所以我的问题是:相应的代码是在哪里实现的?
或者不是 php 而不是 glibc?如果是这样 - 它在 glibc 源代码中的什么位置? (我也试图在那里找到但失败了)
找到了:https://github.com/php/php-src/blob/php-5.5.9/main/network.c#L797
for (sal = psal; !fatal && *sal != NULL; sal++) {
sa = *sal;
/* create a socket for this address */
sock = socket(sa->sa_family, socktype, 0);
if (sock == SOCK_ERR) {
continue;
}
// <skipped>
n = php_network_connect_socket(sock, sa, socklen, asynchronous,
timeout ? &working_timeout : NULL,
error_string, error_code);
if (n != -1) { // <-- here is the check
goto connected;
}
// skipped
}
在这里它遍历地址直到可以连接到一个地址。
我有这样的代码:
if (!socket_connect($this->sock, $this->host, $this->port)) {
其中 $this->host
是主机名,解析为 2 个 IP 地址。
如果我strace
这段代码,我会看到类似
1456868407.567615 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
1456868407.567805 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
1456868407.568081 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
1456868407.568264 connect(3, {sa_family=AF_INET, sin_port=htons(5672), sin_addr=inet_addr("192.168.1.111")}, 16) = -1 EINPROGRESS (Operation now in progress)
1456868407.568763 poll([{fd=3, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, 3000) = 1 ([{fd=3, revents=POLLIN|POLLOUT|POLLERR|POLLHUP}])
1456868408.724034 getsockopt(3, SOL_SOCKET, SO_ERROR, [111], [4]) = 0
1456868408.724699 fcntl(3, F_SETFL, O_RDWR) = 0
1456868408.725414 close(3) = 0
1456868408.725901 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
1456868408.726408 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
1456868408.727032 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
1456868408.727727 connect(3, {sa_family=AF_INET, sin_port=htons(5672), sin_addr=inet_addr("192.168.1.112")}, 16) = -1 EINPROGRESS (Operation now in progress)
1456868408.728484 poll([{fd=3, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, 1842) = 1 ([{fd=3, revents=POLLOUT}])
1456868408.729281 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
1456868408.729590 fcntl(3, F_SETFL, O_RDWR) = 0
因此在第一个地址 192.168.1.111
为连接返回 ECONNREFUSED
(111
) 之后 - php 尝试下一个地址。
我检查了我正在处理的版本的相应 php 源代码:https://github.com/php/php-src/blob/php-5.5.9/ext/sockets/sockets.c#L1376 并没有找到它循环的任何地方:
通过
if (! php_set_inet_addr(&sin, addr, php_sock TSRMLS_CC)) {
解析域名
这反过来只设置返回的
hostent
结构memcpy(&(sin->sin_addr.s_addr), host_entry->h_addr_list[0], host_entry->h_length);
的第一个地址在 https://github.com/php/php-src/blob/php-5.5.9/ext%2Fsockets%2Fsockaddr_conv.c#L106
所以我的问题是:相应的代码是在哪里实现的?
或者不是 php 而不是 glibc?如果是这样 - 它在 glibc 源代码中的什么位置? (我也试图在那里找到但失败了)
找到了:https://github.com/php/php-src/blob/php-5.5.9/main/network.c#L797
for (sal = psal; !fatal && *sal != NULL; sal++) {
sa = *sal;
/* create a socket for this address */
sock = socket(sa->sa_family, socktype, 0);
if (sock == SOCK_ERR) {
continue;
}
// <skipped>
n = php_network_connect_socket(sock, sa, socklen, asynchronous,
timeout ? &working_timeout : NULL,
error_string, error_code);
if (n != -1) { // <-- here is the check
goto connected;
}
// skipped
}
在这里它遍历地址直到可以连接到一个地址。