<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>OddPoet&#039;s βetalog</title>
	<atom:link href="http://oddpoet.net/archives/category/web/feed" rel="self" type="application/rss+xml" />
	<link>http://oddpoet.net</link>
	<description>언제나 미완성... 목표는 인생의 달인!</description>
	<lastBuildDate>Thu, 17 May 2012 10:17:44 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>SPDY : 더 빠른 웹을 위한 실험적인 프로토콜</title>
		<link>http://oddpoet.net/archives/409</link>
		<comments>http://oddpoet.net/archives/409#comments</comments>
		<pubDate>Thu, 17 May 2012 10:02:12 +0000</pubDate>
		<dc:creator>OddPoet</dc:creator>
				<category><![CDATA[웹]]></category>
		<category><![CDATA[Google Chrome]]></category>
		<category><![CDATA[SPDY]]></category>

		<guid isPermaLink="false">http://oddpoet.net/?p=409</guid>
		<description><![CDATA[이 글은 SPDY의 백서 &#8220;SPDY : An experimental protocol for a faster web&#8220;를 번역한 글입니다.  개요 &#8220;웹을 더 빠르게 하자(Let&#8217;s make the web faster)&#8221; 계획의 부분으로써 우리는 웹페이지들의 반응속도를 높일 수 있는 대안 프로토콜을 실험 중에 있다. 이러한 실험 중에 하나가 SPDY(SPeeDY-스피디라고 읽는다)인데, SPDY는 웹에서 컨텐츠 전송을 위한 애플리케이션 레이어 프로토콜이다. 이 프로토콜 명세와 더불어 [...]]]></description>
			<content:encoded><![CDATA[<p>이 글은 SPDY의 백서 &#8220;<em><a href="http://dev.chromium.org/spdy/spdy-whitepaper" onclick="pageTracker._trackPageview('/outgoing/dev.chromium.org/spdy/spdy-whitepaper?referer=');">SPDY : An experimental protocol for a faster web</a></em>&#8220;를 번역한 글입니다.</p>
<h2> 개요</h2>
<p>&#8220;웹을 더 빠르게 하자(<a href="https://developers.google.com/speed/?hl=ko-KR" onclick="pageTracker._trackPageview('/outgoing/developers.google.com/speed/?hl=ko-KR&amp;referer=');">Let&#8217;s make the web faster</a>)&#8221; 계획의 부분으로써 우리는 웹페이지들의 반응속도를 높일 수 있는 대안 프로토콜을 실험 중에 있다. 이러한 실험 중에 하나가 SPDY(SPeeDY-스피디라고 읽는다)인데, SPDY는 웹에서 컨텐츠 전송을 위한 애플리케이션 레이어 프로토콜이다. 이 프로토콜 명세와 더불어 우리는 SPDY를 지원하는 구글 크롬 브라우저와 오픈소스 웹서버를 만들었다. 내부 테스트를 통해 우리는 HTTP와 SPDY 위의 어플리케이션의 성능을 비교한 결과 SPDY를 사용할 때 페이지 로드 타임을 64%정도 줄일 수 있었다. 우리는 오픈 소스 커뮤니티에 아이디어, 피드백, 코드, 테스트 결과들을 기여함으로써 보다 SPDY가 빠른 웹을 위한 차세대 애플리케이션 프로토콜이 되길 바란다.<span id="more-409"></span></p>
<h2>배경 : 웹 프로토콜과 웹 반응속도</h2>
<p>현재 웹에서 사용하는 프로토콜은 HTTP와 TCP이다. TCP는 일반적이고 신뢰성있는 전송프로토콜(transport protocol)로써 전송 보증(guaranteed delivery), 중복 제거(duplicate suppression), 순서유지(in-order delivery), 흐름제어(flow control), 혼잡 회피(congestion avoidance) 등을 제공한다. HTTP는 어플리케이션 레벨 프로토콜로써 기본적인 요청/응답의 시맨틱스를 제공한다. 우리는 전송계층(transport layer)에서 반응속도를 개선할 가능성이 더 있다고 생각하지만, 최초에는 어플리케이션 레이어(HTTP) 쪽을 중점적으로 조사를 했다. 불행히도 HTTP는 반응속도에 대해 특별히 고려된 프로토콜이 아니었다. 게다가 현재 네트웍 상에서 전송되는 웹페이지들은 10년 전의 웹페이지들과는 많이 달라졌고, 이에 따라 HTTP가 개발되던 시절에 예상할 수 없었던 개선이 필요하게 됐다. 다음은 HTTP가 최적의 성능을 내는데 저해가 되는 기능들이다.</p>
<ul>
<li><strong>커넥션 당 하나의 요청</strong>. HTTP가 한번에 하나의 리소스만 가져올 수 있기 때문에(HTTP piplelining이 도움이 되지만 여전히 FIFO queue라는 제약이 있다), 500ms의 서버 지연시간이 다른 요청에 대해서 TCP channel의 재사용을 어렵게 한다. 그래서 브라우저들은 다수의 컨넥션을 사용하여 이 문제를 우회하고 있다. 2008년 이후 대부분의 브라우저들은 결국 도메인 당 커넥션 수를 2개에서 6개로 늘렸다.</li>
<li><strong>클라이언트만 가능한 요청.</strong> HTTP하에서 오직 클라이언트만 요청을 보낼 수 있다. 서버 측에서 클라이언트가 어떤 리소스가 필요하리라는 걸 알더라도 클라이언트에 알릴 메커니즘이 존재하지 않는다. 서버는 클라이언트가 요청할 때까지 기다려야만 한다.</li>
<li><strong>압축되지 않는 요청/응답 헤더</strong>. 요즘 요청 헤더의 크기는 200byte에서 2KB까지 다양해졌다. 어플리케이션에서 쿠키를 더 많이 사용하고, user agent의 기능이 확장됨에 따라 일벅으로 헤더 크기가 700~800 바이트가 되었다. 업링크 대역폭이 아주 작은 모뎀이나 ADSL 연결에서 헤더의 데이터를 줄이는 것은 요청을 보낼 때의 응답시간을 직접적으로 향상 시킬 수 있다.</li>
<li><strong>중복 헤더들</strong>. 같은 채널에서의 대부분의 헤더들은 모든 요청에 반복적으로 사용된다. 그러나 User-Agent, Host, Accept* 등의 헤더 값들은 고정된 값이며 일반적으로 재전송이 필요하지 않다.</li>
<li><strong>선택적인 데이터 압축.</strong> HTTP는 선택적으로 데이터에 대한 압축을 사용할 수 있다. 하지만 컨텐츠는 항상 압축되어 전송되는 것이 좋다.</li>
</ul>
<h3>기존의 접근방법들</h3>
<p>SPDY는 HTTP를 빠르게 하려는 유일한 연구는 아니다. 웹의 반응속도 개선에 대한 제안들 있었고, 그 대부분이 전송계층이나 세션계층에서의 연구였다.</p>
<ul>
<li>Stream Control Transmission Protocol (SCTP) &#8212; TCP를 대체하는 전송계층 프로토콜로써 멀티플렉스 스트림과 스트림 기반 혼잡제어를 제공한다.</li>
<li>HTTP over SCTP &#8212; SCTP 위에 HTTP를 작동하자는 제안. Comparision of HTTP Over SCTP and TCP in High Delay Networks 는 두 전송프로토콜 위에서의 성능 비교 연구 결과를 보여준다.</li>
<li>Structured Stream Transport (SST) &#8212; &#8220;structured streams&#8221;는 일반적인 전송층 위에서 사용될 수 있는 가볍고, 독립적인 스트림을 만드는 프로토콜. 이것은 TCP를 대체하거나 UDP의 위에서 작동할 수 있다.</li>
<li>MUX와 SMUX &#8212; 전송계층과 어플리케이션 레이어 사이에 작동하는 중간 레이어 프로토콜. 스트림의 멀티플렉싱을 지원한다. HTTP/1.1과 비슷한 시기에 제안됐다.</li>
</ul>
<p>상기 제안들은 웹의 반응속도 문제에 대한 부분적인 해결책을 제공한다. HTTP의 압축, 우선순위 등의 고유의 문제는 여전히 남아있고, 그 아래의 전송계층과 별개의 문제다. 현실상황의 어떤 경우라도 전송계층을 변경하는 일은 매우 어렵다. 대신 우리는 어플리케이션 레이어에서의 문제들을 정리하면서 더 쉬운 해결방안 있다고 생각했다. 이 방법은 기존의 인프라스트럭쳐에 최소한의 변경만 필요로 하고, (우리 생각에는) 상당한 성능 향상을 얻어낼 수 있을 것이다.</p>
<h2>SPDY의 목표</h2>
<p>SPDY 프로젝트는 웹의 반응속도를 개선할 수 있는 어플리케이션 프로토콜을 정의하고 구현한다. SPDY의 상위 수준 목표는 다음과 같다.</p>
<ul>
<li>페이지 로드 타임 50% 감소. 우리의 사전작업 결과는 이 목표에 이미 근접하고 있다. (아래)</li>
<li>도입 복잡도를 최소화. SPDY는 전송계층으로 TCP를 사용하여 기존 네트웍 인프라스트럭쳐에 어떤 변화도 필요로 하지 않는다.</li>
<li>웹사이트의 컨테츠에 변경이 필요하지 않도록 함. SPDY는 오직 클라이언트 user agent와 웹서버만 변경하면 되도록 한다.</li>
<li>반응속도의 문제를 해결하기 위한 방법으로 프로토콜을 탐구하는 사람들이 함께 할 수 있도록 한다. 우리는 오픈 소스 커뮤니티와 산업계 전문가들의 협력하에서 이 새로운 프로토콜을 개발하길 원한다.</li>
</ul>
<p>기타 기술적인 목표들은 다음과 같다.</p>
<ul>
<li>하나의 TCP 세션을 통해 다수의 HTTP요청을 동시에 수행할 수 있게 한다.</li>
<li>헤더에 대한 압축과 불필요한 헤더를 제거함으로써 HTTP가 현재 사용중인 대역폭을 줄인다.</li>
<li>구현하기 쉬우면서 서버측에 효율적인 프로토콜을 정의한다. 우리는 예외적인 상황들을 줄이고 파싱하기 쉬운 메시지 포맷을 정의함으로써 HTTP의 복잡도를 낮추려고 한다.</li>
<li>전송계층 위의 SSL을 보다 보안성있고 기존 네트웍 인프라스트럭쳐에 보다 호환성이 좋게 만든다. SSL은 반응속도 측면에서는 불리하지만, 장기적인 관점에서 웹은 결국 보안 네트웍 연결에 의존하게 될 것이라 믿는다. 추가적으로 SSL의 사용이 기존의 프락시들을 통한 통신이 깨지지 않도록 보장해야 한다.</li>
<li>서버가 클라이언트와의 통신을 시작할 수 있게 하여, 가능한 상황에서는 클라이언트에 데이터를 push해줄 수 있도록 한다.</li>
</ul>
<h2>SPDY 설계와 기능</h2>
<p>SPDY는 SSL 위에 세션계층을 추가했다. 이것은 하나의 TCP 연결 위에서 다수의, 동시수행되는 스트림을 교차배치할 수 있게 한다.</p>
<p>일반적인 HTTP GET과 POST 메시지 포맷은 동일하다. 그러나 SPDY는 연결위에서 데이터를 인코딩하고 전송하는 새로운 프레이밍 포맷을 정의한다.</p>
<p><img class="alignnone size-full wp-image-416" title="soarjOjSeS5hoFYvjtAnxCg" src="http://oddpoet.net/wp-content/uploads/2012/05/soarjOjSeS5hoFYvjtAnxCg1.png" alt="" width="267" height="132" /></p>
<p>스트림들은 양방향이다. 즉, 스트림은 클라이언트와 서버에 의해서 생성될 수 있다.</p>
<p>기본 기능(항상 활성화됨)과 고급 기능(선택적으로 활성화)을 통해서 SPDY는 빠른 반응속도를 얻을 수 있다.</p>
<h3> 기본 기능</h3>
<ul>
<li><strong>멀티플렉스 스트림<br />
</strong>SPDY는 하나의 TCP 연결 위에 무제한 동시 스트림을 지원한다. 하나의 채널에서 요청들이 교차배치되기 때문에 TCP의 효율은 높아진다. 적은 네트웍 연결만 필요하고, 더 적은 수의 패킷만 사용된다.</li>
</ul>
<ul>
<li><strong>요청 우선순위<br />
</strong>무제한으로 스트림을 병렬화 할 수 있기 때문에 직렬화 문제를 해결할 수 있지만, 이것은 다른 문제를 만든다. 채널의 대역폭이 제한되어 있다면 채널이 막힐 수 있기 때문에 클라이언트는 요청을 블록할 수 있다. 이 문제를 극복하기 위해서 SPDY는 요청 우선순위를 구현한다 : 클라이언트는 원하는 수 만큼 요청할 수 있고, 각 요청에 우선순위를 부여한다. 이것은 네트웍 채널이 중요하지 않은 리소스들 때문에 혼잡해져서 높은 우선순위의 요청이 지연되는 것을 막는다.</li>
</ul>
<ul>
<li><strong>헤더 압축<br />
</strong>SPDY는 요청과 응답의 HTTP 헤더를 압축한다. 결과적으로 더 적은 수의 패킷과 더 적은 수의 데이터가 전송된다.</li>
</ul>
<h3> 고급 기능 (advanced features)</h3>
<p>SPDY는 서버에서 스트림을 생성할 수 있는 기능을 제공한다. 서버에서 생성된 스트림은 클라이언트의 요청이 없어서도 컨텐츠를 클라이언트에 전송할 수 있다. 웹개발자는 이 옵션을 2가지 방식으로 설정할 수 있다.</p>
<ul>
<li><strong>Server push<br />
</strong>SPDY는 서버가 클라이언트에 데이터를 푸쉬(push)하는 것을 X-Associated-Content 헤더를 통해서 실험했다. 이 헤더는 클라이언트가 요청하기 전에 서버가 리소스를 푸시하고 있다는 것을 클라이언트에 알린다. 사용자가 사이트에 처음으로 방문하여 첫 페이지를 다운로드할 때, 이 기능은 사용자 경험을 크게 향상시킬 수 있다.</li>
</ul>
<ul>
<li><strong>Server hint.<br />
</strong>자동으로 클라이언트에 리소스를 push하는 대신, X-Subresources 헤더를 사용하여 클라이언트가 특정 리소스를 요청하도록 제안하지만, 컨텐츠를 보내기 전에 클라이언트의 요청을 기다리게 된다. 네트웍 연결이 느린 경우, 클라이언트가 필요한 리소스들을 파악하는 걸리는 수백 밀리세컨드의 시간을 줄여줄 수 있다. 이 옵션은 초기 페이지가 아닌 페이지에서 더 나은 선택이 될 것이다.</li>
</ul>
<p>기술적인 세부사항은 <a href="http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft1" onclick="pageTracker._trackPageview('/outgoing/dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft1?referer=');">SPDY draft protocol specification</a>을 참조하라.</p>
<h2> SPDY 구현 : 우리가 만들어온 것들</h2>
<ul>
<li>HTTP와 SPDY로 TCP와 SSL 위에서 효율적으로 응답할 수 있는 high-speed의 in-memory 서버. 우리는 조만간 오픈소스로 이 코드를 릴리즈할 예정이다.</li>
<li>TCL와 SSL위에서 HTTP나 SPDY를 사용할 수 있는 수정된 구글 크롬. 소스 코드는 <a href="http://src.chromium.org/viewvc/chrome/trunk/src/net/spdy/" onclick="pageTracker._trackPageview('/outgoing/src.chromium.org/viewvc/chrome/trunk/src/net/spdy/?referer=');">http://src.chromium.org/viewvc/chrome/trunk/src/net/spdy/</a> 에 있다. (주: 현재 내부적인 코드네임은 &#8220;flip&#8221;이지만, 조만간 바뀌게 될 것이다.)</li>
<li>페이지들이 정확하게 복사되었는지 검증할 수 있는 테스팅과 벤치마킹 인프라스트럭처. SPDY는 원래의 서버 헤더들과 컨텐츠 인코딩, URLs 등을 그대로 유지한다. 우리는 곧 테스팅 툴과 우리의 결과를 재활용하기 위한 가이드를 릴리즈할 것이다.</li>
</ul>
<h3>사전 실험 결과</h3>
<p>우리가 개발한 구글 크롬 클라이언트와 웹서버를 가지고, SPDY의 HTTP 대비 성능을 벤치마크하기 위해서 많은 실험실 테스트를 수행했다.</p>
<p>우리는 1%의 패킷손실을 가지는 홈 네트워크 시뮬레이션 하에서 &#8220;Top 100&#8243; 웹사이트 중 25개를 다운로드 해봤다. 각 사이트를 10번씩 다운로드했고, 평균 페이지 로딩 시간을 계산했다. 그 결과 HTTP 대비 TCP 하에서는 27%~60%정도, SSL하에서는 39%~55% 정도의 성능향상을 확인할 수 있었다.</p>
<p><em>표1 : Top 25 웹사이트들에 대한 평균 페이지 로딩 타임</em></p>
<table border="1" cellspacing="0" cellpadding="3">
<tbody>
<tr>
<td width="20%"></td>
<td colspan="2">DSL 2 Mbps downlink,<br />
375 kbps uplink</td>
<td colspan="2">Cable 4 Mbps downlink,<br />
1 Mbps uplink</td>
</tr>
<tr>
<td width="20%"></td>
<td width="20%"><strong>A</strong><strong>verage ms</strong></td>
<td width="20%"><strong>Speedup</strong></td>
<td width="20%"><strong>Average ms</strong></td>
<td width="20%"><strong>Speedup</strong></td>
</tr>
<tr>
<td width="20%">HTTP</td>
<td width="20%">3111.916</td>
<td width="20%"></td>
<td width="20%">2348.188</td>
<td width="20%"></td>
</tr>
<tr>
<td width="20%">SPDY basic multi-domain* connection / TCP</td>
<td width="20%">2242.756</td>
<td width="20%">27.93%</td>
<td width="20%">1325.46</td>
<td width="20%">43.55%</td>
</tr>
<tr>
<td width="20%">SPDY basic single-domain* connection / TCP</td>
<td width="20%">1695.72</td>
<td width="20%">45.51%</td>
<td width="20%">933.836</td>
<td width="20%">60.23%</td>
</tr>
<tr>
<td width="20%">SPDY single-domain + server push / TCP</td>
<td width="20%">1671.28</td>
<td width="20%">46.29%</td>
<td width="20%">950.764</td>
<td width="20%">59.51%</td>
</tr>
<tr>
<td width="20%">SPDY single-domain + server hint / TCP</td>
<td width="20%">1608.928</td>
<td width="20%">48.30%</td>
<td width="20%">856.356</td>
<td width="20%">63.53%</td>
</tr>
<tr>
<td width="20%">SPDY basic single-domain / SSL</td>
<td width="20%">1899.744</td>
<td width="20%">38.95%</td>
<td width="20%">1099.444</td>
<td width="20%">53.18</td>
</tr>
<tr>
<td width="20%">SPDY single-domain + client prefetch / SSL</td>
<td width="20%">1781.864</td>
<td width="20%">42.74%</td>
<td width="20%">1047.308</td>
<td width="20%">55.40%</td>
</tr>
</tbody>
</table>
<p><em>* 많은 경우 요청 리소스가 속한 도메인의 수와 무관하게 SPDY는 하나의 연결로 모든 요청을 처리할 수 있다. 이 경우에는 모든 다운로드는 완전히 병렬로 진행될 수 있다. 그러나 모든 도메인을 하나의 도메인으로 줄일 수 없는 경우가 있는데, 이 경우에는 SPDY는 각 도메인별로 연결을 만들어야만한다. 이때 연결 생성마다 초기 RTT(round trip time)만큼의 시간이 필요하다.</em></p>
<p><em>그래서 우리는 2가지 모드에 대해서 테스트를 수행했다. 하나는 모든 도메인을 하나로 줄여놓은 경우(즉, 하나의 TCP 연결)와 리소스를 원래 속한 다수의 도메인으로 나누어놓은 경우(즉, 도메인 당 하나의 TCP 연결). 우리는 테스트 결과에 이를 각각 &#8220;single-domain&#8221;과 &#8220;multi-domain&#8221;이라고 표기해놓았다. 실제 환경에서의 결과는 이 결과의 사이값이 될 것이다.</em></p>
<h4>헤더 압축의 효과</h4>
<p>헤더 압축은 요청헤더의 크기를 88%, 응답헤더의 크기를 85%정도 줄인다. 낮은 대역폭을 갖는 DSL 환경에서(업로드가 375Kbps) 요청헤더 압축은 특정사이트에서 페이지 로딩 시간에 있어서 상당한 성능향상을 보여주었다(리소스 요청이 수가 많은 경우). 헤더압축만 해도 페이지 로딩 시간을 45~1142ms만큼 줄일 수 있었다.</p>
<h4>패킷 손실과 RTT(round-trip time)의 효과</h4>
<p>우리는 두번째 테스트로 패킷 손실율과 RTT가 결과에 어떤 영향을 주는지 확인하기 위한 테스트를 수행했다. 이 테스트를 위해서 패킷 손실율과 RTT를 실험변수가 아니라 케이블 연결에서 측정을 했다.</p>
<p>우리는 SPDY의 응답시간 향상효과가 패킷손실율이 높아질 수록 증가한다는 것을 알아냈다. 패킷손실율이 2%일때 최대 48%의 성능향상이 있었다. (패킷손실이 2%는 넘어서면 성능향상폭이 줄어들기 시작해서 2.5%가 되면 성능향상율이 떨어진다. 실제 미국내에서 패킷손실율은 일반적으로 1~2%이고, RTT는 평균 50-100ms이다.)</p>
<p>패킷손실율이 증가할 수록 SPDY가 더 나은 이유는</p>
<ul>
<li>SPDY는 HTTP보다 40% 정도 적은 패킷을 전송한다. 즉 패킷손실율의 영향을 덜 받는다.</li>
<li>SPDY는 보다 적은 TCP 컨넥션을 사용한다. 이것은 SYN packet이 손실될 가능성을 줄인다. 많은 TCP 구현에서 이것에 대한 지연은 의외로 크다. (3초)</li>
<li>SPDY는 재전송 타이머보다는 TCP의 빠른 재전송을 이용하여 TCP를 보다 효율적으로 이용한다.</li>
</ul>
<p>SPDY는 RTT가 증가하면 더 나은 성능을 보였다. RTT가 200ms일때 최대 27%의 성능향상이 있었다. RTT가 증가할 때 SPDY가 HTTP 대비 더 나은 성능보이는 이유는 SPDY가 모든 요청을 병렬로 처리하기 때문이다. HTTP 클라이언트가 도메인당 4개의 연결을 사용하고, 20개의 리소스를 받아야 한다면, 대략 5RT(round trip)가 걸릴것이다. SPDY는 20개의 리소스를 한번의 RT만에 가져올 수 있다.</p>
<p><em>표2 : Top 25 웹사이트에 대한 평균 페이지로딩시간 (패킷손실율 별)</em></p>
<div>
<div>
<table width="581" border="1" cellspacing="0" cellpadding="3">
<tbody>
<tr>
<td width="25%"></td>
<td colspan="2">Average ms</td>
<td width="25%">Speedup</td>
</tr>
<tr>
<td width="25%">Packet loss rate</td>
<td width="25%">HTTP</td>
<td width="25%">SPDY basic (TCP)</td>
<td width="25%"></td>
</tr>
<tr>
<td width="25%">0%</td>
<td width="25%">1152</td>
<td width="25%">1016</td>
<td width="25%">11.81%</td>
</tr>
<tr>
<td width="25%">0.5%</td>
<td width="25%">1638</td>
<td width="25%">1105</td>
<td width="25%">32.54%</td>
</tr>
<tr>
<td width="25%">1%</td>
<td width="25%">2060</td>
<td width="25%">1200</td>
<td width="25%">41.75%</td>
</tr>
<tr>
<td width="25%">1.5%</td>
<td width="25%">2372</td>
<td width="25%">1394</td>
<td width="25%">41.23%</td>
</tr>
<tr>
<td width="25%">2%</td>
<td width="25%">2904</td>
<td width="25%">1537</td>
<td width="25%">47.7%</td>
</tr>
<tr>
<td width="25%">2.5%</td>
<td width="25%">3028</td>
<td width="25%">1707</td>
<td width="25%">43.63%</td>
</tr>
</tbody>
</table>
</div>
</div>
<div><em><br />
</em></div>
<div>
<div>
<div>
<div>
<div>
<div>
<div><em>표3 : Top 25 웹사이트에 대한 평균 페이지로딩시간 (RTT 별)</em></div>
<div></div>
<div>
<div>
<table width="582" border="1" cellspacing="0" cellpadding="3">
<tbody>
<tr>
<td width="25%"><strong><br />
</strong></td>
<td colspan="2"><strong>Average ms<br />
</strong></td>
<td width="25%"><strong>Speedup</strong></td>
</tr>
<tr>
<td width="25%"><strong>RTT in ms<br />
</strong></td>
<td width="25%"><strong>HTTP<br />
</strong></td>
<td width="25%"><strong>SPDY basic (TCP)<br />
</strong></td>
<td width="25%"></td>
</tr>
<tr>
<td width="25%">20</td>
<td width="25%">1240</td>
<td width="25%">1087</td>
<td width="25%">12.34%</td>
</tr>
<tr>
<td width="25%">40</td>
<td width="25%">1571</td>
<td width="25%">1279</td>
<td width="25%">18.59%</td>
</tr>
<tr>
<td width="25%">60</td>
<td width="25%">1909</td>
<td width="25%">1526</td>
<td width="25%">20.06%</td>
</tr>
<tr>
<td width="25%">80</td>
<td width="25%">2268</td>
<td width="25%">1727</td>
<td width="25%">23.85%</td>
</tr>
<tr>
<td width="25%">120</td>
<td width="25%">2927</td>
<td width="25%">2240</td>
<td width="25%">23.47%</td>
</tr>
<tr>
<td width="25%">160</td>
<td width="25%">3650</td>
<td width="25%">2772</td>
<td width="25%">24.05%</td>
</tr>
<tr>
<td width="25%">200</td>
<td width="25%">4498</td>
<td width="25%">3293</td>
<td width="25%">26.79%</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<h2>SPDY 다음 단계 : 어떻게 우리를 도울 수 있는 방법</h2>
<p>우리의 초기 결과는 좋지만, 우리는 그것들을 어떻게 현실 세계에 적용해야 할지 잘 모르겠다. 게다가 SPDY는 더 개선할 여지들이 있다. 예를 들면</p>
<ul>
<li>대역폭 효율성은 여전히 낮다. 전화망의 대역폭 효율이 90%에 근접한다고 하지만, 고속망의 효율은 약 32% 밖에 안된다.</li>
<li>SSL은 추가적인 지연시간과 도입에 대한 난관들을 가지고 있다. SSL 핸드셰이킹를 위한 추가적인 RTT, 암호화, 프락시에서의 캐싱 문제 등이다. 우리는 SSL에 더 적합하게할 일들이 있다.</li>
<li>우리의 패킷 손실율에 대한 실험결과로는 아직 결론을 내릴 수 었다. 패킷 손실율에 대한 연구들이 있었지만, 우리는 웹을 위한 현실적인 모델을 만들기 위한 충분한 데이터를 가지고 있지 않다. 패킷 손실율 시뮬레이션을 더 정교하게 할 수 있는 데이터들을 더 수집할 필요가 있다.</li>
<li>SPDY의 단일 커넥션은 연결이 끊겨서 복구할 경우 다수 컨넥션보다 때로는 성능이 낮을 수 있다. 특히 RTT가 매우 높을 때는 단일 커넥션보다 멀티플 커넥션이 빠를 수 있다. 언제 SPDY 클라이언트가 새로운 커넥션을 만들거나 기존 커넥션을 끊을지, 이것이 서버에 어떤 영향을 줄지를 더 고민할 필요가 있다.</li>
<li>서버는 우리가 만든 것보다 더 지능적으로 구현할 수 있을 것이다. 서버가 스트림을 생성하는 경우, 프리패칭 제안을 위해서 클라이언트 네트웍 정보를 수집하는 등의 케이스에 대해서 더 많은 연구가 필요하다.</li>
</ul>
<p>이런 문제에 도전하기 위해 당신이 참여하길 원한다면…</p>
<ul>
<li><a href="http://groups.google.com/group/chromium-discuss?pli=1" onclick="pageTracker._trackPageview('/outgoing/groups.google.com/group/chromium-discuss?pli=1&amp;referer=');">chrome-discuss discussion group</a> 으로 피드백, 코멘트, 제안, 아이디어를 보낸다.</li>
<li><a href="http://src.chromium.org/viewvc/chrome/trunk/src/net/spdy/" onclick="pageTracker._trackPageview('/outgoing/src.chromium.org/viewvc/chrome/trunk/src/net/spdy/?referer=');">Google Chrome client code</a> 에서 소스를 다운로드 받아서 빌드, 실행, 테스트 해보고</li>
<li>소스코드에 직접 개선을 한다.</li>
</ul>
<h2>SPDY에 대한 FAQ</h2>
<p><strong>Q: HTTP piplelining이 이미 응답시간에 대한 문제를 해결하지 않았나요?</strong></p>
<p>A: No. 파이프라이닝이 다수의 요청을 하나의 TCP 연결하에서 병렬로 보내는 것을 지원하고 있지만, 여전히 단일 스트림입니다. 스트립 내의 과정에서 지연이 발생하면(첫 요청이 long request이거나 패킷 손실이 발생하거나해서) 전체 스트림이 지연됩니다. 파이프라이닝은 적용이 어렵기도 해서 대부분의 주요 브라우저에서 기본적으로 비활성화된 채로 남아있지요.</p>
<p><strong>Q: SPDY는 HTTP를 대체하는 겁니까?</strong></p>
<p>A: 아니오. SPDY는 HTTP의 일부분을 대체할 뿐이고, HTTP를 확장합니다. 어플리케이션 계층의 최상위 레벨에서 요청-응답 프로토콜은 여전히 동일합니다. SPDY는 여전히 HTTP 메소드, 헤더 등을 사용합니다. 그러나 SPDY는 커넥션 관리와 데이터 전송 포맷 등의 프로토콜의 다른 부분을 오버라이드합니다.</p>
<p><strong>Q: 왜 이름을 이렇게 지었습니까?</strong></p>
<p>A: 우리는 이름이 &#8216;속도&#8217;의 의미를 내포하길 원했습니다. SPDY(SPeeDY라고 읽음)는 그에 부합할 뿐만 아니라 압축이 어떻게 속도 향상에 도움되는지를 보여주기도 하지요.</p>
<p><strong>Q: SPDY는 전송계층을 변경해야합니까?</strong></p>
<p>A: 전송계층의 보완이 지연을 줄일 수 있는지는 더 연구해봐야 합니다. 그러나 전송계층의 교체는 복잡한 일이고, 어플리케이션 레이어에서 TCP와 HTTP의 비효율적인 부분들을 극복할 수 있다면 현실 적용이 더 쉬울거라고 봅니다.</p>
<p><strong>Q: TCP는 네트웍의 혼잡이나 붕괴를 유발하지 않는지 오랜 시간 사용되면서 검증되었습니다. SPDY가 인터넷을 깨뜨릴 수도 있습니까?</strong></p>
<p>A: 아니오. SPDY는 TCP 위에서 작동하므로 TCP의 혼잡제어 알고리즘들의 혜택을 받습니다. 게다가 혼잡 제어 방법을 수정한 HTTP가 인터넷에서 동작하고 있습니다. 예를 들면, 오늘날의 HTTP 클라이언트는 하나의 서버에 6개의 연결을 동시에 엽니다. 그리고 어떤 HTTP 서버는 초기 congestion window를 4 패킷으로 증가시켰습니다. TCP가 각각의 연결들을 독립적으로 속도를 올릴 수 있기 때문에 서버는 초기부터 효과적으로 24패킷을 보낼 수 있습니다. 다수 연결에서 TCP의 slow-start 문제를 회피한 것이죠. 반면 SPDY는 하나의 연결 위에 다수의 스트림을 구현한 겁니다.</p>
<p><strong>Q: SCTP는 뭡니까?</strong></p>
<p>A: SCTP는 재미있는 대한 전송 프로토콜이에요. 이것은 하나의 커넥션 위에 다수의 스트림을 제공합니다. 그러나 이건 전송계층의 변경을 필요로 해서 가정용 라우터에까지 적용하려면 매우 어렵운 일이 되죠. 또한 SCTP는 은총알(silver bullet)이 아니에요. 서버와 클라이언트 사이의 채널을 효율적으로 사용하려면 어플리케이션 계층의 변경 역시 필요하죠.</p>
<p><strong>Q: BEEP은 뭡니까?</strong></p>
<p>A: BEEP은 비슷한 여러가지 기능을 제공하는 재미있는 프로토콜이지만, 이것은 페이지 로드 타임을 줄이는 것을 목표로 하지 않습니다. 그걸 가능하게 할 몇몇 기능이 없지요. BEEP은 바이너리 프레이밍 대신에 텍스트 기반의 프레이밍을 사용합니다. 이것은 확장성에 있어서 경쟁력있는 좋은 프로토콜이지만, 몇몇 보안 문제들도 있고 정확히 파싱하기가 어렵다는 문제도 있습니다.</p>
]]></content:encoded>
			<wfw:commentRss>http://oddpoet.net/archives/409/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tomcat에서 한글파라메터 인코딩 처리</title>
		<link>http://oddpoet.net/archives/62</link>
		<comments>http://oddpoet.net/archives/62#comments</comments>
		<pubDate>Thu, 04 Feb 2010 08:07:31 +0000</pubDate>
		<dc:creator>OddPoet</dc:creator>
				<category><![CDATA[개발]]></category>
		<category><![CDATA[웹]]></category>
		<category><![CDATA[EUC-KR]]></category>
		<category><![CDATA[ISO-8859-1]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[MS949]]></category>
		<category><![CDATA[Tomcat]]></category>
		<category><![CDATA[UTF8]]></category>
		<category><![CDATA[한글 인코딩]]></category>

		<guid isPermaLink="false">http://oddpoet.net/?p=62</guid>
		<description><![CDATA[요즘 대부분 웹페이지의 한글페이지는 UTF-8로 개발되는 추세지만, EUC-KR로 개발된 사이트를 UTF-8로 전환하려고 하는 경우 외부에서의 링크 등 때문에 Request의 파라메터에 대해서 UTF-8과 EUC-KR을 모두 지원해야할 경우가 종종 있습니다. 하지만 Java는 PHP 등과는 달리 String을 byte array로 보는게 아니라, byte array를 decoding해서 유니코드로 처리하므로 Tomcat의 character encoding 설정 만으로는 파라메터에 대해서 UTF-8과 EUC-KR을 모두 지원할 수 [...]]]></description>
			<content:encoded><![CDATA[<p>요즘 대부분 웹페이지의 한글페이지는 UTF-8로 개발되는 추세지만, EUC-KR로 개발된 사이트를 UTF-8로 전환하려고 하는 경우 외부에서의 링크 등 때문에 Request의 파라메터에 대해서 UTF-8과 EUC-KR을 모두 지원해야할 경우가 종종 있습니다. 하지만 Java는 PHP 등과는 달리 String을 byte array로 보는게 아니라, byte array를 decoding해서 유니코드로 처리하므로 Tomcat의 character encoding 설정 만으로는 파라메터에 대해서 UTF-8과 EUC-KR을 모두 지원할 수 없습니다. 이런 상황에서 써볼 수 있는 팁을 정리해봅니다. <span id="more-62"></span></p>
<h3>가정</h3>
<ol>
<li>한글 인코딩은  UTF-8, EUC-KR(MS949) 만 고려합니다.</li>
<li>EUC-KR과 MS949가 동일한 character set은 아니지만, MS949가 EUC-KR의 확장이므로 이 글에서는 동일하게 취급합니다.</li>
<li>UTF8에 대해서는 국내에서 일반적인 다국어 환경(한글/영어 등)만 가정합니다.</li>
</ol>
<h3>Byte array 얻어내기</h3>
<p>UTF-8 으로 encoding된 byte array를 EUC-KR로 decoding해서 String 객체를 생성해버리면(반대의 경우도 마찬가지), 최상위 비트가 이미 손실된 상황이므로 String 객체 만으로는 한글 인코딩을 바꿔 다시 디코딩할 방법이 없습니다. 따라서 request parameter의 한글인코딩을 판단하고, 그에 맞는 적절한 인코딩 방법으로 parameter에 대한 String 객체를 생성하기 위해서는 우선적으로 parameter에 대한 String 객체가 아닌 byte array를 얻어낼 수 있어야 합니다.</p>
<p>그런데 문제는 HttpServletRequest에 request에 대한 byte array를 얻어낼 인터페이스가 없다는 점이죠. GET method의 Request의 경우 URL 정보에서 직접 파라메터를 파싱해내는 방법도 적용해볼 수 있지만, POST method의 요청에서는 그것도 불가능합니다. 게다가 GET인 경우에도 IE계열의 경우에는 uri encoding도 하지 않은 채로 보내주는 막강센스를 보여주기 때문에 로직이 좀 짜증이 납니다.</p>
<p>그래서 byte array를 얻어내기 위해서 저는 request에 characterEncoding을 &#8220;ISO-8859-1&#8243; 를 사용합니다. 그렇게 하면, String에서 원래 byte array를 얻어낼 수 있습니다.</p>
<pre class='brush:java'>byte [] barray; // EUC-KR encoded byte array
...
String ko2 = new String(barray, "ISO-8859-1");
byte [] barray2 = ko.getBytes("ISO-8859-1");
// barray2 is same as barray.

String ko2 = new String(barray, "UTF-8");
byte [] barray3 = ko2.getBytes("UTF-8");
// barray3 may be not same as barray.</pre>
<p>tomcat의 경우 HttpServletRequest 객체에 처음으로 getParameter() 메소드를 호출할 때, paramter들의 파싱이 이루어지므로 첫번째 Filter에서 아래와 같은 코드로 전체 파라메터를 ISO-8859-1 로 decoding해서 String 객체를 생성하도록  할 수 있습니다.</p>
<pre class='brush:java'>if (!isMultiPart(request)) {
	request.setCharacterEncoding("ISO-8859-1"); // byte array으로 변환하기 위해 ISO-8859-1로 설정함.
	request.getParameter("dummy"); // parameter parsing을 위해서 getParameter 호출
}</pre>
<p>자~ 그럼 파라메터에서 byte array를 다음과 같은 형태로 얻어낼 수 있겠죠?</p>
<pre class='brush:java'>String query = request.getParameter("query");
byte [] bQuery = query.getBytes("ISO-8859-1"); // 원래의 byte array를 얻음.</pre>
<h3>UTF-8 인지 EUC-KR인지 판별하기</h3>
<p>byte array를 가져 왔으니 byte sequence로 부터 한글 인코딩을 판별해내야겠지요.</p>
<p>php 등의 스크립트 언어에서는 iconv 같은 함수들을 썼겠지만, 아시다시피 그런 방식으로는 한글 인코딩을 완전하게 판별할 수 없습니다. 왜냐하면 UTF-8 한글과 EUC-KR(MS949)와는 코드영역이 겹치는 부분이 있기 때문입니다. 예를 들면, &#8220;<em>천호</em>&#8220;, &#8220;<em>치킨</em>&#8221; 같은 단어들이죠.</p>
<ul>
<li>UTF-8 코드영역 : <a href="http://ko.wikipedia.org/wiki/UTF-8" onclick="pageTracker._trackPageview('/outgoing/ko.wikipedia.org/wiki/UTF-8?referer=');">http://ko.wikipedia.org/wiki/UTF-8</a></li>
<li>UTF-8 byte sequence에 대한 정규식 : <a href="http://www.w3.org/International/questions/qa-forms-utf-8.en.php" onclick="pageTracker._trackPageview('/outgoing/www.w3.org/International/questions/qa-forms-utf-8.en.php?referer=');">http://www.w3.org/International/questions/qa-forms-utf-8.en.php</a></li>
<li>MS949 코드영역 : <a href="http://ko.wikipedia.org/wiki/%EC%BD%94%EB%93%9C_%ED%8E%98%EC%9D%B4%EC%A7%80_949" onclick="pageTracker._trackPageview('/outgoing/ko.wikipedia.org/wiki/_EC_BD_94_EB_93_9C_ED_8E_98_EC_9D_B4_EC_A7_80_949?referer=');">http://ko.wikipedia.org/wiki/코드_페이지_949</a></li>
</ul>
<p>위의 링크를 참고하면, UTF-8의 <em>non-overlong 2-byte</em> 영역이 MS949의 코드 영역과 겹치는 걸 확인 할 수 있습니다. 즉, &#8220;<em>치킨</em>&#8220;이라는 단어의 경우 UTF8로 인코딩하면 <strong>EC.B9.98.ED.82.A8</strong> 인데 이 byte sequence는 UTF-8 인코딩에도 valid하며, MS949 인코딩에도 valid 합니다. 결론적으로 byte sequence 만으로는 UTF-8인지, EUC-KR인지 완벽하게 판별가능한 방법은 없다는 얘기입니다. (iconv 역시 마찬가지입니다.)</p>
<p>그래서 여기에 3번째 가정을 적용합니다. 위의 첫번째 링크(Wikipedia: UTF-8)의 내용 중에 아래와 같은 내용이 있습니다.</p>
<blockquote><p>그 다음 1920문자 &#8211; 발음 구별 기호가 붙은 라틴 문자, 그리스 문자, 키릴 문자, 콥트 문자, 아르메니아 문자, 히브리 문자, 아랍 문자 &#8211; 는 2바이트로 표시되며&#8230;</p></blockquote>
<p>UTF-8 코드영역에서 이 부분이 바로 <em>non-overlong 2-byte</em> 에 해당하는 부분입니다. 일반적으로 자주 쓰는 문자들은 아닌것 같죠? 이 코드 영역을 쓰지 않는다는 가정을 하면, 한글에 있어서는 완전하게 UTF-8과 EUC-KR 중 어떤 인코딩으로 encode된 byte array인지 판별가능합니다.</p>
<p>byte sequence에 대한 한글 UTF-8 여부를 판별하는 코드는 아래에 있습니다. 참고로 전체를 정규식으로 로직을 쓸 경우, 큰 byte array에 대해서 Stack overflow가 발생하기 때문에 아래와 같이 byte 별로 쪼개어 test했습니다.</p>
<pre class='brush:java'>
/**
 * 문자열이 UTF8 Character인지 검사하는 Utility Class.
 *


 * byte arry 및 최상위 비트가 보존된 iso-8859-1로 decoding 문자열에 대한 체크만 가능하다.
 * 한마디로, 이미 깨진 한글 따윈 검증할 수 없다.
 * 

 *


 * utf8 문자셋에 대한 정규식.
 * <br/>
 * MS949와 충돌나는 코드 영역 때문에, 2byte로 인코딩되는 문자들은 제외한다. (e.g. 치킨)
 * 한글 유니코드는 모두 /u0800 보다 큰 코드값에 배열되므로,
 * utf8 인코딩시 2바이트로 인코딩되는 일이 없다. (첫자끝, 한글자모도 동일함)
 * 물론, 이렇게 함으로써 해당 코드영역을 사용하는 타언어의 코드를 체크할 수 없다.
 * 

 *
 * 관련 정보 :
 * 	1. http://ko.wikipedia.org/wiki/UTF-8
 *  2. http://forum.standardmag.org/viewtopic.php?id=462
 *
 * @see http://www.w3.org/International/questions/qa-forms-utf-8.en.php
 *
 * @author oddpoet
 */
public final class UTF8KoreanChecker {
	/**
	 * Utility Class이므로 생성자를 막는다.
	 */
	private UTF8KoreanChecker() { }

	/**
	 * 주어진 byte array가 한글 UTF8 인코딩인지 체크한다.
	 *
	 * @param bytes bytes
	 * @return true/false
	 */
	public static boolean isUTF8Korean(byte[] bytes) {
		for (int i = 0; i < bytes.length;) {
			if (isAscii(bytes, i)) {
				i += 1; // 1byte 체크함.
				continue;

			/*
			 * 위에서 언급한 바처럼, UTF-8 인코딩의 2바이트 영역이 MS949와 겹치므로,
			 * 한글 UTF8 검증에는 사용하지 않는다.
			 * 게다가 한글 UTF8은 2바이트로 인코딩되는 경우가 없으므로,
			 * 한글에 한해서는 체크는 완전하게 가능하다.
			 */
			//} else if (isNonOverlong(bytes, i)) {
			//	i += 2;
			//	continue;
			//}

			} else if (isExcludeOverlogs(bytes, i)
				|| isExcludingSurrogates(bytes, i)
				|| isStraight(bytes, i)) {
				i += 3; // 3byte 체크함.
				continue;
			} else if (isPlane1to3(bytes, i)
				|| isPlane4to15(bytes, i)
				|| isPlane16(bytes, i)) {
				i += 4; // 3byte 체크함.
				continue;
			} else {
				return false;
			}
		}

		return true;
	}

	/**
	 * (1byte)ascii ([\\x09\\x0A\\x0D\\x20-\\x7E])
	 * @param bytes bytes
	 * @param index 체크시작할 바이트
	 * @return true/false
	 */
	private static boolean isAscii(byte[] bytes, int index) {
		return bytes[index] == (byte)0x09
			|| bytes[index] == (byte)0x0A
			|| bytes[index] == (byte)0x0D
			|| (bytes[index] >= (byte)0x20
				&#038;&#038; bytes[index] <= (byte)0x7E
			);
	}

	/**
	 * (3bytes) excluding overlogs (\\xE0[\\xA0-\\xBF][\\x80-\\xBF])
	 * @param bytes bytes
	 * @param index index
	 * @return true/false
	 */
	private static boolean isExcludeOverlogs(byte[] bytes, int index) {
		return index + 2 < bytes.length
			&#038;&#038; bytes[index] == (byte)0xE0
			&#038;&#038; (bytes[index + 1] >= (byte)0xA0
				&#038;&#038; bytes[index + 1] <= (byte)0xBF
			)
			&#038;&#038; (bytes[index + 2] >= (byte)0x80
				&#038;&#038; bytes[index + 2] <= (byte)0xBF
			);
	}

	/**
	 * (3bytes) straight ([\\xE1-\\xEC\\xEE\\xEF][\\x80-\\xBF]{2})
	 * @param bytes bytes
	 * @param index index
	 * @return true/false
	 */
	private static boolean isStraight(byte[] bytes, int index) {
		return index + 2 < bytes.length
				&#038;&#038; (
					(bytes[index] >= (byte)0xE1
						&#038;&#038; bytes[index] <= (byte)0xEC
					)
					|| bytes[index] == (byte)0xEE
					|| bytes[index] == (byte)0xEF
				)
				&#038;&#038; (bytes[index + 1] >= (byte)0x80
					&#038;&#038; bytes[index + 1] <= (byte)0xBF
				)
				&#038;&#038; (bytes[index + 2] >= (byte)0x80
					&#038;&#038; bytes[index + 2] <= (byte)0xBF
				);
	}

	/**
	 * (3bytes) excluding surrogates (\\xED[\\x80-\\x9F][\\x80-\\xBF])
	 * @param bytes bytes
	 * @param index index
	 * @return true/false
	 */
	private static boolean isExcludingSurrogates(byte[] bytes, int index) {
		return index + 2 < bytes.length
			&#038;&#038; (bytes[index] == (byte)0xED)
			&#038;&#038; (bytes[index + 1] >= (byte)0x80
				&#038;&#038; bytes[index + 1] <= (byte)0x9F
			)
			&#038;&#038; (bytes[index + 2] >= (byte)0x80
				&#038;&#038; bytes[index + 2] <= (byte)0xBF
			);
	}

	/**
	 * (4bytes)planes 1-3 (\\xF0[\\x90-\\xBF][\\x80-\\xBF]{2})
	 * @param bytes bytes
	 * @param index index
	 * @return true/false
	 */
	private static boolean isPlane1to3(byte[] bytes, int index) {
		return index + 3 < bytes.length
			&#038;&#038; (bytes[index] == (byte)0xF0)
			&#038;&#038; (bytes[index + 1] >= (byte)0x90
				&#038;&#038; bytes[index + 1] <= (byte)0xBF
			)
			&#038;&#038; (bytes[index + 2] >= (byte)0x80
				&#038;&#038; bytes[index + 2] <= (byte)0xBF
			)
			&#038;&#038; (bytes[index + 3] >= (byte)0x80
				&#038;&#038; bytes[index + 3] <= (byte)0xBF
			);
	}

	/**
	 * planes 4-15 ([\\xF1-\\xF3][\\x80-\\xBF]{3})
	 * @param bytes bytes
	 * @param index index
	 * @return true/false
	 */
	private static boolean isPlane4to15(byte[] bytes, int index) {
		return index + 3 < bytes.length // 4byte check
			&#038;&#038; (bytes[index] >= (byte)0xF1
				&#038;&#038; bytes[index] <= (byte)0xF3
			)
			&#038;&#038; (bytes[index + 1] >= (byte)0x80
				&#038;&#038; bytes[index + 1] <= (byte)0xBF
			)
			&#038;&#038; (bytes[index + 2] >= (byte)0x80
				&#038;&#038; bytes[index + 2] <= (byte)0xBF
			)
			&#038;&#038; (bytes[index + 3] >= (byte)0x80
				&#038;&#038; bytes[index + 3] <= (byte)0xBF
			);
	}

	/**
	 * (4bytes)plane 16 (\\xF4[\\x80-\\x8F][\\x80-\\xBF]{2})
	 * @param bytes bytes
	 * @param index index
	 * @return true/false
	 */
	private static boolean isPlane16(byte[] bytes, int index) {
		return index + 3 < bytes.length // 4byte check
			&#038;&#038; (bytes[index] >= (byte)0xF4)
			&#038;&#038; (bytes[index + 1] >= (byte)0x80
				&#038;&#038; bytes[index + 1] <= (byte)0x8F
			)
			&#038;&#038; (bytes[index + 2] >= (byte)0x80
				&#038;&#038; bytes[index + 2] <= (byte)0xBF
			)
			&#038;&#038; (bytes[index + 3] >= (byte)0x80
				&#038;&#038; bytes[index + 3] <= (byte)0xBF
			);
	}

	/**
	 * (2bytes)non-overlong ([\\xC2-\\xDF][\\x80-\\xBF])
	 * 이 코드 영역은 MS949와 겹치는 영역이므로, 한글 검증용으로 사용하지 않는다.
	 *
	 * UTF8 한글의 경우 2byte로 인코딩되는 경우가 없음.
	 *
	 * @param bytes bytes
	 * @param index index
	 * @return true/false
	 */
	/* 사용하지 않으므로 주석처리.
	private static boolean isNonOverlong(byte[] bytes, int index) {
		return index + 1 < bytes.length // 2byte check
			&#038;&#038; bytes[index] >= (byte)0xC2 &#038;&#038; bytes[index] <= (byte)0xDF
			&#038;&#038; bytes[index + 1] >= (byte)0x80 &#038;&#038; bytes[index + 1] <= (byte)0xBF;
	}
	*/
}
</pre>
<h3>정리</h3>
<p>byte array를 얻어서, 사용된 encoding을 판별하고 나면 아래와 같은 방법으로 적절한 encoding을 사용해서 한글 String 객체를 만들어 낼 수 있습니다.</p>
<pre class='brush:java'>String param = request.getParameter("param");
byte [] bytes = param.getBytes("ISO-8859-1");
String koparam;
if (UTF8KoreanChecker.isUTF8Korean(bytes)) {
	koparam = new String(bytes, "UTF-8");
} else {
	koparam = new String(bytes, "MS949");
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://oddpoet.net/archives/62/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>구글이 말하는 개방의 진짜 의미는?</title>
		<link>http://oddpoet.net/archives/43</link>
		<comments>http://oddpoet.net/archives/43#comments</comments>
		<pubDate>Mon, 01 Feb 2010 15:30:54 +0000</pubDate>
		<dc:creator>OddPoet</dc:creator>
				<category><![CDATA[웹]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[the meaning of open]]></category>
		<category><![CDATA[개방의 의미]]></category>

		<guid isPermaLink="false">http://oddpoet.net/?p=43</guid>
		<description><![CDATA[지난 2009년 12월에 구글의 제품관리 총괄 임원 조나단 로젠버그(Jonathn Rosenberg) 가 공식블로그를 통해 &#8216;The meaning of open&#8216; 이라는 글을 올렸습니다. 이 글은 구글 공식 한국블로그에서  &#8217;개방(Open)의 의미&#8216; 라는 제목으로도 번역되어 올라왔습니다. 구글이 가지고 있는 개방에 대한 철학을 Open technology, Open Information 측면에서 잘 설명하고 있는 글입니다. 구글이 Open이라는 철학으로 기술적인 부분에서나 정보에 대한 접근에 있어서나 사용자들과 개발자들에게 [...]]]></description>
			<content:encoded><![CDATA[<p>지난 2009년 12월에 구글의 제품관리 총괄 임원 조나단 로젠버그(Jonathn Rosenberg) 가 공식블로그를 통해 &#8216;<a href="http://googleblog.blogspot.com/2009/12/meaning-of-open.html" target="_blank" onclick="pageTracker._trackPageview('/outgoing/googleblog.blogspot.com/2009/12/meaning-of-open.html?referer=');">The meaning of open</a>&#8216; 이라는 글을 올렸습니다. 이 글은 구글 공식 한국블로그에서  &#8217;<a href="http://googlekoreablog.blogspot.com/2010/01/blog-post_6951.html" target="_blank" onclick="pageTracker._trackPageview('/outgoing/googlekoreablog.blogspot.com/2010/01/blog-post_6951.html?referer=');">개방(Open)의 의미</a>&#8216; 라는 제목으로도 번역되어 올라왔습니다. 구글이 가지고 있는 개방에 대한 철학을 Open technology, Open Information 측면에서 잘 설명하고 있는 글입니다.</p>
<p>구글이 Open이라는 철학으로 기술적인 부분에서나 정보에 대한 접근에 있어서나 사용자들과 개발자들에게 지지를 받는 IT기업임은 분명합니다. 그리고 그들의 말대로 Open이야말로 웹 전체의 가치를 높이고, 웹이 많은 사람들에게 도움이 될 수 있는 전략이라는 것도 맞는 이야기 입니다.</p>
<p>하지만 달리 바라보면 사용자들의 검색어와 컨텐츠를 광고주에게 연결해서 수익을 만들어내는 구글에게 있어서, Open이란 웹에 공유되는 정보들과 컨텐츠를 늘려 자신들의 가치를 높일 수 있는 <strong>궁극의 전략</strong>이기도 합니다. 다른 이들에게도 도움이 되겠지만, 구글에게는 아주 큰 수익이 되는거죠. <span id="more-43"></span></p>
<p>IE, Firefox, Safari, Opera 등이 신기능으로 경쟁을 하고 있을 때,  Chrome을 출시해서 갑자기 브라우저 성능(속도)을 이슈화시킨 이유가 무엇일까요? 페이지뷰의 증가와 광고수익이 비례한다는 가정을 하면, 그건 브라우저들의 전반적인 성능을 높여 사용자들의 단위시간당 페이지 소비량를 높이는 것이 구글의 수익에 도움이 되기 때문일겁니다.  구글은 이미 웹에서의 게임의 법칙을 주도하고 있는 회사이므로, 웹이 더 커질 수록, 사용자들의 페이지뷰가 많아질수록 수익은 늘어납니다. 조금 냉정하게 보면 &#8216;<em>더 많이 정보를 만들어내고 공유해라. 기술도 주마. 돈은 내가 벌테니</em>&#8216;&#8230; 이런 거죠. 안드로이드 역시 아이폰에 대항할 무기가 없는 H/W 제조사들을 위한 떡밥이자, 모바일에서도 게임의 법칙을 주도하겠다는 야심으로 만들어진 플랫폼이구요.</p>
<p><a href="http://www.appleforum.com/mac-column/58550-%EC%96%B8%EB%A1%A0%EC%9D%98-%EC%A0%81-%EA%B5%AC%EA%B8%80.html" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.appleforum.com/mac-column/58550-_EC_96_B8_EB_A1_A0_EC_9D_98-_EC_A0_81-_EA_B5_AC_EA_B8_80.html?referer=');">&#8220;언론의 적 구글&#8221;</a> 이라는 글에서  구글의 이해와 충돌하고 있는 신문사와 출판사들의 경우를 보면, Open이라는 그들의 철학이 다소 위선처럼 느껴지네요. (물론 이 예는 전세대 미디어가 인터넷 시대에 수익구조를 만들어내지 못하고 붕괴하는 모습으로도 볼 수 있지요. ^^ ) 몇일전 스티브 잡스가 &#8216;Don&#8217;t be evil&#8217;이라는 구글의 모토를 &#8216;bullshit&#8217;이라 욕한데에는 이러한 부분에 대한 지적이라 생각합니다. 애플은 iTunes를 통해 컨텐츠 사업자들과 수익을 나누고 있으니까요.</p>
<p>구글이라는 회사를 좋아하고 구글의 서비스를 삶의 일부로 사용하고 있지만, 가끔씩 구글은 이미  Big brother가 되어버린건 아닌지 하는 섬뜩한 생각이 듭니다. 구글에서 evil이라는 단어가 검색되지 않는 날이 온다면 &#8230; 그게 그때 이겠지요?</p>
]]></content:encoded>
			<wfw:commentRss>http://oddpoet.net/archives/43/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Flash, HTML5, 그리고 mobile</title>
		<link>http://oddpoet.net/archives/34</link>
		<comments>http://oddpoet.net/archives/34#comments</comments>
		<pubDate>Mon, 01 Feb 2010 05:43:17 +0000</pubDate>
		<dc:creator>OddPoet</dc:creator>
				<category><![CDATA[모바일]]></category>
		<category><![CDATA[웹]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[browser]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[HTML5]]></category>

		<guid isPermaLink="false">http://oddpoet.net/?p=34</guid>
		<description><![CDATA[HTML5에서 동영상 태그 지원, 2D drawing를 지원하게되면서 Adobe의 Flash같은 브라우저 플러그인 기반의 기술들의 미래에 대한 얘기가 작년에 회자되었는데요, 최근 유튜브의 HTML5 지원과 스티브 잡스의 발언으로 다시 이슈가 되고 있네요. HTML5 : 플래시와 실버라이트를 물리칠 수 있을까? 유튜브 : HTML5 비디오 지원 &#8211; video 태그 스티브잡스 &#8220;구글의 모토는 헛소리&#8230; 어도비는 게을러&#8221; Flash가 HTML5에 의해 완전히 대체될 [...]]]></description>
			<content:encoded><![CDATA[<p>HTML5에서 동영상 태그 지원, 2D drawing를 지원하게되면서 Adobe의 Flash같은 브라우저 플러그인 기반의 기술들의 미래에 대한 얘기가 작년에 회자되었는데요, 최근 유튜브의 HTML5 지원과 스티브 잡스의 발언으로 다시 이슈가 되고 있네요.</p>
<ul>
<li><a href="http://www.idg.co.kr/newscenter/common/newCommonView.do?newsId=56850" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.idg.co.kr/newscenter/common/newCommonView.do?newsId=56850&amp;referer=');">HTML5 : 플래시와 실버라이트를 물리칠 수 있을까?</a></li>
<li><a href="http://barosl.com/blog/entry/youtube-launches-html5-beta" target="_blank" onclick="pageTracker._trackPageview('/outgoing/barosl.com/blog/entry/youtube-launches-html5-beta?referer=');">유튜브 : HTML5 비디오 지원 &#8211; video 태그</a></li>
<li><a href="http://blog.hankyung.com/kim215/339488" target="_blank" onclick="pageTracker._trackPageview('/outgoing/blog.hankyung.com/kim215/339488?referer=');">스티브잡스 &#8220;구글의 모토는 헛소리&#8230; 어도비는 게을러&#8221;</a></li>
</ul>
<p>Flash가 HTML5에 의해 완전히 대체될 거라고는 생각하지 않습니다만,  최신버전의 웹브라우저들과 유튜브가  HTML5의 동영상태그를 지원하기 시작했다는 점에 웹에서 Flash의 입지는 줄어들게 될 것 같습니다. 게다가 아이폰이 모바일 웹 트래픽의 대부분을 점유하고 있는 시점에서,  애플이 모바일 환경에서의 Flash를 부정적으로 생각하고 있다는 점은 Flash의 미래를 불투명하게 하는 또다른 요소가 되고 있습니다. <span id="more-34"></span></p>
<p>옛날부터 사연이 많은 Apple과 Adobe의 관계를 생각할 때 Apple이 모바일 점유율을 믿고 기싸움을 하는 것으로 볼 수도 있습니다만, 사실 다른 플랫폼은 둘째치고 윈도우 환경에서도 Flash가 실행될때 소모하는 엄청난 리소스 점유율 등을 볼 때 모바일 웹환경에서 Flash는 지양해야할 기술이라고 생각합니다. 웹표준이 추구했던 바가 다양한 환경에서 동일한 정보접근성을 제공하는 데 있었다는 점을 생각하면, 브라우저 플러그인 기반의 기술들은 어느정도 한계를 가질 수 밖에 없으며 언젠가는 서서히 웹에서의 영역이 줄어들 수 밖에 없을 겁니다.</p>
<p>Flash가  그동안 지적되었던 성능이나 리소스 점유율의 문제에 효과적으로 대응하지 못했다는 점에서, 다분히 감정적인 반응으로 보이는 잡스의 &#8216;어도비는 게을러&#8217;라는 얘기도 개인적으로는 어느 정도 공감이 갑니다.</p>
<p>추후 웹에서 시장을 주도하는 기술이 어떤 것이 될지는 모르겠지만, 모바일 시장에서의 승자가 유리한 고지를 차지할 것 같습니다.</p>
]]></content:encoded>
			<wfw:commentRss>http://oddpoet.net/archives/34/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>구글 IE6 지원 중단, 그리나 한국의 웹은</title>
		<link>http://oddpoet.net/archives/11</link>
		<comments>http://oddpoet.net/archives/11#comments</comments>
		<pubDate>Sun, 31 Jan 2010 14:08:25 +0000</pubDate>
		<dc:creator>OddPoet</dc:creator>
				<category><![CDATA[웹]]></category>
		<category><![CDATA[browser]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[IE]]></category>
		<category><![CDATA[IE6]]></category>

		<guid isPermaLink="false">http://oddpoet.net/?p=11</guid>
		<description><![CDATA[구글이 올해 3월 1일부터 점진적으로 IE6에 대한 지원을 중단하기로 했다고 발표했습니다. 일단은 일부 서비스(Gmail, Google docs)에서 IE6가 지원가능 브라우저에서 제외되지만, 서서히 다른 서비스에서도 IE6는 지원목록에서 제외될 것 같습니다. IE6가 윈도우즈XP의 기본브라우저로 2001년에 발표되었으니 아마도 가장 오랜시간동안 현역생활을 한 웹브라우저일 것 같네요. 그러한 이유에는 MS가 오랫동안 업데이트 없이 방치했던 것도 있었지만, 윈도우즈 비스타의 출시지연과 시장에서의 실패 [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://googleenterprise.blogspot.com/2010/01/modern-browsers-for-modern-applications.html" target="_blank" onclick="pageTracker._trackPageview('/outgoing/googleenterprise.blogspot.com/2010/01/modern-browsers-for-modern-applications.html?referer=');">구글이 올해 3월 1일부터 점진적으로 IE6에 대한 지원을 중단하기로 했다고 발표했습니다.</a> 일단은 일부 서비스(Gmail, Google docs)에서 IE6가 지원가능 브라우저에서 제외되지만, 서서히 다른 서비스에서도 IE6는 지원목록에서 제외될 것 같습니다.</p>
<p>IE6가 윈도우즈XP의 기본브라우저로 2001년에 발표되었으니 아마도 가장 오랜시간동안 현역생활을 한 웹브라우저일 것 같네요. 그러한 이유에는 MS가 오랫동안 업데이트 없이 방치했던 것도 있었지만, 윈도우즈 비스타의 출시지연과 시장에서의 실패 등의 상황들도 IE7 보급이 더뎌졌던 이유도 있었지요. 아뭏든 IE6는 윈도우즈 XP의 수명만큼이나 오랫동안(9년) 사용되고 있으니, 현대적인 브라우저의 관점에서는 백발성성한  노장입니다. 그런 면에서 구글의 이번 IE6 지원 중단 발표는 &#8216;신은 죽었다&#8217;고 한 니체의 얘기만큼이나 선언적으로 중요한 계기가 되리라 생각합니다. 다른 유명한 웹서비스들도 서서히 지원을 중단하면서 자연스레 IE6는 역사 속으로 사라지겠지요. <span id="more-11"></span></p>
<p>그!러!나! 한국에서 IE6가 언제쯤 사라질 수 있을까를 생각해보면 암담합니다.</p>
<div id="attachment_14" class="wp-caption aligncenter" style="width: 585px"><a rel="attachment wp-att-14" href="http://oddpoet.net/archives/11/2009-browser-trend"><img class="size-full wp-image-14" title="2009-browser-trend" src="http://oddpoet.net/wp-content/uploads/2010/01/2009-browser-trend.png" alt="2009년 한국 브라우저 버전별 점유율" width="575" height="211" /></a><p class="wp-caption-text">2009년 한국 브라우저 버전별 점유율</p></div>
<p>위 차트는 <a href="http://trend.logger.co.kr/introduction.tsp" target="_blank" onclick="pageTracker._trackPageview('/outgoing/trend.logger.co.kr/introduction.tsp?referer=');">InternetTrend </a>에서 뽑은 2009년 브라우져 버전별 점유율입니다. IE와 그의 형제들이 98% 넘는 점유율을 보이고 있는데, 세계적으로 30% 가까운 점유율을 보인다는 Firefox의 경우 한국에서는 개발자들만 쓰는 모양입니다. <strong>50%가 넘는 IE6의 점유율이 매우 인상적입니다. </strong></p>
<div id="attachment_15" class="wp-caption aligncenter" style="width: 693px"><a rel="attachment wp-att-15" href="http://oddpoet.net/archives/11/statcounterglobal"><img class="size-full wp-image-15 " title="StatCounterGlobal" src="http://oddpoet.net/wp-content/uploads/2010/01/StatCounterGlobal.jpg" alt="2009 세계 브라우저별 점유율" width="683" height="400" /></a><p class="wp-caption-text">2009 세계 브라우저 버전별 점유율</p></div>
<p><a href="http://gs.statcounter.com/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/gs.statcounter.com/?referer=');">StatCounter</a> 에서 확인한 전세계의 브라우저 점유율 추이를 보면 IE6가 이미 20%이하로 떨어진 걸 확인할 수 있습니다. 구글 입장에서 충분히 지원중단을 감행할 만한 상황인 거죠. 하지만 IE6 점유율이 50%가 넘는 한국의 상황에서는 네이버, 다음, 싸이월드 등 한국 대표 포털들이 합심해서 IE6 지원중단을 발표한다고 해도 쉽지 않을 것 같습니다. 고객센터만 난리나는 거죠.</p>
<p>ActiveX로 되지도 않은 보안 운운하지 말고, 쥐라기 시대의 공룡들이나 썼을 법한 IE6의 사용중지 캠페인이라도 정부차원에서 추진하시는게 대한민국의 웹보안에 더 좋을 듯 합니다. ActiveX로 전국민PC 지켜주시려고 애쓰시는 건 알겠는데, 그런 삽질도 몇년째 하셨으면 이제 깨달으실 때 안됐나요? <a href="http://www.engadget.com/2010/01/16/germany-advises-its-citizens-to-say-nein-to-internet-explorer/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.engadget.com/2010/01/16/germany-advises-its-citizens-to-say-nein-to-internet-explorer/?referer=');">독일정부의 인터넷보안부서도 IE 쓰지 말랬다자나요</a>. IE7/8은 봐줄테니 <strong>IE6사용중지특별법</strong>이라도 만들면 안될까요?</p>
]]></content:encoded>
			<wfw:commentRss>http://oddpoet.net/archives/11/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

