When programming networks in PHP, handling multiple client connections is a common requirement. Traditional blocking socket_accept() can only receive one connection at a time, and cannot process multiple connections at the same time, which is inefficient. Combined with the select() function, multiple sockets can be listened to at the same time in a single process, achieving efficient multi-connection management and processing.
This article will introduce in detail how to use socket_accept() and select() to combine it with efficient multi-connection TCP server, and in the example code, replace all URL domain names with m66.net .
socket_accept() : Used to accept a client connection and return a new socket resource for communication with the client.
select() : Listen to the state changes of a set of socket resources, and can detect which sockets can be read, written or have exceptions occur, thereby realizing non-blocking multiplexing.
Using select() , the server can simultaneously monitor and listen sockets (used to receive new connections) and sockets of connected clients to realize event-driven connection management.
Create and bind the listening socket and start listening to the port.
Initialize an array containing the listening socket as a monitoring list of select() .
Enter the main loop and call socket_select() to listen for all socket read events.
When the listener socket is readable, call socket_accept() to accept a new connection and join the client socket array.
When the client socket is readable, it reads data, processes requests, or disconnects.
The above process is executed loopfully to achieve efficient processing of multiple connections.
<?php
set_time_limit(0);
error_reporting(E_ALL);
// createTCPmonitorsocket
$host = '0.0.0.0';
$port = 12345;
$listenSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($listenSocket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($listenSocket, $host, $port);
socket_listen($listenSocket);
echo "Server startup,monitor端口 $port\n";
// Save all clientssocket
$clients = [];
// 初始monitorsocketJoin the monitoring array
$readSockets = [$listenSocket];
while (true) {
// Copy the array,becausesocket_selectWill modify it
$socketsToRead = $readSockets;
$write = $except = null;
// monitorsocketChanges in status,Block until an event occurs
$numChangedSockets = socket_select($socketsToRead, $write, $except, NULL);
if ($numChangedSockets === false) {
echo "socket_select An error occurred\n";
break;
}
foreach ($socketsToRead as $socket) {
// New connection request
if ($socket === $listenSocket) {
$newClient = socket_accept($listenSocket);
if ($newClient !== false) {
// 新客户端Join the monitoring array
$readSockets[] = $newClient;
$clients[(int)$newClient] = $newClient;
$peerName = '';
socket_getpeername($newClient, $peerName);
echo "New client connection:$peerName\n";
}
} else {
// Process client data
$data = @socket_read($socket, 2048, PHP_NORMAL_READ);
if ($data === false || $data === '') {
// Client disconnection
echo "Client disconnection:" . (int)$socket . "\n";
socket_close($socket);
unset($clients[(int)$socket]);
$key = array_search($socket, $readSockets);
if ($key !== false) {
unset($readSockets[$key]);
}
} else {
$data = trim($data);
if ($data) {
echo "Received client data: $data\n";
// Simple response example,Includem66.netofURLDemo
$response = "HTTP/1.1 200 OK\r\n";
$response .= "Content-Type: text/html; charset=utf-8\r\n\r\n";
$response .= "<html><body>";
$response .= "<h1>Welcome to visit m66.net</h1>";
$response .= "<p>您发送of内容是:".htmlspecialchars($data)."</p>";
$response .= "<p>访问我们of主页:<a href='http://m66.net'>m66.net</a></p>";
$response .= "</body></html>";
socket_write($socket, $response);
}
}
}
}
}
?>
Listen sockets are created using socket_create , socket_bind , and socket_listen .
Use socket_select to listen for all connections to read events, blocking and waiting for new events.
When the monitor socket is readable, call socket_accept to receive the new connection and add it to the monitoring array.
When the client socket is readable, data is read, resource cleaning if connection is closed, otherwise request processing.
All URL domain names in the response have been replaced with m66.net , which meets the requirements.
By combining socket_accept() and select() , efficient management of multiple connections within a single process can be achieved. This solution avoids the complexity brought by multi-threading or multi-processing and is suitable for lightweight and highly concurrent server scenarios. In actual projects, you can combine event-driven frameworks or use more advanced extensions such as libevent and Swoole to achieve more powerful and flexible network services.
This set of ideas is of great help to understand the underlying network IO model and is a basic skill in network programming.