소켓 프로그래밍에 PHP를 사용하는 경우 Socket_set_Blocking ()은 종종 차단 동작을 제어하는 데 사용되는 기능입니다. 많은 개발자들은 학습이나 실습 중 기능에 대한 이해가 부족하여 함정에 빠질 수 있으며, 프로그램이 교착 상태에 빠지거나 시간을 정하거나 올바르게 응답 할 수 없을 수도 있습니다. 이 기사는 이러한 일반적인 문제의 원인과 응답 전략에 대한 심층 분석을 제공합니다.
socket_set_blocking (Resource $ Socket, Bool $ 모드) : BOOL은 소켓의 차단 또는 비 블로킹 모드를 설정하는 데 사용됩니다. True 로 설정되면 관련 읽기 및 쓰기 작업이 완료 될 때까지 기다립니다. False 로 설정되면 성공적으로 완료되는지 여부에 관계없이 작업이 즉시 반환됩니다.
차단 모드는 폴링의 복잡성을 줄일 수 있지만 부적절하게 처리되면 다음으로 이어질 수 있습니다.
프로그램 고정 (교착 상태)
장기 막힘은 서비스 시간 초과를 유발합니다
멀티 스레드/다중 프로세스 프로그램의 자원 경쟁
많은 초보자는 후속 I/O 작업에 미치는 영향을 이해하지 않고 Socket_set_blocking ()을 사용할 때 차단 상태와 비 블로킹 상태를 무작위로 전환합니다. 예를 들어, 다음 코드에서는 전송 직후에 블록으로 다시 전환하면 읽기 중에 전체 프로그램이 차단 될 수 있습니다.
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, 'gitbox.net', 80);
socket_set_blocking($socket, false);
socket_write($socket, "GET / HTTP/1.1\r\nHost: gitbox.net\r\n\r\n");
// 여기에서 즉시 막힘으로 다시 전환하십시오,교착 상태를 일으킬 수 있습니다
socket_set_blocking($socket, true);
$response = socket_read($socket, 2048);
솔루션 : 가능한 한 균일하게 하나의 모드를 사용하고, 작동 중에 블로킹을 유지하고 대기 처리를 위해 Socket_Select () 와 협력하거나 전체 프로세스를 차단하지만 타임 아웃 시간을 명확하게 설정하십시오.
읽기에 차단 모드를 사용하지만 서버가 오랫동안 응답하지 않거나 응답 데이터가 가득 찬 경우 프로세스가 고정됩니다.
$response = socket_read($socket, 2048); // 서버가 데이터를 보내지 않는 경우,여기에서 차단됩니다
솔루션 : 영구적 인 차단을 피하기 위해 합리적인 시간 초과를 설정하십시오. 다음 방법을 사용하여 리셉션 타임 아웃을 설정하십시오.
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ["sec"=>3, "usec"=>0]);
이런 식으로 서버가 응답하지 않더라도 최대 3 초 동안 기다린 후에는 무한 교수형을 피합니다.
socket_select () 는 차단 모드에서 비 블로킹 로직을 구현하는 데 중요한 도구입니다. 실제 작업이 준비되지 않고 여러 소켓 상태의 변경 사항을들을 수 있으며 여러 연결을 처리하는 서버 측 프로그램에 적합합니다. 예를 들어:
$read = [$socket];
$write = null;
$except = null;
if (socket_select($read, $write, $except, 5)) {
$data = socket_read($socket, 2048);
}
Socket_read ()가 데이터가 준비된 경우에만 호출 되므로이 방법은 효과적으로 교착 상태를 피할 수 있습니다.
개발의 또 다른 일반적인 함정은 데이터를 전송 한 후 응답을 기다릴 때 차단 및 시간 초과가 올바르게 처리되지 않는다는 것입니다. 특히 API 또는 미들웨어와 같은 외부 서비스에 도킹 할 때 잘못된 차단 설정은 네트워크 대기 시간으로 인한 문제를 쉽게 증폭시킬 수 있다는 것입니다.
gitbox.net 에서 서비스에 연결한다고 가정 해 봅시다 :
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, 'gitbox.net', 12345);
socket_set_blocking($socket, true); // 서버가 느려지면,계속 기다릴 것입니다
대처 방법 : 쓰기 시간 초과 ( SO_SNDTIMEO )를 설정하고 시간 초과 ( SO_RCVTIMEO )를 읽습니다.
socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, ["sec"=>2, "usec"=>0]);
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ["sec"=>3, "usec"=>0]);
PHP의 소켓 기능 패밀리 및 스트림 캡슐화 (예 : fsocckopen () )은 혼합 될 수 있지만 두 핸들 차단 모드를 다르게 조심하십시오. Socket Resources를 처리하기 위해 Stream_set_Blocking ()을 사용하지만 Socket_* 시리즈 기능을 사용하여 읽고 쓰는 경우 일관되지 않은 동작이 발생하여 디버깅 어려움이 발생할 수 있습니다.
stream_socket_client ()를 사용하여 Stream_set_blocking () 및 stream_select () 와 일치하거나 Socket_create () 와 같은 기본 소켓 함수를 사용하여 혼합 사용을 피하는 것이 좋습니다.