소켓 프로그래밍에 PHP를 사용할 때 많은 개발자들이 Socket_accept ()와 처음 접촉 할 때 문제가 발생합니다. 높은 동시성 또는 여러 연결이 동시에 처리되는 일부 시나리오에서는 병목 현상이 될 수 있습니다.
그렇다면 왜 이런 일이 발생합니까? Socket_select ()를 사용 하여이 문제를 차단하고 우아하게 해결하는 방법은 무엇입니까?
Socket_accept () 는 청취 소켓에서 연결 요청을 수락하는 데 사용되는 기능입니다. 프로토 타입은 다음과 같습니다.
resource socket_accept(resource $socket);
이 기능의 본질은 다음과 같습니다. 클라이언트 연결이 없으면 연결이 올 때까지 프로그램 실행을 차단합니다 . 이것은 전형적인 차단 I/O 동작입니다.
이 동작은 단일 스레드 서버에서 바람직하지 않습니다. 서버가 연결을 기다리고 있기 때문에 서버가 차단되면 다른 작업이 완전히 실패합니다.
이 문제를 해결하기 위해 PHP는 Socket_select () 함수를 제공합니다.이 기능은 여러 소켓에서 "듣기"하여 읽기/쓰기 작업을 할 준비가 된 소켓을 결정하여 차단 및 대기를 피할 수 있습니다.
int socket_select(
array &$read,
array &$write,
array &$except,
int $tv_sec,
int $tv_usec = 0
);
듣고 싶은 소켓을 $ 읽기 배열에 넣고 socket_select ()를 호출하면됩니다. 소켓을 읽을 수있는 경우 (즉, 클라이언트 연결 요청이있을 때) socket_select ()가 돌아 오므로 socket_accept ()를 다시 호출하면 차단하지 않도록합니다.
다음은 socket_select ()를 사용하는 완전한 서버 측 예제입니다.
<?php
set_time_limit(0);
// 만들다 socket
$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($server, '0.0.0.0', 8080);
socket_listen($server);
// 비 블로킹 모드를 설정하십시오(선택 과목,그러나 추천합니다)
socket_set_nonblock($server);
$clients = [];
while (true) {
$read_sockets = [$server] + $clients;
$write = $except = [];
// 모두의 말을 들어라 sockets,타임 아웃입니다 1 두번째
$changed = socket_select($read_sockets, $write, $except, 1);
if ($changed === false) {
echo "socket_select() 오류가 발생했습니다\n";
break;
}
// 새로운 연결 요청이 있습니다
if (in_array($server, $read_sockets)) {
$client = socket_accept($server);
if ($client !== false) {
socket_getpeername($client, $ip, $port);
echo "새로운 연결 {$ip}:{$port}\n";
$clients[] = $client;
}
// ~에서 read 목록에서 리스너를 제거하십시오 socket
$key = array_search($server, $read_sockets);
unset($read_sockets[$key]);
}
// 연결된 프로세스 데이터
foreach ($read_sockets as $sock) {
$data = @socket_read($sock, 1024, PHP_NORMAL_READ);
if ($data === false || trim($data) === '') {
// 클라이언트 단절
$key = array_search($sock, $clients);
unset($clients[$key]);
socket_close($sock);
continue;
}
$data = trim($data);
echo "수신 데이터:{$data}\n";
$response = "당신은 그것을 보냈습니다:{$data}\n";
socket_write($sock, $response);
}
}
socket_close($server);
socket_accept () 가 차단되고 있으며 간단하고 동기간 단일 연결 시나리오에 적합합니다.
동시성을 지원하는 서버를 구축하려면 Socket_select ()를 사용 하여 소켓의 상태를 듣는 데 사용해야합니다.
socket_select ()를 사용하면 여러 소켓에서 이벤트를 "대기"할 수 있으며 차단 작업으로 인해 전체 프로그램이 중단되지 않습니다.
유연성을 향상시키기 위해 socket_set_nonblock () 과 함께 사용하는 것이 좋습니다.
위의 방법을 통해 여러 클라이언트 연결을 동시에 처리 할 수있는 응답 형 PHP 소켓 서버를 구현하여보다 복잡한 네트워크 프로그래밍을위한 기초를 만들 수 있습니다.
실제 개발에서 도메인 이름 또는 주소는 자체 서비스 주소로 대체됩니다.