AMPHP 是一组事件驱动的 PHP 库,在设计时考虑了纤维和并发性。 AMPHP/Socket 是一个用于建立和加密非阻塞套接字的库。它为 Client 端和服务器提供套接字抽象。它抽象了 PHP 中非常低级别的非阻塞流。
composer require amphp/socket
连接到服务器
// 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());
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
,该 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
});
}
来实现一个简单的http服务端和客户端
simple-http-server.php
#!/usr/bin/env php
<?php declare(strict_types=1);
require __DIR__ . '/../vendor/autoload.php';
use Amp\Socket;
use function Amp\async;
$server = Socket\listen('127.0.0.1:8888');
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();
assert($address instanceof Socket\InternetAddress);
$ip = $address->getAddress();
$port = $address->getPort();
echo"Accepted connection from {$address}." . PHP_EOL;
$body = "Hey, your IP is {$ip} and your local port used is {$port}." . PHP_EOL;
$bodyLength = strlen($body);
$socket->write("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: {$bodyLength}\r\n\r\n{$body}");
$socket->end();
});
}
启动服务端
# php simple-http-server.php
Listening for new connections on 127.0.0.1:8888 ...
Open your browser and visit http://127.0.0.1:8888/
Accepted connection from 127.0.0.1:33184.
simple-http-client.php
#!/usr/bin/env php
<?php declare(strict_types=1);
require __DIR__ . '/../vendor/autoload.php';
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::new($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);
启动服务端
# php simple-http-client.php http://127.0.0.1:8888
HTTP/1.1 200 OK
Connection: close
Content-Length: 61
Hey, your IP is 127.0.0.1 and your local port used is 33186.