카테고리: Programming

JSON 문법과 gson

JAVA에서 JSON 작성과 파싱을 위해 구글이 만든 gson 라이브러리를 사용하였다.

일반적인 Key-Value를 가지는 JsonObject는 무난하게 파싱하고, 만들 수 있었는데, 순서 있는 배열(Array)을 다루면서 헷갈렸던 부분을 정리한다.

먼저, gson에는 JsonArray라는 타입이 별도로 존재한다. JsonArray 객체 또한 생성자를 이용하여 쉽게 만들 수 있다.
그러나 JsonArray.add()메소드를 통해 Array에 JsonObject를 추가하려고 하면  Object 타입을 받는 메소드가 존재하지 않는 것을 볼 수 있다.

하지만 JsonElement가 JsonObject를 상속한 것이므로, 이 메소드는 사실 JsonObject를 받을 수 있다.

 

그러므로 그냥 JsonArray.add(JsonObject); 을 해버리면 끝..

 

비슷한 방법으로 Object 안에 Object가 들어가는 JSON 객체도 만들 수 있다.

Endian과 네트워크를 통한 바이너리 전송

 

네트워크 프로토콜을 구현하다 보니 Endian을 신경써야만 하는 상황이 되었다. 클라이언트에서 서버로 직렬화된 바이너리 데이터를 전송하면, 서버에서 데이터를 파싱하여 올바른 값을 추출해야 하는 상황.

처음 떠올린 생각은 직렬화를 수행하기 전에 먼저 Endian을 변환하고 직렬화를 한 뒤 서버에서 역순으로 푸는 것이었다. 그런데 4바이트보다 큰 데이터는? htonl()로는 변환이 불가능한 상황. 물론 비트 시프트를 응용해서 수동으로 구현할 수는 있지만 매번 다른 크기의 데이터마다 변환 함수를 작성하는 것은 그다지 좋은 방법이 아닌 듯 했다.

그러다 문득 IPv6는 어떻게 주소를 처리하는지 궁금해졌다. 128비트가 아닌가. 한번에 변환하기는 힘든 크기의 데이터를 어떻게 효율적으로 변환하고 있을까?

나와 같은 생각을 한 사람이 또 있었던 모양이다. (https://stackoverflow.com/questions/14301973/is-network-byte-order-pointless-under-ipv6)

 

IPv6는 공용체를 사용하여 16개의 8비트 배열, 8개의 16비트 배열, 4개의 32비트 배열을 가지고 있었다. 여기서 중요한 것은 네트워크로 주소를 전송할 때 취하는 방법이다.
2바이트를 기준으로 하자면, 그냥 htons()를 8번 수행한다. 그리고 클라이언트에서 ntohs()를 8번 한다. 끝.

참 허무한 결론이 아닐 수 없다.

엔디안에 맞춰 바이너리 전송을 할 때는 일단 직렬화한 뒤 2/4Byte에 맞춰 패딩을 붙이고, htons/l 루프를 돌린다. 그리고 수신자가 거꾸로 반복하면 끝이다.

Visual Studio로 Linux 프로그래밍 하기

Visual Studio에는 리눅스용 프로그램을 빌드할 수 있는 확장 프로그램이 존재한다. Visual C++ for Linux Development가 바로 그것으로, 여기서 다운로드 하거나, Visual Studio 2017의 경우 설치 프로그램에서 추가할 수 있다.

VS와 원격 디버거는 SSH로 연결되며, 때문에 gdb, g++, openssh-server, gdb-server 패키지가 설치되어 있어야 한다.

디버거가 연결되면 리눅스용 프로그램을 작성, 빌드, 컴파일 할 수 있게 되는데, 리눅스의 헤더파일이 VS에 기본적으로 탑재되어 있지 않기에 InteliSense를 이용할 수 없게 되는 문제가 발생한다. 이것은 공개된 리눅스 배포판에서 헤더 파일들을 가져옮으로써 해결될 수 있지만, 별다른 추가적인 조작 없이 윈도 파일시스템에 이 파일들을 가져올 수 있는 방법이 있으니, 바로 Windows Linux Subsystem을 사용하는 것이다.

Linux Subsystem은 파워쉘 명령어 ‘Enable-WindowsOptionalFeature -O -F Microsoft-Windows-Subsystem-Linux‘를 통해 활성화시킬 수 있지만, 이 기능의 활성화를 위해서는 개발자 모드를 먼저 활성화시켜야 한다.

개발자 모드는 설정의 업데이트 및 복구에서 활성화할 수 있다.

파워쉘 스크립트로 활성화가 완료된 뒤에는 반드시 bash를 실행하자. 그래야 서브시스템이 로드되고, rootfs의 압축이 풀리게 된다. 서브시스템의 위치는  C:\Users\UserName\AppData\Local\lxss 이다.

libc의 설치를 위해 g++을 설치하고 나면 헤더파일을 불러올 준비가 다 끝난다.

이 경로를 프로젝트의 Dependency Directory로 잡아주면 이제 InteliSense가 정상적으로 동작할 것이다.

 

프로젝트에서 라이브러리 의존성이 발생할 수 있는데, 원하는 라이브러리를 프로젝트 속성에서 추가할 수 있다.

Library Dependencies에서 원하는 라이브러리의 이름(lib-, .a 제거)을 입력한다. 구분자는 세미콜론이다.
그리고, Additional Library Directories에 라이브러리 경로를 추가해주면 된다.

Nginx valid_referers를 이용한 이미지 핫링크 방지법

Nginx에는 Apache의 .htaccess가 없다. 그렇기에 설정 파일에서 rewrite를 걸어줘야 하는데, 그 때 사용되는 것이 location 절이다.
location 절은 htaccess의 RewriteRule과 같은 역할을 한다.

이 location 절과 valid_referers 오브젝트를 이용하여 이미지 핫링크 방지 코드를 만들어 보았다.

여기서 눈여겨 볼 부분은 valid_referers이다. valid_referersblocked, none, server_names을 기본 인자로 갖는데, 각각 다음과 같다.

blocked : Referer는 존재하나, 방화벽이나 프록시 서버에 의해 값이 삭제된 요청
none : Referer가 존재하지 않는 요청
server_names : 임의의 도메인을 추가할 수 있는 문자열 배열

또한, valid_referers는 내부 변수로 invalid_referer를 갖는데, 만약 valid_referers가 만족되면 빈 문자열을, 만족되지 않으면 1을 가지게 된다.
즉, 상기 코드의 경우 가상 호스트의 주소 혹은 blocked의 경우에 해당되지 않으면 invalid_referer는 1을 가지고, 결과적으로 403을 리턴한다.

Ghost.py 사용법

 

BeautifulSoup으로 중첩 태그 검색하기

BeautifulSoup4.4에서 제공하는 강력한 검색 메소드들에는 한 가지 문제가 있는데, 바로 attribute를 찾을 때 검색된 선택자만의 것을 찾는다는 점이다. 그렇기 때문에 <tr><a> … </a></tr> 이런 식으로 중첩된 경우 <a>를 find()나 find_all()로 검색할 시 <tr>에 적용된 attribute를 확인하여 특정하는 것이 불가능하다.

이럴 땐 find_all() 메소드를 붙들고 있지 말고 .parant 메소드를 이용, 부모를 호출해버리면 된다.

그리고, BeautifulSoup에서 생성한 객체는 Navigatable String으로, String과는 다른 종류의 물건이다. 만약 String 관련 메소드들을 사용할 필요가 있다면, String으로 변환해주자.

 

예제 코드를 하나 첨부한다.

 

 

Python 2.7에서의 Urllib2를 이용한 쿠키 전달

LWPCookieJar 객체를 그대로 헤더에 때려박으면 에러가 난다는 좋은 교훈을 얻었다.

CookieJar에 세션을 잘 담았더라도, Urllib2의 Request를 통해 전송하려면 꼭 add_cookie_header() 메소드를 사용해야 한다.