首页 >后端开发 >php教程 >如何用 PHP 构建 WebSocket 服务器?

如何用 PHP 构建 WebSocket 服务器?

Susan Sarandon
Susan Sarandon原创
2024-12-07 01:01:10390浏览

How to Build a WebSocket Server in PHP?

如何在 PHP 中创建 WebSocket 服务器

创建 WebSocket 服务器可能是一项具有挑战性的任务,特别是当您遇到过时的代码或不完整的文档时。以下是指导您完成整个过程的详细解决方案:

服务器端代码:

<?php

set_time_limit(0);
ob_implicit_flush();

$master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($master, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($master, "localhost", 12345);
socket_listen($master, 20);

$sockets = array($master);
$users = array();

while (true) {
  $changed = $sockets;
  socket_select($changed, $write=NULL, $except=NULL, NULL);
  foreach ($changed as $socket) {
    if ($socket == $master) {
      $client = socket_accept($master);
      if ($client < 0) {
        echo "socket_accept() failed\n";
        continue;
      } else {
        connect($client);
      }
    } else {
      $bytes = @socket_recv($socket, $buffer, 2048, 0);
      if ($bytes == 0) {
        disconnect($socket);
      } else {
        $user = getuserbysocket($socket);
        if (!$user->handshake) {
          dohandshake($user, $buffer);
        } else {
          process($user, $buffer);
        }
      }
    }
  }
}

function connect($socket) {
  global $sockets, $users;
  $user = new User();
  $user->id = uniqid();
  $user->socket = $socket;
  array_push($users, $user);
  array_push($sockets, $socket);
  echo $socket." CONNECTED!\n";
}

function disconnect($socket) {
  global $sockets, $users;
  $found = null;
  $n=count($users);
  for ($i=0;$i<$n;$i++) {
    if ($users[$i]->socket == $socket) {
      $found = $i;
      break;
    }
  }
  if (!is_null($found)) {
    array_splice($users, $found, 1);
  }
  $index = array_search($socket, $sockets);
  socket_close($socket);
  echo $socket." DISCONNECTED!\n";
  if ($index>=0) {
    array_splice($sockets, $index, 1);
  }
}

function dohandshake($user, $buffer) {
  $headers = getheaders($buffer);
  $acceptkey = base64_encode(sha1($headers[4] . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
  $upgrade  = "HTTP/1.1 101 Switching Protocols\r\n" .
               "Upgrade: websocket\r\n" .
               "Connection: Upgrade\r\n" .
               "Sec-WebSocket-Accept: $acceptkey\r\n\r\n";
  socket_write($user->socket, $upgrade, strlen($upgrade));
  $user->handshake = true;
  echo "Done handshaking...\n";
}

function getheaders($req) {
  $r=$h=$u=$c=$key=$protocol=$version=$o=$data=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("/Upgrade: (.*)\r\n/", $req, $match)) {
    $u = $match[1];
  }
  if (preg_match("/Connection: (.*)\r\n/", $req, $match)) {
    $c = $match[1];
  }
  if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $req, $match)) {
    $key = $match[1];
  }
  if (preg_match("/Sec-WebSocket-Protocol: (.*)\r\n/", $req, $match)) {
    $protocol = $match[1];
  }
  if (preg_match("/Sec-WebSocket-Version: (.*)\r\n/", $req, $match)) {
    $version = $match[1];
  }
  if (preg_match("/Origin: (.*)\r\n/", $req, $match)) {
    $o = $match[1];
  }
  if (preg_match("/\r\n(.*?)$/", $req, $match)) {
    $data = $match[1];
  }
  return array($r,$h,$u,$c,$key,$protocol,$version,$o,$data);
}

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

class User {
  var $id;
  var $socket;
  var $handshake;
}

?>

客户端代码:

var connection = new WebSocket('ws://localhost:12345');

connection.onopen = function () {
  connection.send('Ping');
};

connection.onerror = function (error) {
  console.log('WebSocket Error ' + error);
};

connection.onmessage = function (e) {
  console.log('Server: ' + e.data);
};

故障排除:

如果遇到错误消息“Firefox 无法与位于 ws:// 的服务器建立连接” localhost:12345/”,检查以下内容:

  • 确保您的服务器代码正在运行端口 12345。
  • 验证您的客户端代码是否连接到正确的主机名和端口。
  • 确保您的代码正确实现 RFC 6455 规范中概述的 WebSocket 握手过程.
  • 确保正确处理 WebSocket 帧和屏蔽。

以上是如何用 PHP 构建 WebSocket 服务器?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn