向套接字写入数据并处理断开的管道。

8

我有一些PHP代码连接到一个套接字。在向其写入数据时,我偶尔会遇到“broken pipe”错误。如果再次向管道中写入数据,问题似乎就会消失。我想知道恢复正常的最安全的方式是什么。 我还想知道socket_write是否可能在未写完传递给它的完整字符串的情况下返回。以下是我当前的代码。

function getSocket() {
  $socket = socket_create( AF_UNIX, SOCK_STREAM, 0 );
  if ( $socket === FALSE ) {
    throw new Exception(
      "socket_create failed: reason: " . socket_strerror( socket_last_error() ));
    }
  }

  $result = socket_connect($socket, $address);
  if ($result === false) {
    throw new Exception("socket_connect() failed.\nReason: ($result) " .
        socket_strerror(socket_last_error($socket)));
  }
  return $socket;
}

function writeSocket($stmt) {
  $tries = 0;
  $socket = getSocket();
  do {
    // Is is possible that socket_write may not write the full $stmt?
    // Do I need to keep rewriting until it's finished?
    $writeResult = socket_write( $socket, $stmt, strlen( $stmt ) );
    if ($writeResult === FALSE) {
      // Got  a broken pipe, What's the best way to re-establish and 
      // try to write again, do I need to call socket_shutdown?
      socket_close($socket);
      $socket = getSocket();
    }
    $tries++;
  } while ( $tries < MAX_SOCKET_TRIES && $writeResult ===  FALSE);
}
3个回答

2
Q1. 我想知道从中恢复所需的(最安全的方式)是什么。
A:这取决于应用程序。套接字侦听器正在关闭连接,或者您设置了未向我们显示的套接字选项。如何处理这些事情取决于应用程序的语义。
Q2. 我还想知道socket_write是否可能在没有写入传递给它的完整字符串的情况下返回。
A:是的。socket_write() 可以在返回之前写入零个、一些或所有字节。如果它返回一个大于零但小于输入长度的值,您应该调整偏移量(也许使用 substr())。如果它返回零或更少,请检查 socket_last_error() 以了解是否可以重试。这种扭曲已经在手册中被涵盖

我传递的唯一选项是我在示例中拥有的内容。有人告诉我,我不必担心socket_write写入比指示的字符少,因为这是一个UNIX域套接字,所以没有网络延迟。你同意吗? - Ruan Mendes
socket_write() 的文档没有提供这样的保证。 - geocar

0

你尝试过设置SO_KEEPALIVE或SO_SNDTIMEO吗?你也可以在循环中测试缓冲区长度,以查看是否已发送完整。

祝好运, -- Joe


我知道我可以测试socket_write的返回值来查看实际写入了多少字节,我的问题是是否有必要这样做,因为我看到的大多数示例都没有尝试这样做。另外,您说通过设置SO_KEEPALIVE和SO_SNDTIMEO,我将不会遇到断开的管道,这是什么意思?管道断开是因为套接字服务器(而不是PHP)出现了问题。我认为在PHP客户端上无法做任何事情来防止这种情况发生。 - Ruan Mendes
警告信息:检测到错误,导致无法加载此页面。如果问题仍然存在,请联系网站管理员。socket_write() [<a href='function.socket-write'>function.socket-write</a>]:无法写入套接字[32]:管道破裂application/classes/cci/DataSrv.php - Ruan Mendes

0

使用 socket_set_nonblock() 并修复你的 while 语句:

$writeResult === FALSE 应该改为 $writeResult !== FALSE


为什么我应该使用socket_set_nonblock?在读取套接字之前,脚本没有其他事情可做。 - Ruan Mendes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接