【问题标题】:cURL only IP and portcURL 仅 IP 和端口
【发布时间】:2017-01-18 11:07:49
【问题描述】:

我正在尝试向 IP:port 发送 XML 请求,但 cURL 总是超时。但是,端点已启动并正在运行。我是否指定了错误的 URL?这就是我所拥有的:

$ip = '90.179.113.54';
$port = '5500';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://' . $ip . ':' . $port);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 4);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
$result = curl_exec($ch);

$xml 变量只是我要发送的 XML,所以不用担心。这个端口上的服务器应该返回一个 XML 响应,我想我在 $result 中捕获它。但是,此连接总是以超时结束 - 当我在浏览器中输入 IP/端口时,它不会超时。它返回浏览器无法处理的 XML 响应。

Telnet 响应:

telnet 90.179.113.54 5500
Trying 90.179.113.54...
Connected to 54.113.broadband12.iol.cz.
Escape character is '^]'.
telnet 90.179.113.54 5500
Trying 90.179.113.54...
Connected to 54.113.broadband12.iol.cz.
<?xml version="1.0" encoding="Windows-1250" standalone="yes"?>
<RESPONSE TYPE="0" MODUL="" LANG=""><ERROR ERRNUM="0" ERRMESSAGE="0-OK" ATTRIBUT=""/></RESPONSE>

【问题讨论】:

  • @LucaGiardina 这段代码给了我一个无限旋转的圆圈。只是等待和等待。我认为这是因为巨大的超时值。如果有一个较低的值,它也会超时。
  • 你的 CURLOPT_POSTFIELDS 错过了一个 "arg = ".$xml,也许是这个问题,试试看吧..
  • @LucaGiardina 你的意思是curl_setopt($ch, CURLOPT_POSTFIELDS, "xmlRequest=" . $xml);?这就是我从您提供的 URL 中复制的内容。不工作。
  • “但是,这个连接总是以超时结束——当我在浏览器中输入 IP/端口时,它并没有超时。” -- 你跑了吗与浏览器在同一台计算机上的 PHP 代码?不同的计算机可能使用不同的路由到达远程服务器。此外,即使它们在同一台计算机上,也有可能浏览器使用代理并且 PHP 代码尝试直接连接(这些也是不同的路由)。

标签: php xml curl


【解决方案1】:

服务器不使用 HTTP,你告诉 curl 它是一个 http url。

因为它不是 HTTP 服务器,所以不要尝试与它说 HTTP。这就是你在这里做错的事情(你告诉 curl 它是一个 HTTP url,然后 curl 尝试与服务器说 HTTP)。

它似乎只说 TCP/ASCII(或 utf-8?)XML,所以试试吧。

$sock=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_connect($sock,'90.179.113.54',5500);
socket_write($sock,$xml);//???
$read_total='';
while(false!==($read_now=socket_read($sock,999,PHP_BINARY_READ))){
    if(strlen($read_now)<1){
        break;//...
    }
    $read_total.=$read_now;
}
socket_close($sock);
var_dump($read_total);

还要小心,不能保证 socket_write 实际上在一次调用中发送所有数据(几乎可以保证当要发送的数据大小>= 65535 字节时它不会发送),所以要安全,你应该使用一些 write_all 函数,比如

function socket_write_all($sock, string $data) {
    $len=strlen($data);
    while($len>0){
        $written=socket_write($sock,$data);
        if($written===false){
            throw new RuntimeException('socket_write failed. errno: '.socket_last_error($sock).'. error: '.socket_strerror(socket_last_error($sock)));
        }
        $len-=$written;
        $data=substr($data,$written);
    }
    return;//all data written
}

还要小心,默认情况下,套接字是阻塞的(无论如何,在 linux/windows/mac 中),但是如果你明确地将套接字设置为非阻塞模式,上面的 send_all 函数会使用很多 cpu(比如 near 100% 的 1 个核心),并且有一些方法可以缓解这种情况(select()/poll()),但为了简单起见,我建议你现在只使用阻塞套接字(并在何时开始考虑非阻塞套接字你一切正常,从优化阶段开始,如果有的话)

【讨论】:

    【解决方案2】:

    此端口未开放,尝试访问:http://90.179.113.54:5500/

    【讨论】:

    • 我试了一下,浏览器返回ERR_INVALID_HTTP_RESPONSE。这并不意味着端口已关闭,对吧?这只是意味着它返回的是 XML 响应,而不是 HTTP 响应。
    • 可能,端口响应不是 http 格式。您可以通过 windows cmd 以另一种方式对其进行测试: Telnet 90.179.113.54 5500
    • 是的。你说得对。该端口用于 XML 通信,我不确定您是否不能通过 CURL 与服务通信。看起来像 XML 套接字服务器。请参阅文档:php.net/manual/en/sockets.examples.php 您必须发送请求,并立即收到响应。您有此服务的一些文档/示例吗?
    • 我将无法在生产服务器上使用套接字。 cURL 中已经有一个实现,所以这绝对是可能的。我只是手头没有代码,所以我不能使用当前稳定的解决方案。不过感谢您的帮助。
    • 如果这个服务器有 curl 实现,它可能使用 CURLOPT_PROTOCOLS => CURLPROTO_TELNET ,因为它绝对不是 HTTP
    猜你喜欢
    • 1970-01-01
    • 2014-03-14
    • 1970-01-01
    • 2012-02-03
    • 2010-10-30
    • 2021-12-11
    • 2018-05-09
    • 2011-11-12
    • 1970-01-01
    相关资源
    最近更新 更多