Skip to content

Commit 793e9a0

Browse files
committed
#53: + Add UDP tests for Socket Stream
1 parent b8832ec commit 793e9a0

File tree

5 files changed

+416
-1
lines changed

5 files changed

+416
-1
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
--TEST--
2+
UDP basic operations with stream_socket_recvfrom/sendto in async context
3+
--FILE--
4+
<?php
5+
6+
use function Async\spawn;
7+
use function Async\awaitAll;
8+
use function Async\delay;
9+
10+
echo "Start UDP basic operations test\n";
11+
12+
// Server coroutine
13+
$server = spawn(function() {
14+
echo "Server: creating UDP socket\n";
15+
$socket = stream_socket_server("udp://127.0.0.1:0", $errno, $errstr);
16+
if (!$socket) {
17+
echo "Server: failed to create socket: $errstr\n";
18+
return;
19+
}
20+
21+
$address = stream_socket_get_name($socket, false);
22+
echo "Server: listening on $address\n";
23+
24+
// Wait for incoming data
25+
echo "Server: waiting for UDP data\n";
26+
$data = stream_socket_recvfrom($socket, 1024, 0, $peer);
27+
echo "Server: received '$data' from $peer\n";
28+
29+
// Send response back
30+
$response = "Hello from UDP server";
31+
$bytes = stream_socket_sendto($socket, $response, 0, $peer);
32+
echo "Server: sent $bytes bytes response\n";
33+
34+
fclose($socket);
35+
return $address;
36+
});
37+
38+
// Client coroutine
39+
$client = spawn(function() use ($server) {
40+
// Wait for server to start with retry logic
41+
$address = null;
42+
for ($attempts = 0; $attempts < 5; $attempts++) {
43+
delay(10);
44+
$address = $server->getResult();
45+
if ($address) {
46+
break;
47+
}
48+
}
49+
50+
if (!$address) {
51+
throw new Exception("Client: failed to get server address after 5 attempts");
52+
}
53+
54+
echo "Client: connecting to $address\n";
55+
$socket = stream_socket_client($address, $errno, $errstr);
56+
if (!$socket) {
57+
echo "Client: failed to connect: $errstr\n";
58+
return;
59+
}
60+
61+
// Send data to server
62+
$message = "Hello from UDP client";
63+
$bytes = stream_socket_sendto($socket, $message);
64+
echo "Client: sent $bytes bytes\n";
65+
66+
// Receive response
67+
$response = stream_socket_recvfrom($socket, 1024);
68+
echo "Client: received '$response'\n";
69+
70+
fclose($socket);
71+
});
72+
73+
awaitAll([$server, $client]);
74+
echo "End UDP basic operations test\n";
75+
76+
?>
77+
--EXPECT--
78+
Start UDP basic operations test
79+
Server: creating UDP socket
80+
Server: listening on udp://127.0.0.1:0
81+
Server: waiting for UDP data
82+
Client: connecting to udp://127.0.0.1:0
83+
Client: sent 21 bytes
84+
Server: received 'Hello from UDP client' from 127.0.0.1:0
85+
Server: sent 21 bytes response
86+
Client: received 'Hello from UDP server'
87+
End UDP basic operations test
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
--TEST--
2+
Concurrent UDP operations with multiple servers and clients in async context
3+
--FILE--
4+
<?php
5+
6+
use function Async\spawn;
7+
use function Async\awaitAll;
8+
use function Async\delay;
9+
10+
echo "Start concurrent UDP operations test\n";
11+
12+
// Create multiple UDP servers
13+
$servers = [];
14+
$server_addresses = [];
15+
16+
for ($i = 0; $i < 3; $i++) {
17+
$servers[] = spawn(function() use ($i, &$server_addresses) {
18+
$socket = stream_socket_server("udp://127.0.0.1:0", $errno, $errstr);
19+
if (!$socket) {
20+
echo "Server $i: failed to create socket\n";
21+
return;
22+
}
23+
24+
$address = stream_socket_get_name($socket, false);
25+
$server_addresses[$i] = $address;
26+
echo "Server $i: listening on $address\n";
27+
28+
// Handle multiple clients
29+
for ($j = 0; $j < 2; $j++) {
30+
$data = stream_socket_recvfrom($socket, 1024, 0, $peer);
31+
echo "Server $i: received '$data' from client\n";
32+
33+
$response = "Response from server $i to message $j";
34+
stream_socket_sendto($socket, $response, 0, $peer);
35+
}
36+
37+
fclose($socket);
38+
return $address;
39+
});
40+
}
41+
42+
// Create multiple clients for each server
43+
$clients = [];
44+
for ($i = 0; $i < 3; $i++) {
45+
for ($j = 0; $j < 2; $j++) {
46+
$clients[] = spawn(function() use ($i, $j, &$server_addresses) {
47+
// Wait for server address with retry logic
48+
$address = null;
49+
for ($attempts = 0; $attempts < 5; $attempts++) {
50+
delay(10);
51+
if (isset($server_addresses[$i])) {
52+
$address = $server_addresses[$i];
53+
break;
54+
}
55+
}
56+
57+
if (!$address) {
58+
throw new Exception("Client $i-$j: server address not ready after 5 attempts");
59+
}
60+
61+
$socket = stream_socket_client($address, $errno, $errstr);
62+
if (!$socket) {
63+
echo "Client $i-$j: failed to connect\n";
64+
return;
65+
}
66+
67+
$message = "Message from client $i-$j";
68+
stream_socket_sendto($socket, $message);
69+
70+
$response = stream_socket_recvfrom($socket, 1024);
71+
echo "Client $i-$j: received '$response'\n";
72+
73+
fclose($socket);
74+
});
75+
}
76+
}
77+
78+
// Background worker
79+
$worker = spawn(function() {
80+
for ($i = 0; $i < 5; $i++) {
81+
echo "Worker: iteration $i\n";
82+
delay(10);
83+
}
84+
});
85+
86+
awaitAll(array_merge($servers, $clients, [$worker]));
87+
echo "End concurrent UDP operations test\n";
88+
89+
?>
90+
--EXPECTF--
91+
Start concurrent UDP operations test
92+
Server 0: listening on udp://127.0.0.1:%d
93+
Server 1: listening on udp://127.0.0.1:%d
94+
Server 2: listening on udp://127.0.0.1:%d
95+
Worker: iteration 0
96+
%a
97+
Server %d: received 'Message from client %d-%d' from client
98+
Client %d-%d: received 'Response from server %d to message %d'
99+
%a
100+
Worker: iteration %d
101+
%a
102+
End concurrent UDP operations test
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
--TEST--
2+
Socket limits exhaustion handling in async context
3+
--FILE--
4+
<?php
5+
6+
use function Async\spawn;
7+
use function Async\await;
8+
9+
echo "Start socket limits exhaustion test\n";
10+
11+
$test = spawn(function() {
12+
$sockets = [];
13+
$max_attempts = 1000; // Try to create many sockets
14+
$successful = 0;
15+
$failed = 0;
16+
17+
echo "Creating multiple sockets to test limits\n";
18+
19+
for ($i = 0; $i < $max_attempts; $i++) {
20+
try {
21+
$socket = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr);
22+
if ($socket) {
23+
$sockets[] = $socket;
24+
$successful++;
25+
} else {
26+
$failed++;
27+
if ($errno == 24) { // EMFILE - Too many open files
28+
echo "Reached file descriptor limit (EMFILE) at socket $i\n";
29+
break;
30+
} elseif ($errno == 23) { // ENFILE - File table overflow
31+
echo "Reached system file table limit (ENFILE) at socket $i\n";
32+
break;
33+
}
34+
}
35+
} catch (Exception $e) {
36+
echo "Exception creating socket $i: " . $e->getMessage() . "\n";
37+
$failed++;
38+
break;
39+
}
40+
41+
// Check if we're approaching reasonable limits
42+
if ($successful > 500) {
43+
echo "Created $successful sockets successfully, stopping test\n";
44+
break;
45+
}
46+
}
47+
48+
echo "Created $successful sockets, failed $failed\n";
49+
50+
// Test that we can still create sockets after cleanup
51+
foreach ($sockets as $socket) {
52+
fclose($socket);
53+
}
54+
55+
echo "Cleaned up all sockets\n";
56+
57+
// Verify we can create new sockets after cleanup
58+
$test_socket = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr);
59+
if ($test_socket) {
60+
echo "Successfully created socket after cleanup\n";
61+
fclose($test_socket);
62+
} else {
63+
echo "Failed to create socket after cleanup: $errstr\n";
64+
}
65+
66+
return $successful;
67+
});
68+
69+
$result = await($test);
70+
echo "Test completed with $result sockets created\n";
71+
72+
?>
73+
--EXPECTF--
74+
Start socket limits exhaustion test
75+
Creating multiple sockets to test limits
76+
%a
77+
Created %d sockets, failed %d
78+
Cleaned up all sockets
79+
Successfully created socket after cleanup
80+
Test completed with %d sockets created

0 commit comments

Comments
 (0)