File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>socket.io-chat-kr.html</title>
<meta name="generator" content="Haroopad 0.12.2" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>div.oembedall-githubrepos{border:1px solid #DDD;border-radius:4px;list-style-type:none;margin:0 0 10px;padding:8px 10px 0;font:13.34px/1.4 helvetica,arial,freesans,clean,sans-serif;width:452px;background-color:#fff}div.oembedall-githubrepos .oembedall-body{background:-moz-linear-gradient(center top,#FAFAFA,#EFEFEF) repeat scroll 0 0 transparent;background:-webkit-gradient(linear,left top,left bottom,from(#FAFAFA),to(#EFEFEF));border-bottom-left-radius:4px;border-bottom-right-radius:4px;border-top:1px solid #EEE;margin-left:-10px;margin-top:8px;padding:5px 10px;width:100%}div.oembedall-githubrepos h3{font-size:14px;margin:0;padding-left:18px;white-space:nowrap}div.oembedall-githubrepos p.oembedall-description{color:#444;font-size:12px;margin:0 0 3px}div.oembedall-githubrepos p.oembedall-updated-at{color:#888;font-size:11px;margin:0}div.oembedall-githubrepos ul.oembedall-repo-stats{border:medium none;float:right;font-size:11px;font-weight:700;padding-left:15px;position:relative;z-index:5;margin:0}div.oembedall-githubrepos ul.oembedall-repo-stats li{border:medium none;color:#666;display:inline-block;list-style-type:none;margin:0!important}div.oembedall-githubrepos ul.oembedall-repo-stats li a{background-color:transparent;border:medium none;color:#666!important;background-position:5px -2px;background-repeat:no-repeat;border-left:1px solid #DDD;display:inline-block;height:21px;line-height:21px;padding:0 5px 0 23px}div.oembedall-githubrepos ul.oembedall-repo-stats li:first-child a{border-left:medium none;margin-right:-3px}div.oembedall-githubrepos ul.oembedall-repo-stats li a:hover{background:none no-repeat scroll 5px -27px #4183C4;color:#FFF!important;text-decoration:none}div.oembedall-githubrepos ul.oembedall-repo-stats li:first-child a:hover{border-bottom-left-radius:3px;border-top-left-radius:3px}ul.oembedall-repo-stats li:last-child a:hover{border-bottom-right-radius:3px;border-top-right-radius:3px}span.oembedall-closehide{background-color:#aaa;border-radius:2px;cursor:pointer;margin-right:3px}div.oembedall-container{margin-top:5px;text-align:left}.oembedall-ljuser{font-weight:700}.oembedall-ljuser img{vertical-align:bottom;border:0;padding-right:1px}.oembedall-stoqembed{border-bottom:1px dotted #999;float:left;overflow:hidden;width:730px;line-height:1;background:none repeat scroll 0 0 #FFF;color:#000;font-family:Arial,Liberation Sans,DejaVu Sans,sans-serif;font-size:80%;text-align:left;margin:0;padding:0}.oembedall-stoqembed a{color:#07C;text-decoration:none;margin:0;padding:0}.oembedall-stoqembed a:hover{text-decoration:underline}.oembedall-stoqembed a:visited{color:#4A6B82}.oembedall-stoqembed h3{font-family:Trebuchet MS,Liberation Sans,DejaVu Sans,sans-serif;font-size:130%;font-weight:700;margin:0;padding:0}.oembedall-stoqembed .oembedall-reputation-score{color:#444;font-size:120%;font-weight:700;margin-right:2px}.oembedall-stoqembed .oembedall-user-info{height:35px;width:185px}.oembedall-stoqembed .oembedall-user-info .oembedall-user-gravatar32{float:left;height:32px;width:32px}.oembedall-stoqembed .oembedall-user-info .oembedall-user-details{float:left;margin-left:5px;overflow:hidden;white-space:nowrap;width:145px}.oembedall-stoqembed .oembedall-question-hyperlink{font-weight:700}.oembedall-stoqembed .oembedall-stats{background:none repeat scroll 0 0 #EEE;margin:0 0 0 7px;padding:4px 7px 6px;width:58px}.oembedall-stoqembed .oembedall-statscontainer{float:left;margin-right:8px;width:86px}.oembedall-stoqembed .oembedall-votes{color:#555;padding:0 0 7px;text-align:center}.oembedall-stoqembed .oembedall-vote-count-post{font-size:240%;color:#808185;display:block;font-weight:700}.oembedall-stoqembed .oembedall-views{color:#999;padding-top:4px;text-align:center}.oembedall-stoqembed .oembedall-status{margin-top:-3px;padding:4px 0;text-align:center;background:none repeat scroll 0 0 #75845C;color:#FFF}.oembedall-stoqembed .oembedall-status strong{color:#FFF;display:block;font-size:140%}.oembedall-stoqembed .oembedall-summary{float:left;width:635px}.oembedall-stoqembed .oembedall-excerpt{line-height:1.2;margin:0;padding:0 0 5px}.oembedall-stoqembed .oembedall-tags{float:left;line-height:18px}.oembedall-stoqembed .oembedall-tags a:hover{text-decoration:none}.oembedall-stoqembed .oembedall-post-tag{background-color:#E0EAF1;border-bottom:1px solid #3E6D8E;border-right:1px solid #7F9FB6;color:#3E6D8E;font-size:90%;line-height:2.4;margin:2px 2px 2px 0;padding:3px 4px;text-decoration:none;white-space:nowrap}.oembedall-stoqembed .oembedall-post-tag:hover{background-color:#3E6D8E;border-bottom:1px solid #37607D;border-right:1px solid #37607D;color:#E0EAF1}.oembedall-stoqembed .oembedall-fr{float:right}.oembedall-stoqembed .oembedall-statsarrow{background-image:url(http://cdn.sstatic.net/stackoverflow/img/sprites.png?v=3);background-repeat:no-repeat;overflow:hidden;background-position:0 -435px;float:right;height:13px;margin-top:12px;width:7px}.oembedall-facebook1{border:#1A3C6C solid 1px;padding:0;font:13.34px/1.4 verdana;width:500px}.oembedall-facebook2{background-color:#627add}.oembedall-facebook2 a{color:#e8e8e8;text-decoration:none}.oembedall-facebookBody{background-color:#fff;vertical-align:top;padding:5px}.oembedall-facebookBody .contents{display:inline-block;width:100%}.oembedall-facebookBody div img{float:left;margin-right:5px}div.oembedall-lanyard{-webkit-box-shadow:none;transition-delay:0s;transition-duration:.4000000059604645s;transition-property:width;transition-timing-function:cubic-bezier(0.42,0,.58,1);background-attachment:scroll;background-clip:border-box;background-color:transparent;background-image:none;background-origin:padding-box;border-bottom-width:0;border-left-width:0;border-right-width:0;border-top-width:0;box-shadow:none;color:#112644;display:block;float:left;font-family:'Trebuchet MS',Trebuchet,sans-serif;font-size:16px;height:253px;line-height:19px;margin-bottom:0;margin-left:0;margin-right:0;margin-top:0;max-width:none;min-height:0;outline-color:#112644;outline-style:none;outline-width:0;overflow-x:visible;overflow-y:visible;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;position:relative;text-align:left;width:804px}div.oembedall-lanyard .tagline{font-size:1.5em}div.oembedall-lanyard .wrapper{overflow:hidden;clear:both}div.oembedall-lanyard .split{display:inline}div.oembedall-lanyard .prominent-place .flag:active,div.oembedall-lanyard .prominent-place .flag:focus,div.oembedall-lanyard .prominent-place .flag:hover,div.oembedall-lanyard .prominent-place .flag:link,div.oembedall-lanyard .prominent-place .flag:visited{float:left;display:block;width:48px;height:48px;position:relative;top:-5px;margin-right:10px}div.oembedall-lanyard .place-context{font-size:.889em}div.oembedall-lanyard .prominent-place .sub-place{display:block}div.oembedall-lanyard .prominent-place{font-size:1.125em;line-height:1.1em;font-weight:400}div.oembedall-lanyard .main-date{color:#8CB4E0;font-weight:700;line-height:1.1}div.oembedall-lanyard .first{width:48.57%;margin:0 0 0 2.857%}html{height:100%}body{margin:0!important;padding:5px 20px 26px!important;background-color:#fff;font-family:"Lucida Grande","Segoe UI","Apple SD Gothic Neo","Malgun Gothic","Lucida Sans Unicode",Helvetica,Arial,sans-serif;font-size:.9em;overflow-x:hidden;overflow-y:auto}br,h1,h2,h3,h4,h5,h6{clear:both}hr.page{background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC) repeat-x 0 0;border:0 none;color:#ccc;height:3px;padding:0}hr.underscore{border:0 none!important;height:30px;padding:0;-webkit-margin-before:0;-webkit-margin-after:0}body >:first-child{margin-top:0!important}img.plugin{box-shadow:0 1px 3px rgba(0,0,0,.1);border-radius:3px}iframe{border:0}figure{-webkit-margin-before:0;-webkit-margin-after:0;-webkit-margin-start:0;-webkit-margin-end:0}kbd{border:1px solid #aaa;-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-moz-box-shadow:1px 2px 2px #ddd;-webkit-box-shadow:1px 2px 2px #ddd;box-shadow:1px 2px 2px #ddd;background-color:#f9f9f9;background-image:-moz-linear-gradient(top,#eee,#f9f9f9,#eee);background-image:-o-linear-gradient(top,#eee,#f9f9f9,#eee);background-image:-webkit-linear-gradient(top,#eee,#f9f9f9,#eee);background-image:linear-gradient(top,#eee,#f9f9f9,#eee);padding:1px 3px;font-family:inherit;font-size:.85em}.oembeded .oembed_photo{display:inline-block}img[data-echo]{margin:25px 0;width:100px;height:100px;background:#fff url(../img/ajax.gif) no-repeat center center}.spinner{display:inline-block;width:10px;height:10px;margin-bottom:-.1em;border:2px solid rgba(0,0,0,.5);border-top-color:transparent;border-radius:100%;-webkit-animation:spin 1s infinite linear;animation:spin 1s infinite linear}.spinner:after{content:'';display:block;width:0;height:0;position:absolute;top:-6px;left:0;border:4px solid transparent;border-bottom-color:rgba(0,0,0,.5);-webkit-transform:rotate(45deg);transform:rotate(45deg)}@-webkit-keyframes spin{to{-webkit-transform:rotate(360deg)}}@keyframes spin{to{transform:rotate(360deg)}}p.toc{margin:0!important}p.toc ul{padding-left:10px}p.toc>ul{padding:10px;margin:0 10px;display:inline-block;border:1px solid #ededed;border-radius:5px}p.toc li,p.toc ul{list-style-type:none}p.toc li{width:100%;padding:0;overflow:hidden}p.toc li a::after{content:"."}p.toc li a:before{content:"• "}p.toc h5{text-transform:uppercase}p.toc .title{float:left;padding-right:3px}p.toc .number{margin:0;float:right;padding-left:3px;background:#fff;display:none}.markdown{padding:20px}.markdown a{text-decoration:none;vertical-align:baseline}.markdown a:hover{text-decoration:underline}.markdown h1{font-size:2.2em;font-weight:700;margin:1.5em 0 1em}.markdown h2{font-size:1.8em;font-weight:700;margin:1.275em 0 .85em}.markdown h3{font-size:1.6em;font-weight:700;margin:1.125em 0 .75em}.markdown h4{font-size:1.4em;font-weight:700;margin:.99em 0 .66em}.markdown h5{font-size:1.2em;font-weight:700;margin:.855em 0 .57em}.markdown h6{font-size:1em;font-weight:700;margin:.75em 0 .5em}.markdown h1+p,.markdown h1:first-child,.markdown h2+p,.markdown h2:first-child,.markdown h3+p,.markdown h3:first-child,.markdown h4+p,.markdown h4:first-child,.markdown h5+p,.markdown h5:first-child,.markdown h6+p,.markdown h6:first-child{margin-top:0}.markdown hr{border:1px solid #ccc}.markdown p{margin:1em 0;word-wrap:break-word}.markdown ol{list-style-type:decimal}.markdown li{display:list-item;line-height:1.4em}.markdown blockquote{margin:1em 20px}.markdown blockquote>:first-child{margin-top:0}.markdown blockquote>:last-child{margin-bottom:0}.markdown blockquote cite:before{content:'\2014 \00A0'}.markdown .code{border-radius:3px;word-break:break-all;word-wrap:break-word}.markdown pre{border-radius:3px;word-break:break-all;word-wrap:break-word;overflow:auto}.markdown pre code{display:block}.markdown pre>code{border:1px solid #ccc;white-space:pre;padding:.5em;margin:0}.markdown code{border-radius:3px;word-break:break-all;word-wrap:break-word;border:1px solid #ccc;padding:0 5px;margin:0 2px}.markdown img{max-width:100%}.markdown table{padding:0;border-collapse:collapse;border-spacing:0}.markdown table tr td,.markdown table tr th{border:1px solid #ccc;margin:0;padding:6px 13px}.markdown table tr th{font-weight:700}.markdown table tr th>:first-child{margin-top:0}.markdown table tr th>:last-child{margin-bottom:0}.markdown table tr td>:first-child{margin-top:0}.markdown table tr td>:last-child{margin-bottom:0}.markdown em.underline{font-style:normal;text-decoration:underline}.markdown strong.highlight{color:#000;padding:0 5px;background-color:#fdffb6;-webkit-box-shadow:#fdffb6 0 0 5px;-moz-box-shadow:#fdffb6 0 0 5px;box-shadow:#fdffb6 0 0 5px}@import url(http://fonts.googleapis.com/css?family=Tauri);@import url(http://fonts.googleapis.com/css?family=Roboto+Condensed:300italic,400italic,700italic,400,300,700);.haroopad{padding:20px;color:#222;font-size:15px;font-family:'Roboto Condensed',Tauri,"Lucida Grande","Lucida Sans Unicode","Lucida Sans",AppleSDGothicNeo-Medium,'Segoe UI','Malgun Gothic',Verdana,Tahoma,sans-serif;background:#fff;-webkit-font-smoothing:antialiased}.haroopad a{color:#3269a0}.haroopad a:hover{color:#4183c4}.haroopad h2{border-bottom:1px solid #e6e6e6;line-height:1.7em}.haroopad h6{color:#777}.haroopad hr{border:1px solid #e6e6e6}.haroopad blockquote>code,.haroopad h1>code,.haroopad h2>code,.haroopad h3>code,.haroopad h4>code,.haroopad h5>code,.haroopad h6>code,.haroopad li>code,.haroopad p>code,.haroopad td>code{color:#000;background-color:#feecdd;border:1px solid #efdfd0}.haroopad pre>code{font-size:1em;font-family:Consolas,Inconsolata,Courier,monospace;letter-spacing:-1px;font-weight:700}.haroopad blockquote{border-left:4px solid #e6e6e6;padding:0 15px;color:#777}.haroopad table{background-color:#fafafa}.haroopad table tr td,.haroopad table tr th{border:1px solid #e6e6e6}.haroopad table tr:nth-child(2n){background-color:#f2f2f2}.hljs{display:block;overflow-x:auto;padding:.5em;background:#fdf6e3;color:#657b83;-webkit-text-size-adjust:none}.diff .hljs-header,.hljs-comment,.hljs-doctype,.hljs-javadoc,.hljs-pi,.hljs-template_comment,.lisp .hljs-string{color:#93a1a1}.css .hljs-tag,.hljs-addition,.hljs-keyword,.hljs-request,.hljs-status,.hljs-winutils,.method,.nginx .hljs-title{color:#859900}.hljs-command,.hljs-hexcolor,.hljs-link_url,.hljs-number,.hljs-phpdoc,.hljs-regexp,.hljs-rules .hljs-value,.hljs-string,.hljs-tag .hljs-value,.tex .hljs-formula{color:#2aa198}.css .hljs-function,.hljs-built_in,.hljs-chunk,.hljs-decorator,.hljs-id,.hljs-identifier,.hljs-localvars,.hljs-title,.vhdl .hljs-literal{color:#268bd2}.hljs-attribute,.hljs-class .hljs-title,.hljs-constant,.hljs-link_reference,.hljs-parent,.hljs-type,.hljs-variable,.lisp .hljs-body,.smalltalk .hljs-number{color:#b58900}.clojure .hljs-title,.css .hljs-pseudo,.diff .hljs-change,.hljs-attr_selector,.hljs-cdata,.hljs-header,.hljs-pragma,.hljs-preprocessor,.hljs-preprocessor .hljs-keyword,.hljs-shebang,.hljs-special,.hljs-subst,.hljs-symbol,.hljs-symbol .hljs-string{color:#cb4b16}.hljs-deletion,.hljs-important{color:#dc322f}.hljs-link_label{color:#6c71c4}.tex .hljs-formula{background:#eee8d5}footer{position:fixed;font-size:.8em;text-align:right;bottom:0;margin-left:-25px;height:20px;width:100%}</style>
</head>
<body class="markdown haroopad">
<h1 id="socket.io-chat"><a name="socket.io-chat" href="#socket.io-chat"></a>Socket.io Chat</h1><ul>
<li>from: <a href="http://socket.io/get-started/chat/">http://socket.io/get-started/chat/</a></li>
</ul><h2 id="시작하기:-채팅-애플리케이션"><a name="시작하기:-채팅-애플리케이션" href="#시작하기:-채팅-애플리케이션"></a>시작하기: 채팅 애플리케이션</h2><p>이 가이드에서 우리는 기본적인 채팅 애플리케이션을 만들 것입니다. Node.JS 또는 Socket.IO에 대한 거의 모르고 있어도 되기 때문에, 일반적인 지식 수준이라면 충분합니다.</p><h3 id="소개"><a name="소개" href="#소개"></a>소개</h3><p>채팅 애플리케이션을 만들 때, LAMP(PHP)같이 일반적인 웹 애플리케이션 스택으로 만드는 것은 전통적으로 매우 어려운 일이었습니다. 서버에서 변경사항을 가져오는 방식이고, 타임스탬프를 계속 추적하고, 생각보다 매우 많이 느립니다.</p><p>소켓은 전통적으로 클라이언트와 서버 간의 양방향 통신을 제공하는, 거의 모든 실시간 채팅 시스템이 설계되는 해법이었습니다.</p><p>서버는 메시지를 클라이언트에게 <em>푸시</em>할 수 있다는 것을 의미합니다.</p><p>채팅 메시지를 쓸 때마다, 서버가 그것을 다른 연결된 모든 클라이언트에게 푸시할 것이라는 개념입니다.</p><h3 id="웹-프레임워크"><a name="웹-프레임워크" href="#웹-프레임워크"></a>웹 프레임워크</h3><p>첫번째 목표는 폼과 메시지 목록을 제공하는 간단한 HTML 웹페이지를 만드는 것입니다. 우리는 Node.JS 웹 프레임워크 <code>express</code>를 사용할 것입니다. <a href="http://nodejs.org">Node.JS가 설치되어 있어야 합니다</a>.</p><p>우선 우리 프로젝트를 설명하는 <code>package.json</code> 매니페스트 파일을 만듭니다. 파일의 위치는 완전히 빈 디렉토리를 추천합니다 (저는 <code>chat-example</code> 이라고 하겠습니다).</p><pre><code class="lang-javascript hljs" data-origin="<pre><code class="lang-javascript">{
"name": "socket-chat-example",
"version": "0.0.1",
"description": "my first socket.io app",
"dependencies": {}
}
</code></pre>">{
"name": "socket-chat-example",
"version": "0.0.1",
"description": "my first socket.io app",
"dependencies": {}
}
</code></pre><p>이제, 필요한 것을 쉽게 <code>dependencies</code>에 추가하기 위해서, <code>npm install </code>를 사용하겠습니다:</p><pre><code data-origin="<pre><code>npm install express
</code></pre>">npm install express
</code></pre><p>express가 설치되었으므로 우리 애플리케이션을 만들기 위한 <code>index.js</code> 파일을 만들 수 있습니다.</p><pre><code class="lang-javascript hljs" data-origin="<pre><code class="lang-javascript">var app = require('express')();
var http = require('http').Server(app);
app.get('/', function(req, res){
res.send('&lt;h1&gt;Hello world&lt;/h1&gt;');
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
</code></pre>">var app = require('express')();
var http = require('http').Server(app);
app.get('/', function(req, res){
res.send('<h1>Hello world</h1>');
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
</code></pre><p>코드의 뜻은 다음과 같습니다:</p><ol>
<li>Express가 <code>app</code>을 초기화해서 여러분이 HTTP 서버를 제공할 수 있도록 함수 핸들러가 되게 합니다(2번째 줄).</li>
<li>경로 핸들러 <code>/</code>를 선언해서 웹사이트 홈에 접속할 주소를 선언합니다.</li>
<li>서버가 대기하는 포트를 3000번으로 정합니다.</li>
</ol><p>여러분이 <code>node index.js</code> 라고 실행하면 다음과 같이 보일 것입니다:
<img src="https://i.cloudup.com/-LsMcTduUg.png" alt=""></p><p>그리고 브라우저에서 <code><a href="http://localhost:3000">http://localhost:3000</a></code> 로 접속합니다:
<img src="https://i.cloudup.com/AOuGSHy7QM.png" alt=""></p><h3 id="html-제공하기"><a name="html-제공하기" href="#html-제공하기"></a>HTML 제공하기</h3><p>지금까지 <code>index.js</code>에서 <code>res.send</code>를 호출해서 HTML 문자열을 전달했습니다. 만약 전체 애플리케이션의 HTML 전체를 거기에 추가한다면 우리 코드를 알아보기 힘들게 될 것입니다. 대신, 우리는 <code>index.html</code> 파일을 만들어서 제공합니다.</p><p>우리의 경로 핸들러를 리팩터해서 대신 <code>sendfile</code>을 사용합니다:</p><pre><code data-origin="<pre><code>app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
</code></pre>">app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
</code></pre><p>그리고 <code>index.html</code> 파일을 다음과 같이 만듭니다:</p><pre><code class="lang-html hljs" data-origin="<pre><code class="lang-html">&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Socket.IO chat&lt;/title&gt;
&lt;style&gt;
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;ul id="messages"&gt;&lt;/ul&gt;
&lt;form action=""&gt;
&lt;input id="m" autocomplete="off" /&gt;&lt;button&gt;Send&lt;/button&gt;
&lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>"><!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
</code></pre><p>만약 프로세스를 재시작(Ctrl+C 입력하고 다시 <code>node index</code>)하고 페이지를 새로고침하면 이렇게 보일 것입니다:
<img src="https://i.cloudup.com/985FgSH2HQ.png" alt=""></p><h3 id="socket.io와-통합하기"><a name="socket.io와-통합하기" href="#socket.io와-통합하기"></a>Socket.IO와 통합하기</h3><p>Socket.IO는 두 가지로 이루어져 있습니다:</p><ul>
<li>Node.JS HTTP 서버에(또는 기반해서) 통합되는 서버: <code>socket.io</code></li>
<li>브라우저에서 실행되는 클라이언트 라이브러리: <code>socket.io-client</code></li>
</ul><p>개발하는 동안, <code>socket.io</code>는 클라이언트를 자동으로 제공해주기 때문에, 곧 알게 될 것입니다. 지금은 모듈 하나를 더 추가하기만 하면 됩니다:</p><pre><code data-origin="<pre><code>npm install socket.io
</code></pre>">npm install socket.io
</code></pre><p>모듈이 설치되고, <code>package.json</code>에 의존성이 추가될 것입니다. 이제 index.js 파일을 수정해서 다음을 추가합니다:</p><pre><code class="lang-javascript hljs" data-origin="<pre><code class="lang-javascript">var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res){
res.sendfile('index.html');
});
io.on('connection', function(socket){
console.log('a user connected');
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
</code></pre>">var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res){
res.sendfile('index.html');
});
io.on('connection', function(socket){
console.log('a user connected');
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
</code></pre><p>주목할 것은 <code>socket.io</code>의 새로운 인스턴스를 초기화해서, <code>http</code> (HTTP 서버) 객체에 전달했다는 것입니다. 그리고 들어오는 소켓을 위한 <code>connection</code> 이벤트를 대기시키고, 그것을 콘솔에 기록하게 했습니다.</p><p>이제 index.html에서 <code></body></code> 앞에 다음 코드 조각을 추가합니다:</p><pre><code class="lang-html hljs" data-origin="<pre><code class="lang-html">&lt;script src="/socket.io/socket.io.js"&gt;&lt;/script&gt;
&lt;script&gt;
var socket = io();
&lt;/script&gt;
</code></pre>"><script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
</script>
</code></pre><p><code>io</code>를 전역 변수로 노출하고, 연결하는 역할을 하는 <code>socket.io-client</code>를 불러오기 위한 전부입니다.</p><p><code>io()</code> 호출할 때 어떤 URL도 명시하지 않은 것을 명심하세요, 왜냐하면 기본적으로 페이지를 제공하는 호스트에 연결하려고 하기 때문입니다.</p><p>이제 서버와 웹 사이트를 재시작하면 콘솔에 "a user connected"라고 찍히는 것을 볼 수 있을 것입니다. 서버 창을 열어보면 다음처럼 여러 개의 메시지를 보게 될 것입니다.
<img src="https://i.cloudup.com/F5EBcTVDcd.png" alt=""></p><p>각 소켓은 특별히 <code>disconnect</code> 이벤트를 발생합니다:</p><pre><code class="lang-javascript hljs" data-origin="<pre><code class="lang-javascript">io.on('connection', function(socket){
console.log('a user connected');
socket.on('disconnect', function(){
console.log('user disconnected');
});
});
</code></pre>">io.on('connection', function(socket){
console.log('a user connected');
socket.on('disconnect', function(){
console.log('user disconnected');
});
});
</code></pre><p>그리고 여러 번 새로 고침하면 다음과 같은 결과를 볼 것입니다:</p><p><img src="https://i.cloudup.com/bOmy6xrJmi.png" alt=""></p><h3 id="이벤트-보내기"><a name="이벤트-보내기" href="#이벤트-보내기"></a>이벤트 보내기</h3><p>Socket.IO의 중심 사상은 여러분이 원하는 어떤 데이터이든지, 어떤 이벤트 형태로라도 보내고 받을 수 있다는 것입니다. JSON같이 형태도 가능하고, <a href="http://socket.io/blog/introducing-socket-io-1-0/#binary">바이너리 데이터</a> 역시 지원됩니다.</p><p>사용자가 메시지를 타이핑할 때 서버가 그것을 채팅 메시지 이벤트로 가져갈 수 있도록 만들어 봅시다. index.html에 있는 스크립트 섹션은 다음과 같이 보일 것입니다:</p><pre><code class="lang-html hljs" data-origin="<pre><code class="lang-html">&lt;script src="https://cdn.socket.io/socket.io-1.2.0.js"&gt;&lt;/script&gt;
&lt;script src="http://code.jquery.com/jquery-1.11.1.js"&gt;&lt;/script&gt;
&lt;script&gt;
var socket = io();
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
&lt;/script&gt;
</code></pre>"><script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
var socket = io();
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
</script>
</code></pre><p>그리고 <code>index.js</code> 에서 우리는 <code>chat message</code> 이벤트를 출력합니다:</p><pre><code data-origin="<pre><code>io.on('connection', function(socket){
socket.on('chat message', function(msg){
console.log('message: ' + msg);
});
});
</code></pre>">io.on('connection', function(socket){
socket.on('chat message', function(msg){
console.log('message: ' + msg);
});
});
</code></pre><p>결과는 다음 영상과 같을 것입니다:</p><p><video autoplay="" loop="" width="100%"><source src="https://i.cloudup.com/transcoded/zboNrGSsai.mp4"></video></p><h3 id="브로드캐스팅하기"><a name="브로드캐스팅하기" href="#브로드캐스팅하기"></a>브로드캐스팅하기</h3><p>다음 목표는 서버에서 다른 사용자들에게 이벤트를 전송하는 것입니다.</p><p>모든 사람에게 이벤트를 보내기 위해서, Socket.IO는 <code>io.emit</code>을 제공합니다:</p><pre><code class="lang-javascript hljs" data-origin="<pre><code class="lang-javascript">io.emit('some event', { for: 'everyone' });
</code></pre>">io.emit('some event', { for: 'everyone' });
</code></pre><p>만약 여러분이 특정 소켓을 제외하고 모든 사람에게 메시지를 보내려고 한다면, <code>broadcast</code> 플래그를 사용합니다:</p><pre><code data-origin="<pre><code>io.on('connection', function(socket){
socket.broadcast.emit('hi');
});
</code></pre>">io.on('connection', function(socket){
socket.broadcast.emit('hi');
});
</code></pre><p>이번에는, 단순히 하기 위해서 우리는 보낸 사람을 포함해서 모든 사람에게 메시지를 보내겠습니다.</p><pre><code data-origin="<pre><code>io.on('connection', function(socket){
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
});
</code></pre>">io.on('connection', function(socket){
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
});
</code></pre><p>그리고 클라이언트 쪽에서 <code>chat message</code>이벤트를 받았을 때 페이지에 표시합니다. 클라이언트 쪽의 자바스크립트 코드는 이제 이렇게 됩니다:</p><pre><code data-origin="<pre><code>&lt;script&gt;
var socket = io();
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
socket.on('chat message', function(msg){
$('#messages').append($('&lt;li&gt;').text(msg));
});
&lt;/script&gt;
</code></pre>"><script>
var socket = io();
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
socket.on('chat message', function(msg){
$('#messages').append($('<li>').text(msg));
});
</script>
</code></pre><p>그리고 우리의 채팅 애플리케이션을 완성했는데, 코드가 20줄 정도입니다! 대박! 이렇게 보일 것입니다:</p><p><video autoplay="" loop="" width="100%"><source src="https://i.cloudup.com/transcoded/J4xwRU9DRn.mp4"></video></p><h3 id="과제"><a name="과제" href="#과제"></a>과제</h3><p>애플리케이션을 개선할 몇 가지 아이디어들입니다:</p><ul>
<li>사용자가 연결되거나 끊어졌을 때 접속자들에게 브로드캐스트 메시지를 보내기</li>
<li>닉네임 지원 기능 추가하기</li>
<li>보내는 사람은 자신의 메시지를 다시 보지 않기. 대신 엔터키를 누르는 순간 바로 보이게 만들기</li>
<li>“{user} 입력중..” 기능 추가하기</li>
<li>누가 온라인인지 보여주기</li>
<li>프라이빗 메시지 기능 추가하기</li>
<li>여러분이 개선한 것을 공유하기!</li>
</ul><h3 id="이-예제-구하기"><a name="이-예제-구하기" href="#이-예제-구하기"></a>이 예제 구하기</h3><p>GitHub <a href="https://github.com/socketio/chat-example">여기</a>에서 찾을 수 있습니다.</p><pre><code data-origin="<pre><code>$ git clone https://github.com/socketio/chat-example
</code></pre>">$ git clone https://github.com/socketio/chat-example
</code></pre>
<footer style="position:fixed; font-size:.8em; text-align:right; bottom:0px; margin-left:-25px; height:20px; width:100%;">generated by <a href="http://pad.haroopress.com" target="_blank">haroopad</a></footer>
<div id="fb-root"></div>
<script>
(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s);
js.id = id;
js.src = "//connect.facebook.net/ko_KR/sdk.js#xfbml=1&appId=1417763368476376&version=v2.0";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>
<div class="fb-comments" data-href="https://okdevtv.com/kr/socket.io-chat-kr.html" data-width="630" data-numposts="5" data-colorscheme="light"></div>
</section>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-DGMC27QNFQ"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-DGMC27QNFQ');
</script>
</html>