PHP에서 Socket_export_stream () 은 저수준 소켓 리소스를보다 고급 스트림 기반 스트림 리소스로 내보낼 수 있도록 매우 실용적인 기능으로 파일 또는 표준 입력 및 출력과 같은 소켓을 처리 할 수 있습니다. 이것은 특히 Stream_Select () , fread () , fwrite () 등과 같은 기존 스트리밍 API와 협력 할 때 개발 프로세스를 크게 단순화합니다.
그러나 소켓을 스트림으로 변환 한 후 많은 개발자들이 일반적인 문제를 겪습니다. 동일한 스트림에서 인터리브 된 읽기 및 쓰기 작업을 수행 할 때 충돌이 발생하기 쉽습니다 . 이러한 유형의 문제의 핵심은 데이터 흐름의 안정성과 일관성을 보장하기 위해 읽기 및 쓰기 프로세스를 합리적으로 정리하는 방법에 있습니다.
소켓을 스트림으로 변환하기 위해 socket_export_stream ()을 호출 할 때 PHP는 스트림을 읽을 수 있고 쓰기 쉬운 기능을 제공합니다. 이론적으로 Fread () 및 fwrite () 로 직접 조작 할 수 있습니다. 그러나 읽기 및 쓰기 작업이 예약되지 않으면 다음과 같은 문제가 발생할 수 있습니다.
쓰기 작업 차단 : 상대방이 데이터를 읽지 않으면 버퍼가 가득 차면 fwrite ()를 호출합니다.
읽기 작동 차단 : 읽기 데이터가 없으면 fread () 호출이 차단됩니다.
데이터 혼동 : 동시 읽기 및 쓰기 동기화는 수행되지 않아서 구문 분석의 일관성이없는 프로토콜과 실패가 발생합니다.
위의 문제를 피하기 위해 다음 측면에서 시작하여 사용하는 동안 안전하고 효율적인 흐름을 보장 할 수 있습니다.
스트림을 비 블로킹 모드로 설정하고 Stream_Select ()를 사용하여 블로킹을 피하기 위해 읽고 쓸 때를 결정하십시오.
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, 'm66.net', 80);
$stream = socket_export_stream($socket);
stream_set_blocking($stream, false); // 비 블로킹 모드를 설정하십시오
$read = [$stream];
$write = [$stream];
$except = null;
if (stream_select($read, $write, $except, 5)) {
if (!empty($write)) {
fwrite($stream, "GET / HTTP/1.1\r\nHost: m66.net\r\n\r\n");
}
if (!empty($read)) {
$response = fread($stream, 8192);
echo $response;
}
}
이렇게하면 스트림이 쓸 수있는 경우에만 쓰기를 통제 할 수 있으며 읽을 수있는 경우에만 차단 및 자원 폐기물을 피할 수 있습니다.
socket_export_stream ()는 양방향 스트림을 반환하지만 일부 프로토콜 또는 응용 프로그램에서 읽기 및 쓰기 로직을 분리하면 충돌이 줄어들 수 있습니다. 레이어 프로토콜 컨트롤을 적용하거나 코 루틴/멀티 프로세스/스레드를 도입하여 읽기 및 쓰기 작업을 별도로 분리 할 수 있습니다.
예를 들어, stream_socket_pair ()를 사용하여 두 개의 로컬 소켓 스트림을 생성합니다. 하나는 읽기를 담당하고 다른 하나는 쓰기를 담당하고 데이터 전송 채널을 구축합니다.
stream_select ()가 사용되지 않는 시나리오에서는 프로그램에 잠금을 명시 적으로 추가하거나 비동기 프레임 워크 (예 : Swoole, Reactphp)를 사용하여 읽기 및 쓰기 순서를 제어 할 수도 있습니다.
$lock = fopen(__FILE__, 'r');
flock($lock, LOCK_EX);
// 데이터 작성
fwrite($stream, $data);
// 잠금 해제 후 데이터를 읽습니다
flock($lock, LOCK_UN);
$response = fread($stream, 8192);
이 방법은 비교적 원시적이지만 스크립트 응용 프로그램에서 동시 자원 충돌을 효과적으로 피할 수 있습니다.
스트림을 사용하여 쓰기 작업을 완료하면 상대방이 즉시 읽을 것으로 예상되는 경우 Fflush ()에게 전화하여 버퍼를 새로 고치십시오. 연결을 닫기 전에 먼저 쓰기 끝을 닫고 읽기 종료가 완전한 읽기를 기다린 다음 연결을 끊는 데주의를 기울여야합니다.
fwrite($stream, $data);
fflush($stream);
fclose($stream);
socket_export_stream ()을 사용하면 스트림의 작동 가능성이 향상되었지만 동기 제어의 과제도 소개합니다. 읽기 및 쓰기 갈등을 피하려면 다음을 수행 할 수 있습니다.
stream_select ()를 사용하여 정확하게 일정을 잡으십시오.
비 블로킹 모드와 함께 사용;
잠금, 코 루틴 또는 비동기 처리 메커니즘을 도입합니다.
버퍼 새로 고침 및 종료 타이밍을 관리하십시오.
이러한 방법을 통해 PHP 네트워크 프로그래밍에서 소켓 변환 스트림의 신뢰성 및 유지 보수 가능성을 효과적으로 개선 할 수 있습니다.