amphp / socket
基于 Amp 和 Revolt 的非阻塞套接字连接/服务器实现。
Requires
- php: >=8.1
- ext-openssl: *
- amphp/amp: ^3
- amphp/byte-stream: ^2
- amphp/dns: ^2
- kelunik/certificate: ^1.1
- league/uri: ^6.5 | ^7
- league/uri-interfaces: ^2.3 | ^7
- revolt/event-loop: ^1 || ^0.2
Requires (Dev)
- amphp/php-cs-fixer-config: ^2
- amphp/phpunit-util: ^3
- amphp/process: ^2
- phpunit/phpunit: ^9
- psalm/phar: 5.20
- 2.x-dev
- v2.3.1
- v2.3.0
- v2.2.4
- v2.2.3
- v2.2.2
- v2.2.1
- v2.2.0
- v2.1.0
- v2.0.0
- v2.0.0-beta.9
- v2.0.0-beta.8
- v2.0.0-beta.7
- v2.0.0-beta.6
- v2.0.0-beta.5
- v2.0.0-beta.4
- v2.0.0-beta.3
- v2.0.0-beta.2
- v2.0.0-beta.1
- 1.x-dev
- v1.2.1
- v1.2.0
- v1.1.3
- v1.1.2
- v1.1.1
- v1.1.0
- v1.0.0
- v0.10.x-dev
- v0.10.13
- v0.10.12
- v0.10.11
- v0.10.10
- v0.10.9
- v0.10.8
- v0.10.7
- v0.10.6
- v0.10.5
- v0.10.4
- v0.10.3
- v0.10.2
- v0.10.1
- v0.10.0
- v0.9.9
- v0.9.8
- v0.9.7
- v0.9.6
- v0.9.5
- v0.9.4
- v0.9.3
- v0.9.2
- v0.9.1
- v0.9.0
- v0.8.0
- v0.7.0
- v0.6.0
- v0.5.0
- v0.4.5
- v0.4.4
- v0.4.3
- v0.4.2
- v0.4.1
- v0.4.0
- v0.3.0
- v0.2.7
- v0.2.6
- v0.2.5
- v0.2.4
- v0.2.3
- v0.2.2
- v0.2.1
- v0.2.0
- v0.1.0
- dev-socks5
- dev-ipv6-disable-if-not-bindable
- dev-ipv6
- dev-cert-md5-sha1
This package is auto-updated.
Last update: 2024-09-21 15:38:07 UTC
README
AMPHP 是一套专为 PHP 设计的事件驱动库集合,注重纤程和并发。 amphp/socket
是一个用于建立和加密非阻塞套接字的库。它为客户端和服务器提供套接字抽象。它抽象了 PHP 中非常低层的非阻塞流。
安装
此包可以作为 Composer 依赖项安装。
composer require amphp/socket
需求
amphp/socket
严重依赖于 amphp/byte-stream
,特别是其 ReadableStream
和 WritableStream
接口。
连接到服务器
amphp/socket
允许客户端通过 TCP、UDP 或 Unix 域套接字连接到服务器。您可以使用 Amp\Socket\connect()
建立套接字连接。如果连接失败且存在多个 IP,它会自动解析 DNS 名称并重试其他 IP。
// You can customize connect() options using ConnectContext $connectContext = (new Amp\Socket\ConnectContext) ->withConnectTimeout(5); // You can optionally pass a Cancellation object to cancel a pending connect() operation $deferredCancellation = new Amp\DeferredCancellation(); $socket = connect('amphp.org:80', $connectContext, $deferredCancellation->getCancellation());
加密连接 / TLS
如果您想通过 TLS 连接,请使用 Amp\Socket\connectTls()
或在返回的套接字上调用 $socket->setupTls()
。
处理连接
Socket
实现 ReadableStream
和 WritableStream
,因此所有来自 amphp/byte-stream
的内容都适用于接收和发送数据。
#!/usr/bin/env php <?php // basic (and dumb) HTTP client require __DIR__ . '/../vendor/autoload.php'; // This is a very simple HTTP client that just prints the response without parsing. // league/uri required for this example. use Amp\ByteStream; use Amp\Socket\ClientTlsContext; use Amp\Socket\ConnectContext; use League\Uri\Http; use function Amp\Socket\connect; use function Amp\Socket\connectTls; $stdout = ByteStream\getStdout(); if (\count($argv) !== 2) { $stdout->write('Usage: examples/simple-http-client.php <url>' . PHP_EOL); exit(1); } $uri = Http::createFromString($argv[1]); $host = $uri->getHost(); $port = $uri->getPort() ?? ($uri->getScheme() === 'https' ? 443 : 80); $path = $uri->getPath() ?: '/'; $connectContext = (new ConnectContext) ->withTlsContext(new ClientTlsContext($host)); $socket = $uri->getScheme() === 'http' ? connect($host . ':' . $port, $connectContext) : connectTls($host . ':' . $port, $connectContext); $socket->write("GET {$path} HTTP/1.1\r\nHost: $host\r\nConnection: close\r\n\r\n"); ByteStream\pipe($socket, $stdout);
服务器
amphp/socket
允许监听传入的 TCP 连接以及通过 Unix 域套接字的连接。如果您选择启用 TLS,它默认使用安全的 TLS 设置。
监听和接受连接
使用 Amp\Socket\Socket\listen()
在端口或 Unix 域套接字上监听。它是对 stream_socket_server
的包装,在失败时通过异常提供有用的错误信息。
一旦开始监听,请使用 Server::accept()
接受客户端。它返回一个在接收新客户端时返回的 Socket
。它通常在 while
循环中调用。
$server = Socket\listen("tcp://127.0.0.1:1337"); while ($client = $server->accept()) { // You shouldn't spend too much time here, because that blocks accepting another client, so we use async(): async(function () use ($client) { // Handle client connection here }); }
处理连接
Socket
实现 ReadableStream
和 WritableStream
,因此所有来自 amphp/byte-stream
的内容都适用于接收和发送数据。最好在各自的协程中处理客户端,同时让服务器尽快接受所有客户端。
#!/usr/bin/env php <?php // basic (and dumb) HTTP server require __DIR__ . '/../vendor/autoload.php'; // This is a very simple HTTP server that just prints a message to each client that connects. // It doesn't check whether the client sent an HTTP request. // You might notice that your browser opens several connections instead of just one, // even when only making one request. use Amp\Socket; use function Amp\async; $server = Socket\listen('127.0.0.1:0'); echo 'Listening for new connections on ' . $server->getAddress() . ' ...' . PHP_EOL; echo 'Open your browser and visit http://' . $server->getAddress() . '/' . PHP_EOL; while ($socket = $server->accept()) { async(function () use ($socket) { $address = $socket->getRemoteAddress(); $ip = $address->getHost(); $port = $address->getPort(); echo "Accepted connection from {$address}." . PHP_EOL; $body = "Hey, your IP is {$ip} and your local port used is {$port}."; $bodyLength = \strlen($body); $socket->write("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: {$bodyLength}\r\n\r\n{$body}"); $socket->end(); }); }
关闭连接
一旦完成与客户端的通信,请使用 Socket::close()
关闭连接。如果您想在关闭连接之前等待所有数据成功写入,请使用 Socket::end()
。请参阅上面的示例。
服务器地址
有时您不知道服务器正在监听的地址,例如,因为您监听了 tcp://127.0.0.1:0
,它分配了一个随机空闲端口。您可以使用 Server::getAddress()
获取服务器绑定到的地址。
服务器关闭
一旦完成服务器套接字的通信,请关闭套接字。这意味着服务器将不再在指定位置监听。使用 Server::close()
关闭服务器套接字。
加密连接 / TLS
如 Amp\Socket\Socket\listen()
的文档所述,在接收连接后需要手动启用 TLS。对于 TLS 服务器套接字,您在指定地址上监听 tcp://
协议。接受客户端后,请调用 $socket->setupTls()
,其中 $socket
是来自 SocketServer::accept()
的套接字。
警告 在调用
Socket::setupTls()
完成之前传输的所有数据将以明文形式传输。不要尝试从套接字读取或手动写入它。这样做将会读取本应由 OpenSSL 读取的原始 TLS 握手数据。
自签名证书
在 ClientTlsContext
中没有选项允许使用自签名证书,因为它并不比禁用对等方验证更安全。要安全地使用自签名证书,请禁用对等方验证,并使用 ClientTlsContext::withPeerFingerprint()
要求对证书进行指纹验证。
安全
如果您发现任何与安全相关的问题,请通过电子邮件发送到 [email protected]
而不是使用问题跟踪器。
许可证
MIT 许可证(MIT)。有关更多信息,请参阅 LICENSE
。