PHPackages                             phasync/server - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. phasync/server

ActiveLibrary[HTTP &amp; Networking](/categories/http)

phasync/server
==============

A high performance async TCP and UDP socket server for PHP.

v1.1.1(4mo ago)0231MITPHPPHP ^8.2

Since May 23Pushed 4mo ago1 watchersCompare

[ Source](https://github.com/phasync/server)[ Packagist](https://packagist.org/packages/phasync/server)[ RSS](/packages/phasync-server/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (3)Versions (9)Used By (0)

phasync/server
==============

[](#phasyncserver)

> **Note:** This package will be renamed to `phasync/net` in a future release.

Efficient TCP and UDP networking for PHP using phasync coroutines.

All stream resources are wrapped with `AsyncStream`, providing transparent async I/O - no need to call `phasync::readable()` or `phasync::writable()` manually.

Installation
------------

[](#installation)

```
composer require phasync/server
```

TcpServer
---------

[](#tcpserver)

Accept TCP connections using a simple iterator pattern:

```
use phasync\Net\TcpServer;

phasync::run(function() {
    $server = new TcpServer('0.0.0.0:8080');

    foreach ($server->accept() as $peer => $stream) {
        phasync::go(function() use ($stream, $peer) {
            $request = fread($stream, 65536);

            fwrite($stream,
                "HTTP/1.1 200 OK\r\n" .
                "Connection: close\r\n" .
                "Content-Length: 13\r\n" .
                "\r\n" .
                "Hello, $peer!"
            );
            fclose($stream);
        });
    }
});
```

### Multiple Listen Addresses

[](#multiple-listen-addresses)

Listen on multiple ports or interfaces simultaneously:

```
$server = new TcpServer(['0.0.0.0:80', '0.0.0.0:443']);

foreach ($server->accept() as $peer => $stream) {
    // Connections from both ports arrive here
}
```

### Unix Domain Sockets

[](#unix-domain-sockets)

```
$server = new TcpServer('unix:///var/run/myapp.sock');

foreach ($server->accept() as $peer => $stream) {
    // Handle connection
}
```

### API

[](#api)

```
// Constructor
new TcpServer(string|array $addresses, array $context = [])

// Accept connections (generator)
$server->accept(): Generator  // yields peer => stream

// Management
$server->close(): void
$server->isClosed(): bool
$server->getAddresses(): array
```

Dns
---

[](#dns)

Async DNS resolution (used automatically by TcpClient):

```
use phasync\Net\Dns;
use phasync\Net\DnsRecordType;

phasync::run(function() {
    // Default: tries A (IPv4) first, then AAAA (IPv6)
    // Returns random IP when multiple records exist (load balancing)
    $ip = Dns::resolve('example.com');

    // Get all IPs for a hostname
    $allIps = Dns::resolveAll('example.com', DnsRecordType::A);

    // Explicit IPv4 only
    $ipv4 = Dns::resolve('example.com', DnsRecordType::A);

    // Explicit IPv6 only
    $ipv6 = Dns::resolve('example.com', DnsRecordType::AAAA);
});
```

Features:

- Non-blocking UDP queries to system nameserver
- IPv4 (A) and IPv6 (AAAA) support
- Random selection for load balancing when multiple records exist
- `resolveAll()` to get all IPs
- Reads `/etc/hosts` first (both IPv4 and IPv6 entries)
- Caches results using DNS TTL
- Falls back to 8.8.8.8 if no nameserver configured

### API

[](#api-1)

```
Dns::resolve(string $hostname, DnsRecordType $type = DnsRecordType::ANY, float $timeout = 2.0): ?string
Dns::resolveAll(string $hostname, DnsRecordType $type = DnsRecordType::ANY, float $timeout = 2.0): array
Dns::clearCache(): void

// DnsRecordType enum
DnsRecordType::A     // IPv4
DnsRecordType::AAAA  // IPv6
DnsRecordType::ANY   // Try A first, then AAAA (default)
```

TcpClient
---------

[](#tcpclient)

Connect to TCP servers asynchronously (with async DNS):

```
use phasync\Net\TcpClient;

phasync::run(function() {
    $conn = TcpClient::connect('example.com:80');

    fwrite($conn, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n");
    $response = stream_get_contents($conn);
    fclose($conn);

    echo $response;
});
```

### Unix Domain Sockets

[](#unix-domain-sockets-1)

```
$conn = TcpClient::connectUnix('/var/run/app.sock');
```

### API

[](#api-2)

```
// Connect to TCP server
TcpClient::connect(string $address, float $timeout = 30, array $context = []): resource

// Connect to Unix socket
TcpClient::connectUnix(string $path, float $timeout = 30, array $context = []): resource
```

UdpServer
---------

[](#udpserver)

Receive UDP datagrams with correct reply routing:

```
use phasync\Net\UdpServer;

phasync::run(function() {
    $server = new UdpServer('0.0.0.0:9000');

    foreach ($server->receive() as $peer => [$data, $socket]) {
        // Reply using the same socket (correct interface routing)
        stream_socket_sendto($socket, "Echo: $data", 0, $peer);
    }
});
```

### Multiple Interfaces

[](#multiple-interfaces)

When bound to multiple interfaces, the `$socket` returned ensures replies come from the correct source IP:

```
$server = new UdpServer(['192.168.1.10:9000', '10.0.0.10:9000']);

foreach ($server->receive() as $peer => [$data, $socket]) {
    // $socket is the interface that received the packet
    // Reply will have the correct source IP
    stream_socket_sendto($socket, "Reply", 0, $peer);
}
```

### API

[](#api-3)

```
// Constructor
new UdpServer(string|array $addresses, array $context = [])

// Receive datagrams (generator)
$server->receive(int $maxLength = 65536): Generator
// yields peer => [data, socket]

// Send (for initiating sends, not replies)
$server->send(string $address, string $data, int $flags = 0): int|false

// Management
$server->close(): void
$server->isClosed(): bool
$server->getAddresses(): array
```

Performance
-----------

[](#performance)

These implementations leverage phasync coroutines and non-blocking I/O for high performance:

- **Zero-copy buffers**: Read/write buffers are disabled for direct kernel access
- **TCP\_NODELAY**: Disabled Nagle algorithm for low-latency responses
- **SO\_REUSEPORT**: Enabled by default for graceful restarts and multi-process scaling
- **Large chunk size**: 64KB chunks for efficient data transfer

In synthetic benchmarks, this can handle 50% more requests per second than Node.js.

Design Guidelines
-----------------

[](#design-guidelines)

### Read/Write Strategy

[](#readwrite-strategy)

- **Read big**: Always read large chunks (65536 bytes) and buffer yourself if needed
- **Write for your use case**: Large chunks for bandwidth, small chunks for low latency

### Socket Options

[](#socket-options)

OptionDefaultReason`so_reuseport``true`Graceful restarts, multi-process scaling`tcp_nodelay``true`Low-latency delivery of small messages`backlog``511`Handle connection burstsOverride via the `$context` parameter:

```
$server = new TcpServer('0.0.0.0:8080', [
    'socket' => [
        'tcp_nodelay' => false,  // Enable Nagle algorithm
        'backlog' => 1024,
    ]
]);
```

Deprecated: Server Class
------------------------

[](#deprecated-server-class)

The original `Server` class is deprecated. Migrate to `TcpServer` or `UdpServer`:

```
// Old (deprecated)
Server::serve('tcp://127.0.0.1:8080', function($stream, $peer) {
    // handle connection
});

// New
$server = new TcpServer('127.0.0.1:8080');
foreach ($server->accept() as $peer => $stream) {
    phasync::go(fn() => /* handle connection */);
}
```

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance76

Regular maintenance activity

Popularity7

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~85 days

Recently: every ~136 days

Total

8

Last Release

131d ago

Major Versions

0.0.1 → 1.0.02024-06-11

### Community

Maintainers

![](https://www.gravatar.com/avatar/8822e0a14ce04a8f711d4ea933ea90aa005d9ee14827f05feac572c5601fb840?d=identicon)[frodeborli](/maintainers/frodeborli)

---

Top Contributors

[![frodeborli](https://avatars.githubusercontent.com/u/2299344?v=4)](https://github.com/frodeborli "frodeborli (10 commits)")

###  Code Quality

TestsPest

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/phasync-server/health.svg)

```
[![Health](https://phpackages.com/badges/phasync-server/health.svg)](https://phpackages.com/packages/phasync-server)
```

###  Alternatives

[friendsofsymfony/rest-bundle

This Bundle provides various tools to rapidly develop RESTful API's with Symfony

2.8k73.3M319](/packages/friendsofsymfony-rest-bundle)[php-http/discovery

Finds and installs PSR-7, PSR-17, PSR-18 and HTTPlug implementations

1.3k309.5M1.2k](/packages/php-http-discovery)[pusher/pusher-php-server

Library for interacting with the Pusher REST API

1.5k94.8M293](/packages/pusher-pusher-php-server)[react/http

Event-driven, streaming HTTP client and server implementation for ReactPHP

78026.4M414](/packages/react-http)[php-http/curl-client

PSR-18 and HTTPlug Async client with cURL

48347.0M384](/packages/php-http-curl-client)[smi2/phpclickhouse

PHP ClickHouse Client

84310.1M71](/packages/smi2-phpclickhouse)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
