오늘은 IDL에서 네트워크를 통하여 파일을 수신하도록 코딩하는 방법에 관하여 소개해보기로 하겠습니다. 즉 HTTP 또는 FTP 연결을 통하여 어떤 파일을 다운로드하고자 할 때, IDL 코딩에 의하여 이러한 작업이 자동적으로 수행되도록 할 수 있다는 얘기입니다. 이러한 작업을 위해서는 IDLnetURL 클래스의 객체를 사용해야 합니다. '객체(Object)'라는 용어 때문에 다소 거창하게 느껴질 수도 있겠지만 그다지 어려운 개념은 아닙니다. 그러면 먼저 FTP를 통하여 파일을 수신하는 예제부터 살펴보도록 하겠습니다. 예제로 수신해보고자 하는 파일은 NASA의 SWPC에서 제공되는 TXT 포맷의 데이터 파일이고 링크는 아래와 같습니다.
ftp://ftp.swpc.noaa.gov/pub/lists/xray/20200305_Gp_xr_5m.txt
이와 같이 수신하고자 하는 파일의 링크를 정확히 파악하고 있어야 합니다. 그래야 IDLnetURL 객체를 생성하면서 관련 정보들을 정확히 설정할 수 있기 때문입니다. 그러면 먼저 위의 정보를 바탕으로 다음과 같이 IDLnetURL 객체를 생성해 봅시다.
oUrl = OBJ_NEW('IDLnetUrl', URL_SCHEME='ftp', $
URL_HOST='ftp.swpc.noaa.gov', $
URL_USERNAME='anonymous', URL_PASSWORD='leesw', $
FTP_CONNECTION_MODE=1, CONNECT_TIMEOUT=40)
여기서는 IDLnetURL 클래스의 객체 레퍼런스인 oURL을 정의하면서 몇가지 중요한 속성(Property)들을 사용하고 있습니다. 가장 먼저 등장하는 URL_SCHEME 속성은 파일 수신 방식이 FTP 또는 HTTP임을 명시하는 역할인데 여기서는 위와 같이 FTP임을 명시해주었습니다. 그리고 URL_HOST 속성에는 접속할 FTP 사이트의 주소를 부여합니다. 이 FTP 사이트에 접속하기 위해서는 특별한 계정이 필요없고 그냥 anonymous로 하면 되기 때문에 URL_USERNAME, URL_PASSWORD 속성을 위와 같이 사용하였습니다. 특별한 계정이 필요한 경우라면 그 정보를 적어주면 됩니다. FTP_CONNECTION_MODE 속성은 FTP 연결 모드의 active 또는 passive 여부를 설정하는 역할인데, 디폴트 값은 1로서 active에 해당되지만 만약 passive일 경우에는 0으로 설정하면 됩니다. 그런데 이러한 구분이 중요하냐여부는 FTP 사이트의 특성에 따라 달라질 수 있기 때문에 필요시에는 신경을 써야 하겠지만, 일반적으로는 그냥 디폴트 값인 1을 사용해도 큰 문제는 없는 것 같습니다. CONNECT_TIMEOUT 속성은 만약 접속에 시간이 오래 걸릴 경우 몇 초까지 기다리도록 할 것인가를 정하는 역할인데, 디폴트 값은 180(초)이고 위에서는 40(초)로 설정하였습니다. 사실 이 값이 실제로 정확히 지켜진다는 보장은 없는 것 같지만, 그래도 만약을 위해서는 적당한 값을 주는 것이 좋을 것입니다.
이제 다음 단계에서는 실제로 수신하고자 하는 파일의 폴더 경로 및 파일명을 지정해야 합니다. 여기서는 다음과 같이 폴더 경로와 파일명을 각각의 문자 변수에 담았습니다.
dir = 'pub/lists/xray/'
file = '20200305_Gp_xr_5m.txt'
이 정보는 결국 다음과 같이 URL_PATH 속성에 대하여 적절한 값을 제공하기 위하여 사용됩니다.
path = dir+file
oURL -> SetProperty, URL_PATH=path
이와 같이 수신하고자 하는 파일의 링크에 대한 정확한 정보를 근거로 하여 IDLnetURL 클래스의 객체를 생성하는 것이 매우 중요합니다. 이 정보가 부정확할 경우에는 정상적인 파일 수신이 불가능하다는 점을 유념해야 합니다. 이제 다음 단계는 실제로 파일을 수신하는 작업인데, 다음과 같이 Get 메서드를 사용합니다. 이 메서드가 실제로 파일을 다운로드하는 역할을 합니다. 그리고 다운로드가 끝난 후에는 oURL 객체를 제거함으로써 작업이 깔끔하게 마무리되도록 하였습니다.
result = oURL->Get(FILENAME=file)
PRINT, result
OBJ_DESTROY, oURL
여기서 Get 메서드를 사용할 때에는 FILENAME 키워드에 파일명을 문자값으로 부여해야 합니다 (폴더 경로를 제외하고 파일명만). 그리고 Get 메서드가 사용된 결과를 담는 변수 result의 값이 출력되도록 했는데, 이 변수값을 통하여 파일의 수신이 제대로 수행되었는가를 진단할 수 있습니다. 만약 제대로 수신이 되었다면 그 파일이 내 컴퓨터에서 어디에 저장되었는가를 로컬 폴더 경로 정보까지 합쳐서 알려줍니다. 제 경우는 다음과 같이 출력되었습니다 (참고로 Mac OS에서 작업한 것입니다).
/Users/Sangwoo/Documents/IDL/20200305_Gp_xr_5m.txt
그런데 만약 파일 수신이 제대로 안되었을 경우에는 변수 result의 값은 그냥 null이 됩니다. 하지만 이 때 유의해야 할 점은, 파일의 수신이 제대로 안되었을 경우에는 사실 이 단계(Get 메서드가 사용된 시점)에서 에러가 발생하게 된다는 것입니다. 물론 '파일 수신이 제대로 안되었을 경우'라는 것도 종류가 있습니다. 수신하고자 했던 파일이 실제로는 존재하지 않는 경우일 수도 있고, 파일은 존재하지만 네트워크 상황이 불량하여 커넥션 타임 내에 수신이 불가한 경우 등등 여러가지가 있겠지요. 그러면 여기서 파일이 실제로는 존재하지 않아서 수신이 불가한 상황을 일부러 연출해 봅시다. 이를 위해서는 위에서 파일명만 다음과 같이 실제로 존재하지 않을만한 것으로 바꿔보면 됩니다.
file = '20200335_Gp_xr_5m.txt'
이렇게 비정상적인 상황을 인위적으로 가정하여 다시 실행을 해보면 아마 다음과 같은 내용의 에러 메시지가 뜨면서 중단될 것입니다.
% IDLNETURL::GET: CCurlException: Error: Ftp Get Request Failed. Error = RETR response: 550, Curl Error Code = 78. Last
Ftp Response = 550 20200335_Gp_xr_5m.txt: No such file or directory
여기서 가장 눈에 띄는 내용은 'No such file or directory'입니다. 즉 수신하고자 했던 파일이 실제로는 존재하지 않는다는 의미가 될 것입니다. 이 정보만으로도 어떤 문제점이 있었던 것인지 파악할 수가 있습니다. 하지만 추가적으로 주목해야 할 중요한 부분이 또 있는데 바로 'response : 550'이라는 내용입니다. 이 에러 코드 번호를 통해서도 어떤 문제가 발생한 것인지 확인할 수 있습니다. 코드 번호 일람은 IDL 도움말에서 IDLnetURL 클래스에 관한 내용을 찾아보면 하단부에 테이블로 나옵니다. 다음 그림은 해당 내용을 캡쳐한 것입니다.
이 내용을 보면 코드 번호 550에 해당되는 증상은 'Requested action not taken'으로서 요청된 다운로드 액션이 수행되지 않았다는 것입니다. 수신하려고 했던 파일이 실제로는 존재하지 않으므로 어쩔 수 없이 이러한 액션이 취해진 것으로 보입니다. 위의 에러 메시지에서는 그 외에도 'Curl Error Code = 78'이라는 내용도 있는데 이 정보를 통해서도 수신하고자 했던 파일이 실제로 존재하지 않는 문제가 발생했다는 것을 역시 확인할 수 있습니다. 따라서 파일의 수신이 정상적으로 수행되지 못하였을 때 구체적인 원인이 무엇인지에 대해서는 이러한 에러 코드 정보에 의하여 원인에 대한 진단이 가능하다는 것도 알아두면 좋습니다.
이번에는 HTTP를 통하여 파일을 수신하는 예제를 살펴보도록 하겠습니다. 사실 이 과정은 URL_SCHEME 속성의 값을 'http'로 설정해야 한다는 것을 제외하면 나머지는 위의 FTP의 경우와 크게 다르지 않습니다. 예제로 수신해보고자 하는 파일은 NASA의 GSFC에서 제공되는 JPG 포맷의 그림 파일이고 링크는 아래와 같습니다.
https://sdo.gsfc.nasa.gov/assets/img/browse/2020/03/05/20200305_020000_1024_HMIIF.jpg
그러면 먼저 위의 정보를 바탕으로 다음과 같이 IDLnetURL 객체를 생성해 봅시다.
oURL = OBJ_NEW('IDLnetUrl', URL_SCHEME='http', URL_HOST='sdo.gsfc.nasa.gov', $
URL_USERNAME='anonymous', URL_PASSWORD='lee', CONNECT_TIMEOUT=40)
여기서는 URL_SCHEME 속성의 값이 'ftp' 대신 'http'로 바뀌었다는 것을 제외하면 나머지는 앞선 예제와 거의 동일합니다. 다음 단계에서는 실제로 수신하고자 하는 파일의 폴더 경로 및 파일명을 지정해야 합니다. 이를 위하여 다음과 같이 폴더 경로와 파일명을 각각의 문자 변수에 담았습니다.
dir = 'assets/img/browse/2020/03/05/'
file = '20200305_020000_1024_HMIIF.jpg'
그리고 이 정보를 바탕으로 다음과 같이 URL_PATH 속성에 적절한 값을 부여합니다.
path = dir+file
oURL -> SetProperty, URL_PATH=path
그리고 파일을 실제로 다운로드하기 위하여 다음과 같이 Get 메서드를 사용합니다.
result = oURL->Get(FILENAME=file)
PRINT, result
OBJ_DESTROY, oURL
네트워크에 문제가 없다면 이 작업은 성공적으로 수행될 것입니다. 그리고 수신된 파일이 내 컴퓨터에서 어디에 있는지를 로컬 폴더 경로 정보까지 합쳐서 알려주도록 변수 result의 값을 출력하였습니다. 제 경우는 다음과 같이 출력되었습니다 (역시 Mac OS에서 작업한 것입니다).
/Users/Sangwoo/Documents/IDL/20200305_020000_1024_HMIIF.jpg
물론 HTTP를 통한 파일 수신에서도 파일이 없거나 네트워크가 불량하거나 할 경우라면 에러가 발생할 것입니다. 그런 경우에는 앞서 설명했던 것과 마찬가지로 에러 코드의 내용을 보면 그 원인을 진단할 수 있습니다.
'IDL > Programming' 카테고리의 다른 글
NG 체계에서의 문자 표기 관련 팁 몇가지 (PDF 문서) (0) | 2020.11.30 |
---|---|
텍스트 파일을 효과적으로 읽는 방법에 관하여 [5] (2) | 2020.04.07 |
배열의 값들을 임의의 순서로 재배치하기 (Array Scramble) (0) | 2019.12.31 |
격자점들의 다각형 내부/외부 판별 (Grids inside Polygon) (Part 2) (0) | 2019.10.31 |
격자점들의 다각형 내부/외부 판별 (Grids inside Polygon) (Part 1) (0) | 2019.10.28 |