2012-07-28 4 views
2

기본적으로 stream_get_contents은 60 초 동안 대기합니다. 여러 개의 스트림이 있고 모든 스트림을 연속적으로 들으려면stream_get_contents()에 의해 지속적으로 다중 TCP 스트림을 수신하는 방법은 무엇입니까?

foreach 내부에서 하나의 스트림을 듣고 있는데 다른 스트림을들을 수 없습니다.

모든 스트림에 대한 스트림 출력을 지속적으로 수신하고 캡처하는 솔루션은 무엇입니까?

while(true){ 
    //$streamArray is an array of streams obtained by stream_socket_client("tcp://..); 
    foreach($streamArray as $stream){ 
     fputs($stream,$command); 
     stream_get_contents($stream); // and update file/DB (Blocking call) 
     } 
    } 

참고 :

내 요구 사항은 시간에 대한 모든 스트림을 듣고 30 개 민트 말을하는 것입니다 : 모든 스트림의 경우 이미 stream_set_blocking($stream , true);

이 업데이트 했어요. 동시에 나는 2 개의 스트림을들을 수 없다. 5 개의 스트림이있는 경우 내 코드는 time division multiplexing입니다. 각 개별 스트림은 6 회의 민트에만 기록됩니다.

AJAX가 개별 스트림 및 기록을 독립적으로 요청하는 솔루션이 있습니다. 분명히 더 많은 코드뿐만 아니라 더 많은 CPU를 가져올 것이므로이 다중 AJAX 호출 메서드를 사용하고 싶지는 않습니다.

+0

내 요구 사항은 시간에 대한 모든 스트림을 경청하는 것입니다 30 개 민트을 말한다. 동시에 나는 2 개의 스트림을들을 수 없다. 내가 5 스트림 있다면, 내 코드는 단지 시간 분할 멀티플렉싱, 30 mints 각 개별 스트림은 6 민트에만 기록됩니다 –

+0

나는 당신이 그것을 달성하기 위해 PHP의 여러 인스턴스를 실행해야한다고 생각. –

+0

예 Anze, 여러 개의 독립적 인 ajax 호출을 실행해야합니다. 단일 인스턴스로 PHP에서 병렬 모니터링합니까? –

답변

6

당신이 읽을 수있는 데이터가있을 때까지 fread() 대기 각 호출을 의미 스트림 (들) 동 기적으로을 읽기 시작합니다. 그런 다음 stream_get_contents()을 호출합니다.이 스트림은 EOF에 도달 할 때까지 차단 스트림에서 읽습니다 (닫혀 있음). 결과는 "연속적"이 아니라 하나의 스트림을 읽는 것입니다.

이렇게 스트림을 읽는 것이 일반적이며 코드 작성이 가장 쉽지만 여러 스트림을 동시에 처리하려면 버퍼, 타이밍 및 "스트림 끝"검색을 직접 처리해야합니다. 현재 코드를 사용하면이 부분은 스트림 차단 및 stream_get_contents()을 통해 추상화됩니다.

여러 스트림을 동시에 읽으려면 스트림 과 일치하도록을 읽도록 코드를 다시 작성해야합니다.

비 시험 의사 예 :

// $streamArray is an array of streams obtained by stream_socket_client(".."); 

$buffers = array(); 
$num_streams = 0; 
foreach($streamArray as $stream) { 
    // set streams non-blocking for asynchroneous reading 
    stream_set_blocking($stream, false); 
    // write command to all streams - multiplexing 
    fputs($stream, $command); 
    // initialize buffers 
    $buffers[$stream] = ''; 
    $num_streams++; 
} 
while($num_streams) { 
    // use stream_select() to wait for new data and not use CPU at 100%. 
    // note that the stream arrays are passed by reference and are modified 
    // by stream_select() to reflect which streams are modified/have a 
    // new event. Because of this we use a copy of the original stream array. 
    // also note that due to a limitation in ZE you can not pass NULL directly 
    // for more info: read the manual 
    $no_stream = NULL; 
    $select_read = $streamArray; 
    stream_select($select_read, $no_stream, $no_stream, null); 

    // if there is new data, read into the buffer(s) 
    foreach($select_read as $stream) { 
     $buffers[$stream] .= fread($stream, 4096); 
     // check if the stream reached end 
     if (feof($stream)) { 
      $key = array_search($stream, $streamArray); 
      // close stream properly 
      $num_streams--; 
      fclose($stream); 
      // remove stream from array of open streams 
      unset($streamArray[$key]); 
     } 
    } 
} 
// do something with your buffers - our use them inside the while() loop already 
print_r($buffers); 
+0

usleep은 정말 좋지 않습니다. 'select' 호출을 사용하십시오. –

+1

1) 끝나면 읽기 배열의 스트림을 제거하십시오. 2) 'null'을 사용하는 타임 아웃을 위해, "타임 아웃 값 0을 사용하면 스트림의 상태를 즉각적으로 폴링 할 수 있습니다. 그러나 사용하는 것은 좋지 않습니다 루프에서 타임 아웃 값을 0으로 설정하면 스크립트가 너무 많은 CPU 시간을 소비하게됩니다. " –

+0

@KarolyHorvath 다시 테스트되지 않은 코드에서 일부 누설을 지적하기 위해 다시 – Kaii

1

PHP는 서버에서 단일 프로세스로 실행됩니다. 이런 식으로하는 "최선의"방법은 각 스트림에 대한 스레드를 생성하는 것입니다. 각 스레드는 청취 할 단일 스트림을 갖습니다. 멀티 스레딩은 자동으로 여러 CPU를 활용하고 병렬로 실행할 수있게합니다.

불행히도 PHP는 이 아니며은 스레드를 만들 수 있습니다. 그러나 몇 가지 해결 방법이 있습니다 (참고 : this question이 도움이 될 수 있습니다).

옵션 1 : 복제 당신이 pcntl_fork 같은 기능을 현재의 프로세스를 복제 할 수 있도록 않습니다 프로세스

PHP. 기본적으로, 현재 PHP 프로세스의 복사본을 생성 할 수 있으며, 그 프로세스가 인계 받아 실행을 시작합니다. 그냥들을 필요가있는 각 스트림에 대해 그렇게하십시오. 합병증은 각 프로세스가 올바른 스트림을 수신하는지 확인하는 것입니다. (힌트 : 스트림 목록을 가지고 목록의 다음 스트림에 플래그를 사용하고 fork [clone the process]를 실행하면 자식 프로세스가 해당 스트림을 듣기 시작합니다. 그러나 부모 프로세스에서 update 에 같은 목록의 다음 스트림에 플래그, 또 다른 아이를 만들고, ...)

옵션 2 : 여러 PHP 인스턴스

당신은 cronjob에 다수의 호출, 또는 다른 사용할 수 있습니다 서비스 (명령 행 호출조차도)를 사용하여 각 PHP 스크립트를 호출하거나 매개 변수를 스크립트에 전달하여 수신 할 스트림을 식별합니다. 이렇게하면 각 PHP 스크립트/파일이 병렬로 실행되어 원하는 것을 얻을 수 있습니다.

옵션 3 : PHP

PHP는 기술적으로 같은 물건 내장되지 않은 사용하지 마십시오, 이것은 아마 쉽게 C, C++ 또는 Java에서 달성 될 수있다. 설정을 다시 생각해야합니다.

옵션 4 : PHP 나 아파치 모듈

만들기 당신은 PHP 나 아파치 C에서 모듈을 작성, 다음 함수는 PHP 내에서 호출 할 수 있습니다. 이것은 아마도 매우 복잡 할 것이고, 나는 그것을 권장하지 않는다.

전체적으로 전체 설정을 재고하고 PHP를 사용하지 않는 것이 좋습니다. 그러나 PHP에 국한되어 있다면 여러 개의 AJAX 호출이 필요합니다.

+0

감사합니다. 옵션 2를 진행할 것입니다. 좋은 정보. –

+0

기꺼이 도와 드리겠습니다. – cegfault

+0

@Praveen이 답변은 귀하의 질문과 관련이 없습니다. 여러 스레드/프로세스가 실제로 한 번에 하나의 스트림을 읽는 여러 스크립트에서 스트림을 분리하여 문제를 해결할 수 있습니다. 그러나 실제 해결책은 비동기 적 읽기입니다. (내 대답을 참조하십시오) – Kaii

1

모든 스트림의 스트림 출력을 지속적으로 수신하고 캡처하는 솔루션은 무엇입니까?

This issue은 꽤 오랫동안 프로그래머를 괴롭 히고 있습니다. W. Richard Stevens가 작성한 UNIX Network Programming이라는 책은 문제 해결을 위해 적절한 해결책을 찾은 경우 매우 좋은 출발점이 될 것입니다. stream_set_blocking($resource, true)

관련 문제