【问题标题】:WebSocket: client does not response to serverWebSocket:客户端不响应服务器
【发布时间】:2013-03-31 12:56:41
【问题描述】:

我是 websocket 的新手。 我在 PHP 上做了一个简单的 websocket 实现。握手工作正常,而且连接肯定是打开的,因为我的服务器可以从客户端获取消息。

但是,一旦我尝试将消息发送回客户端,客户端根本没有响应。

这是屏蔽消息并将其发送回客户端的代码。

function myProcess($user,$buffer)
{
//$buffer=unwrap($buffer);
console("Request Caught.");
console("Content Length: ".strlen($buffer));
console("Content: ".unmask($buffer));
console("First 8 bits: ".ord($buffer[0]));
console("Opcode: ".opcode($buffer,true));
//console("Full Text: ".$buffer);
//socket_write($user->socket,mask(unmask($buffer)));
console("Masking: ");
$tmp=unmask($buffer);
console($tmp);
$masked=mask($tmp);
opcode($masked);
for($i=0;$i<strlen($masked);$i++)
{
    console($i.": ".ord($masked[$i]));
}
console("length: ".strlen($masked));
console("Sending Response: ");
console(socket_write($user->socket,$masked,strlen($masked)));
}


function mask($text)
{
    $first8bit=0x81;
    $header;
    console("mask: payload length:".strlen($text));
    if(strlen($text)<=125)
    {
        $header=pack("CC",$first8bit,strlen($text));
    }
    else if(strlen($text)<65536)
    {
        $header=pack("CCS",$first8bit,126,strlen($text));
    }
    else
    {
        $header=pack("CCN",$first8bit,127,strlen($text));
    }
    return $header.$text;
}

如果客户端向服务器发送“hi”,服务器将简单地回复“hi”。使用wireshark捕获的数据包是81 02 68 69。看来线路上的位正如协议所说的那样。如果服务器尝试发送更长的字符串,例如“hi from server”,客户端响应错误:未定义。

有人可以帮忙吗?非常感谢。

这是服务器的代码:

while(true){
  $changed = $sockets;
  socket_select($changed,$write=NULL,$except=NULL,NULL);
  foreach($changed as $socket){
    if($socket==$master){
        console("Master Socket Changed.");
      $client=socket_accept($master);
      if($client<0){ console("socket_accept() failed"); continue; }
      else{ connect($client); }
    }
    else{
        console($socket." Socket Changed.");
        $str=socket_read($socket,2048);
        $user=getuserbysocket($socket);
        if(strlen($str)==0) disconnect($socket);
        else if(!$user->handshake){ dohandshake($user,$str); }
        else
        {
            myProcess($socket,$str);
        }
        console("Comunication Ends Here.");
    }
  }
}

这是accept部分的计算:

function calc_accept($key)
{
    $tmp=$key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    $tmp=sha1($tmp,true);
    //console($tmp);
    $tmp=base64_encode($tmp);
    //console($tmp);
    return $tmp;
}

这是握手:

function dohandshake($user,$buffer){
  console("\nRequesting handshake...");
  console($buffer);
  list($resource,$host,$origin,$strkey,$data) = getheaders($buffer);
  console("Handshaking...");
  $upgrade="HTTP/1.1 101 Switching Protocols\r\n".
                    "Upgrade: websocket\r\n".
                    "Connection: Upgrade\r\n".
                    "Sec-WebSocket-Accept: ".calc_accept($strkey)."\r\n\r\n";
  socket_write($user->socket,$upgrade.chr(0),strlen($upgrade.chr(0)));
  $user->handshake=true;
  console($upgrade);
  console("Done handshaking...");
  return true;
}

这两个函数获取客户端的握手并通过套接字获取用户对象:

function getheaders($req){
  $r=$h=$o=null;
  if(preg_match("/GET (.*) HTTP/"   ,$req,$match)){ $r=$match[1]; }
  if(preg_match("/Host: (.*)\r\n/"  ,$req,$match)){ $h=$match[1]; }
  if(preg_match("/Origin: (.*)\r\n/",$req,$match)){ $o=$match[1]; }
  if(preg_match("/Sec-WebSocket-Key: (.*)\r\n/",$req,$match)){ $key=$match[1]; }
  if(preg_match("/\r\n(.*?)\$/",$req,$match)){ $data=$match[1]; }
  return array($r,$h,$o,$key,$data);
}

function getuserbysocket($socket){
  global $users;
  $found=null;
  foreach($users as $user){
    if($user->socket==$socket){ $found=$user; break; }
  }
  return $found;
}

【问题讨论】:

  • 您确定在正确的套接字上写入客户端吗?向客户端发送消息与接收消息是分开的。
  • 是的,我接受新传入的套接字并将其保存到用户对象以供以后使用。我认为在发送较长的字符串时在客户端出现错误表明客户端获取了字节。

标签: php websocket


【解决方案1】:

pack 的格式字符串对于 126 到 65536 字节之间的消息看起来是错误的。可以换个试试吗

“CCS” - 无符号短(始终为 16 位,机器字节顺序)

“CCn” - “网络”(大端)顺序中的无符号短(16 位)

【讨论】:

  • 我已经改过了,但是没有用……而且"hi"的长度是2,肯定达不到>125 &&
  • 我认为您的问题是发送“hi”有效,但发送(未指定)更长的消息失败?发送“hi”也会失败吗?
  • 我的情况是发送“hi”回客户端,客户端没有任何响应,发送“hi from server”,客户端会报错:未定义。更具体地说,发送任何小于 6 个字节的帧,客户端将不会响应,但发送任何超过 6 个字节的帧,客户端将给出错误消息。
  • 谢谢,我明白了。您确定不从问题中未包含的任何代码发送任何数据吗?在握手结束时说出额外的数据。可能值得发布更多代码来仔细检查。
  • 嗨,我已经在这篇文章中发布了几乎所有的代码。我对这个奇怪的问题很生气。如果可以,请帮忙,非常感谢!!
【解决方案2】:

我解决了。

对于正在为这个奇怪问题苦苦挣扎的人来说,这就是答案:

从握手函数中删除 socket_write($user->socket,$upgrade.chr(0),strlen($upgrade.chr(0))) 的 chr(0)。

我仍然会将 simnoc 的答案标记为正确答案,因为他启发了我。谢谢

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-26
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    相关资源
    最近更新 更多