본문 바로가기
프로그래밍/PHP

소켓연결이나 fopen등을 이용할때의 timeout 처리

by 백룡화검 2010. 1. 22.
회사일중에 소켓을 이용해서 다른 웹서비스의 xml데이터를 받아서 처리하는 작업이 있었다.

별 문제 없이 처리했으나 서비스를 하던중 문제가 발생했다.

xml을 제공하는 웹서비스의 서버 상태가 불안해서 처리 작업이 진행이 안되고 멈춰있는 경우가 종종 발생한 것이다.

소켓 연결 실패 라던가 무한 루프 등의 예외 처리는 해 놓은 상태였지만

소켓 연결이 성공한 상황에서 데이터를 받지 못해서 처리작업이 신호대기 상태로 멈춰있는 경우였다.

방법이 없을까 고민하던중 php.net에서 다음과 같은 함수를 찾았다.

stream_set_timeout와 socket_set_timeout이다.

다른 함수처럼 보이지만 결과는 같다.

stream_set_timeout은 데이터 스트림 수신 대기시간의 타임 아웃을 설정하는것이고
socket_set_timeout은 소켓 연결중 데이터 송수신 없이 대기하는 타임아웃을 설정하는 것이다.

실제 테스트에서도 같은 결과를 보여주었다.

php.net의 예제 소스들을 보면 stream_set_blocking또는 socket_set_blocking를 필히 false로 설정하라고 나와 있었지만,

이번의 경우에는 설정을 했을경우에 오히려 제대로 동작하지 않았다.

그 이유는 blocking모드를 false로 설정하게 되면 송수신이 완료하게 되었을 경우에만

데이터를 출력이나 socket의 상태값을 반환하기 때문이다.

timeout값을 설정한다고 해서 연결이 자동적으로 끊어지는것이 아니기 때문에

fget이나 feof등 의 데이터 수신 구문이 있는곳에는 필히

socket_get_status를 이용해서 수시로 연결 상태를 확인한후

timeout상태가 발생하면 예외 처리를 해주어야 한다.

다음은 샘플 소스이다.
$sock = fsockopen($host, 80, $errno, $errstr, 30);
if(!$sock){
    echo "Unable to get server status";
}else{
    $out = "GET /server.php HTTP/1.1\r\n";
    $out .= "Host: $host\r\n";
    $out .= "Connection: Close\r\n\r\n";

    fwrite($sock, $out);

    stream_set_blocking($sock, FALSE );
    stream_set_timeout($sock, $timeout);
    $info = stream_get_meta_data($sock);

    while (!feof($sock) && !$info['timed_out']) {
        $file .= fgets($sock, 4096);
        $info = stream_get_meta_data($sock);
    }

    fclose($sock);