PHP에서 Socket_Recv 및 Socket_Select 기능은 특히 비 블로킹 I/O 작업을 수행해야 할 때 네트워크 프로그래밍에서 매우 일반적인 도구입니다. 이 두 기능을 사용하면 네트워크 데이터를 기다려야하는 막힘을 피할 수 있으므로 프로그램의 효율성과 응답 성이 향상됩니다. 이 기사는이 두 기능을 사용하여 비 차단 수신을 달성하는 방법을 자세히 소개합니다.
전통적인 차단 수신에서는 Socket_Recv 및 기타 기능을 사용하여 데이터를 수신 할 때 프로그램은 해당 코드 라인에서 중지되며 데이터가 도착하거나 타임 아웃이 발생할 때까지 계속 실행되지 않습니다. 즉, 데이터가 없으면 프로그램이 "고정"되고 다른 작업을 수행 할 수 없습니다.
수신을 차단하는 대신 데이터를 기다리는 동안 프로그램이 실행을 중단하지 않음을 의미합니다. 데이터를 수신 할 때 확인합니다. 데이터가 없으면 다른 작업을 계속할 수 있습니다. 이런 식 으로이 프로그램은 I/O 작업을 수행하는 동안 데이터를 기다리는 동안 차단되지 않습니다.
socket_select 함수는 여러 소켓이 준비되어 있는지 확인하는 방법을 제공하므로 대기 차단을 피할 수 있습니다. Socket_Select를 호출하면 주어진 소켓에 읽을 데이터가 있는지 확인합니다. 그렇다면 해당 소켓 객체를 반환합니다. 이 기능을 사용하여 여러 소켓에서 비 차단 수신 작업을 수행 할 수 있습니다.
<span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-title function_ invoke__">socket_select</span></span><span> ( </span><span><span class="hljs-keyword">array</span></span><span> &</span><span><span class="hljs-variable">$read</span></span><span>, </span><span><span class="hljs-keyword">array</span></span><span> &</span><span><span class="hljs-variable">$write</span></span><span>, </span><span><span class="hljs-keyword">array</span></span><span> &</span><span><span class="hljs-variable">$except</span></span><span>, </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$tv_sec</span></span><span>, </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$tv_usec</span></span><span> )
</span></span>
$ 읽기 : 읽을 수 있도록 감지 해야하는 모든 소켓이 포함 된 배열.
$ 쓰기 : 쓸 수 있도록 감지 해야하는 모든 소켓이 포함 된 배열.
예외 : 예외를 위해 감지 해야하는 모든 소켓이 포함 된 배열.
$ tv_sec 및 $ tv_usec : 시간 초과 (초 및 마이크로 초)를 지정합니다. 널로 설정되면 무한 대기 중입니다.
<span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-title function_ invoke__">socket_recv</span></span><span> ( resource </span><span><span class="hljs-variable">$socket</span></span><span> , </span><span><span class="hljs-keyword">string</span></span><span> &</span><span><span class="hljs-variable">$buf</span></span><span> , </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$length</span></span><span> , </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$flags</span></span><span> )
</span></span>
$ 소켓 : 데이터를 수신 할 소켓 리소스.
$ BUF : 수신 된 데이터는이 변수에 저장됩니다.
$ 길이 : 수신 할 최대 바이트 수입니다.
$ 플래그 : 수신 작업을 제어하는 플래그, 일반적으로 0.
다음은 Socket_Select 와 함께 Socket_Recv를 사용하여 비 블로킹 수신을 달성하는 완전한 예입니다.
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-comment">// a TCP socket</span></span><span>
</span><span><span class="hljs-variable">$server</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_create</span></span><span>(AF_INET, SOCK_STREAM, SOL_TCP);
</span><span><span class="hljs-comment">// 서버 주소 및 포트 설정</span></span><span>
</span><span><span class="hljs-variable">$address</span></span><span> = </span><span><span class="hljs-string">'127.0.0.1'</span></span><span>;
</span><span><span class="hljs-variable">$port</span></span><span> = </span><span><span class="hljs-number">12345</span></span><span>;
</span><span><span class="hljs-comment">// 묶다 socket</span></span><span>
</span><span><span class="hljs-title function_ invoke__">socket_bind</span></span><span>(</span><span><span class="hljs-variable">$server</span></span><span>, </span><span><span class="hljs-variable">$address</span></span><span>, </span><span><span class="hljs-variable">$port</span></span><span>);
</span><span><span class="hljs-comment">// 모니터링을 시작하십시오</span></span><span>
</span><span><span class="hljs-title function_ invoke__">socket_listen</span></span><span>(</span><span><span class="hljs-variable">$server</span></span><span>);
</span><span><span class="hljs-comment">// 시간 초과 설정</span></span><span>
</span><span><span class="hljs-variable">$timeout</span></span><span> = </span><span><span class="hljs-number">10</span></span><span>; </span><span><span class="hljs-comment">// 타임 아웃 10 두번째</span></span><span>
</span><span><span class="hljs-variable">$read</span></span><span> = [</span><span><span class="hljs-variable">$server</span></span><span>]; </span><span><span class="hljs-comment">// 연결이 있는지 감지하는 데 사용됩니다</span></span><span>
</span><span><span class="hljs-variable">$write</span></span><span> = </span><span><span class="hljs-variable">$except</span></span><span> = [];
</span><span><span class="hljs-comment">// 루프를 입력하십시오,클라이언트 연결을 기다리고 있습니다</span></span><span>
</span><span><span class="hljs-keyword">while</span></span><span> (</span><span><span class="hljs-literal">true</span></span><span>) {
</span><span><span class="hljs-comment">// 사용 socket_select 새로운 연결이 있는지 감지합니다</span></span><span>
</span><span><span class="hljs-variable">$changed</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_select</span></span><span>(</span><span><span class="hljs-variable">$read</span></span><span>, </span><span><span class="hljs-variable">$write</span></span><span>, </span><span><span class="hljs-variable">$except</span></span><span>, </span><span><span class="hljs-variable">$timeout</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$changed</span></span><span> === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"socket_select failed\n"</span></span><span>;
</span><span><span class="hljs-keyword">break</span></span><span>;
}
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$changed</span></span><span> > </span><span><span class="hljs-number">0</span></span><span>) {
</span><span><span class="hljs-comment">// 새로운 클라이언트 연결이 있는지 확인하십시오</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">in_array</span></span><span>(</span><span><span class="hljs-variable">$server</span></span><span>, </span><span><span class="hljs-variable">$read</span></span><span>)) {
</span><span><span class="hljs-variable">$client</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_accept</span></span><span>(</span><span><span class="hljs-variable">$server</span></span><span>);
</span><span><span class="hljs-variable">$read</span></span><span>[] = </span><span><span class="hljs-variable">$client</span></span><span>; </span><span><span class="hljs-comment">// 새로운 연결이 추가되어 배열을 읽습니다</span></span><span>
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Client connected\n"</span></span><span>;
}
</span><span><span class="hljs-comment">// 연결된 모든 것을 통해 반복하십시오 socket,읽을 데이터가 있는지 확인하십시오</span></span><span>
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$read</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$sock</span></span><span>) {
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$sock</span></span><span> !== </span><span><span class="hljs-variable">$server</span></span><span>) {
</span><span><span class="hljs-variable">$data</span></span><span> = </span><span><span class="hljs-string">''</span></span><span>;
</span><span><span class="hljs-variable">$bytes_received</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_recv</span></span><span>(</span><span><span class="hljs-variable">$sock</span></span><span>, </span><span><span class="hljs-variable">$data</span></span><span>, </span><span><span class="hljs-number">1024</span></span><span>, MSG_DONTWAIT);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$bytes_received</span></span><span> === </span><span><span class="hljs-number">0</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Client disconnected\n"</span></span><span>;
</span><span><span class="hljs-title function_ invoke__">socket_close</span></span><span>(</span><span><span class="hljs-variable">$sock</span></span><span>);
</span><span><span class="hljs-variable">$read</span></span><span> = </span><span><span class="hljs-title function_ invoke__">array_diff</span></span><span>(</span><span><span class="hljs-variable">$read</span></span><span>, [</span><span><span class="hljs-variable">$sock</span></span><span>]); </span><span><span class="hljs-comment">// 읽기 목록에서 이것을 제거하십시오 socket</span></span><span>
} </span><span><span class="hljs-keyword">elseif</span></span><span> (</span><span><span class="hljs-variable">$bytes_received</span></span><span> > </span><span><span class="hljs-number">0</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Received data: <span class="hljs-subst">$data</span></span></span><span>\n";
}
}
}
}
</span><span><span class="hljs-comment">// 더 많은 처리 로직을 여기에 추가 할 수 있습니다,예를 들어, 쓰기 작업을 확인하십시오、타임 아웃处理等</span></span><span>
}
</span><span><span class="hljs-title function_ invoke__">socket_close</span></span><span>(</span><span><span class="hljs-variable">$server</span></span><span>);
</span><span><span class="hljs-meta">?></span></span><span>
</span></span>
소켓 생성 및 바인드 : Socket_create를 사용하여 TCP 소켓을 생성하고 Socket_bind를 사용하여 지정된 주소와 포트에 바인딩합니다.
Socket_select는 여러 소켓에 리스텐스 : Socket_Select 에서 듣는 $ 읽기 배열이며 $ 서버 소켓은 새 클라이언트 연결을 수락하는 데 사용됩니다. $ timeout 매개 변수는 10 초로 설정됩니다. 즉, 데이터가 전달되지 않거나 새 연결이없는 경우 Socket_Select가 반환됩니다.
수신 데이터 : 읽을 데이터가있는 경우 소셜 _recv를 통해 비 블로킹 수신이 수행됩니다. 클라이언트가 연결을 끊으면 해당 소켓을 닫고 $ 읽기 배열에서 제거하십시오.
비 블로킹 모드 :이 경우 MSG_Dontwait 플래그를 사용하여 비 블로킹 수신을 달성했습니다. 즉, Socket_Recv는 읽을 데이터가 없으면 프로그램을 차단하지 않습니다.
socket_select 사용 : socket_select는 여러 소켓의 상태를 확인하는 데 사용됩니다. 비 블로킹 모드에서는 항상 소켓에서 데이터를 기다리지 않도록 도와 주지만 데이터를 사용할 수있는 경우 즉시 처리 할 수 있습니다.
메모리 관리 : socket_select를 사용할 때는 메모리 누출과 유효하지 않은 소켓 감지를 피하기 위해 $ 읽기 배열에서 닫힌 소켓을 제거하십시오.
socket_recv 와 socket_select를 결합하면 비 블로킹 수신을 매우 편리하게 달성 할 수 있습니다. 이 방법은 데이터 대기로 인해 프로그램이 차단되는 것을 방지 할뿐만 아니라 여러 소켓 연결을 효율적으로 처리하고보다 효율적인 네트워크 통신을 달성 할 수 있습니다.
비 블로킹 수신은 중요한 기술이며, 대기 시간이 저조한 네트워크 서비스를 구축 할 때 특히 유용합니다. PHP 소켓 프로그래밍의 유연한 사용을 통해 응용 프로그램의 성능 및 확장 성을 향상시킬 수 있습니다.