PHP의 Socket_accept () 함수를 사용하여 소켓 기반 서버 응용 프로그램을 작성할 때 개발자는 종종 두통이 발생합니다. 이는 일반적으로 서버가 새로운 클라이언트 연결을 수락하지 않아 서비스 중단을 유발합니다. 이 기사는이 문제의 원인을 심층적으로 분석하고보다 안정적이고 강력한 소켓 서비스를 구축하는 데 도움이되는 실질적인 대응 전략을 제공합니다.
UNIX와 같은 시스템에서 각 프로세스에는 파일, 소켓, 파이프 라인 등과 같은 리소스에 대한 참조를 관리하는 파일 디스크립터 테이블이 있습니다. 파일 디스크립터는 정수이며 시스템은 각 열린 리소스에 고유 한 FD를 할당합니다. 네트워크 프로그래밍의 경우 클라이언트가 연결할 때마다 새로운 FD가 생성됩니다.
기본적으로 단일 프로세스를 위해 Linux 시스템을 열 수있는 FDS 수는 제한됩니다 (일반적으로 1024). 동시 소켓 서비스를 실행하면 연결 리소스가 제대로 관리되지 않으면 FD가 매우 빠르게 소진됩니다.
PHP에서 소켓 프로그래밍을 사용하는 경우 Socket_accept ()는 클라이언트 연결을 수용하는 데 사용되는 핵심 기능입니다. 기본 사용량은 다음과 같습니다.
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket, '0.0.0.0', 8080);
socket_listen($socket);
while (true) {
$client = socket_accept($socket);
if ($client) {
// 클라이언트 연결을 처리합니다
}
}
Socket_accept ()가 성공적으로 실행될 때마다 새로운 클라이언트 소켓 리소스가 생성되어 FD를 차지합니다. 클라이언트가 정시에 닫히지 않거나 비정상적인 조건에서 릴리스되지 않으면 FDS 수가 계속 증가하여 결국 Socket_Accept ()가 거짓을 반환하고 오류를보고합니다.
먼저 시스템에서 허용하는 최대 파일 설명자 수를 확인하고 적절하게 늘립니다.
ulimit -n 65535
/etc/security/limits.conf 를 편집하여 설정을 지속 할 수도 있습니다.
www-data soft nofile 65535
www-data hard nofile 65535
Blocking Socket_Accept ()가 연결을 기다리는 동안 스레드가 매달려 있습니다. 시스템 FD가 소진되면 프로그램이 중단됩니다. 새 연결을 현재 허용 할 수없는 경우에도 Socket_set_nonBlock ()을 사용하여 프로그램을 계속 실행하십시오.
socket_set_nonblock($socket);
Socket_Accept ()가 자원 Dead 루프를 피하지 못한 후 지연 리트리 로직을 추가 할 수 있습니다.
$client = @socket_accept($socket);
if ($client === false) {
usleep(100000); // 기다리다 100ms 다시 시도하십시오
continue;
}
클라이언트 연결이 데이터 전송을 완료하면 연결을 명시 적으로 닫아야하고 리소스를 해제해야합니다.
socket_close($client);
꺼지 않으면 FD가 항상 소비됩니다. 모든 클라이언트 연결을 배열로 관리하고, 정기적으로 활성 상태를 확인하고, 잘못된 연결을 정리하는 것이 좋습니다.
단순한 while + socket_accept () 와 비교하여 socket_select ()를 사용하여 이벤트 중심 모델을 구현하는 것이 좋습니다. ()을 선택하면 동시에 여러 연결을 듣고 불필요한 자원 폐기물을 피하면서 이벤트가 발생할 때 연결을 처리 할 수 있습니다.
$read = [$socket];
$write = $except = [];
if (socket_select($read, $write, $except, 0) > 0) {
if (in_array($socket, $read)) {
$client = socket_accept($socket);
if ($client) {
socket_set_nonblock($client);
$clients[] = $client;
}
}
}
높은 동시성 시나리오에서는 최대 연결 수를 제한하여 FD가 동시에 채워지는 것을 방지 할 수 있습니다.
$maxClients = 1000;
if (count($clients) >= $maxClients) {
socket_close($client); // 새로운 연결을 거부하십시오
continue;
}
서버 압력을 줄이기 위해 Nginx 또는 유사한 미들웨어를 통해 프론트 엔드 연결 수를 제한 할 수도 있습니다. 예를 들어:
limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;
server {
listen 80;
server_name m66.net;
location / {
limit_conn conn_limit_per_ip 20;
proxy_pass http://localhost:8080;
}
}
FD 소진은 소켓 서비스의 일반적인 함정 중 하나이지만, 관련 원칙을 마스터하고 비 차단 모드, 합리적인 연결 폐쇄, 연결 번호 제어 및 기타 방법을 통해이를 처리하는 한 시스템의 안정성과 가용성을 크게 향상시킬 수 있습니다. 강력한 소켓 서비스를 구축하는 것은 실행할 수있는 코드 작성에 관한 것이 아니라 더 중요한 것은 시스템 리소스를 합리적으로 관리하고 잠재적 위험을 방지하는 것입니다.
소켓 프로젝트에서 Socket_Accept () 의 오류에 직면 한 경우 False 또는 "너무 많은 열린 파일"을 반환하는 경우 위의 방향에서 문제를 해결하고 최적화하여 효율적이고 신뢰할 수있는 서버 프로그램을 생성 할 수 있습니다.