<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Program Factory</title>
    <link>https://program-factory.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 23 Jun 2026 21:29:50 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>알터.</managingEditor>
    <item>
      <title>4. STUN이란</title>
      <link>https://program-factory.tistory.com/8</link>
      <description>&lt;p&gt;홀펀칭으로 클라이언트간 연결을 하기위해서는 NAT환경마다 조금씩 방법이 다르다.&lt;/p&gt;
&lt;p&gt;NAT는 4종류로 나눌 수 있다.&lt;/p&gt;
&lt;p&gt;1. Full Cone NAT&lt;/p&gt;
&lt;p&gt;2. Restricted Cone NAT&lt;/p&gt;
&lt;p&gt;3. Port Restricted Cone NAT&lt;/p&gt;
&lt;p&gt;4. Symmetric NAT&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Full Cone&lt;/b&gt;은 별도의 IP/Port를 검증하지않고 내부에 있는 PC가 서버와 통신을 할경우 생성된 Public IP/Port를 통해 외부와 계속 통신할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Restricted Cone&lt;/b&gt;은 Full Cone방식에서 IP검증이 추가 되었다. NAT Table이 생성될 때 사용된 목적지 IP에 대해서만 허용된다. 다른 서버에서 해당 IP/Port를 사용하지못한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Port Restricted Cone&lt;/b&gt;은 Restricted Cone에서 Port 검증까지 추가 되었다. IP만이아니라 같은 Port로 통신이 되어야한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Symmetric&lt;/b&gt;은 서버의 주소가 다를경우 전혀 다른 Port로 NAT Table이 생성된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위와 같이 NAT종류가 다양해 그냥 연결을 시도하면 장소에따라 연결 되기도 하고 안되기도하는 상황이 생긴다.&lt;/p&gt;
&lt;p&gt;따라서 Relay Server의 경우 NAT의 종류 먼저 알아야하며, 이문제를 해결할 수 있는 방법은 STUN이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;STUN(Session Traversal Utilities for NAT)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;STUN은 IETF RFC 5389에 정의된 네트워크 프로토콜 포맷이다. 위에 정리된 NAT환경을 파악하기위해 사용된다.&lt;/p&gt;
&lt;p&gt;스턴은 다음과 같은 과정을 거쳐 NAT환경을 알아낸다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Untitled Diagram.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MdrSA/btqzwumwusc/EOsgXpxWrJ92gcXVfQezD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MdrSA/btqzwumwusc/EOsgXpxWrJ92gcXVfQezD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MdrSA/btqzwumwusc/EOsgXpxWrJ92gcXVfQezD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMdrSA%2Fbtqzwumwusc%2FEOsgXpxWrJ92gcXVfQezD0%2Fimg.png&quot; data-filename=&quot;Untitled Diagram.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Project1 - FileTransfer</category>
      <author>알터.</author>
      <guid isPermaLink="true">https://program-factory.tistory.com/8</guid>
      <comments>https://program-factory.tistory.com/8#entry8comment</comments>
      <pubDate>Mon, 4 Nov 2019 16:08:45 +0900</pubDate>
    </item>
    <item>
      <title>3. Hole Punching이란</title>
      <link>https://program-factory.tistory.com/7</link>
      <description>&lt;p&gt;NAT 환경에서 P2P 연결을 위해서는 HolePunching을 사용해야한다.&lt;/p&gt;
&lt;p&gt;관련자료는 &lt;a href=&quot;https://www.netmanias.com/ko/post/blog/6263/nat-network-protocol-p2p/p2p-nat-nat-traversal-technic-rfc-5128-part-2-udp-hole-punching&quot;&gt;https://www.netmanias.com/ko/post/blog/6263/nat-network-protocol-p2p/p2p-nat-nat-traversal-technic-rfc-5128-part-2-udp-hole-punching&lt;/a&gt;를 참고하였다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;홀펀칭(Hole Punching)은 NAT상황에서 P2P연결을 할때 사용되는 기술이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;P2P&lt;span style=&quot;color: #333333;&quot;&gt;(Peer to Peer)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;흔히 스타크래프트와 같은 조금 오래된 게임의 경우 P2P로 연결되어 게임이 진행된다.&lt;/p&gt;
&lt;p&gt;서버를 통해서 데이터를 주고 받는것이 아니라 사용자 간에 연결을 구성하는 것을 P2P라고 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;그림1.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sJhjY/btqzaYJjK58/UYjAxul3Sz8EXaMxhgKGlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sJhjY/btqzaYJjK58/UYjAxul3Sz8EXaMxhgKGlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sJhjY/btqzaYJjK58/UYjAxul3Sz8EXaMxhgKGlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsJhjY%2FbtqzaYJjK58%2FUYjAxul3Sz8EXaMxhgKGlk%2Fimg.png&quot; data-filename=&quot;그림1.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;일반적으로 P2P연결을 하기위해선 서로의 IP와 Port를 알아야 연결을 할 수 있다.&lt;/p&gt;
&lt;p&gt;하지만 가정집의 경우 NAT로 구성되어 있어 쉽게 연결할 수 없다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;NAT&lt;span style=&quot;color: #333333;&quot;&gt;(Network Address Translation)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;요즘 가정집의 경우 유무선 공유기는 필수로 존재한다. 공유기가 있으면 하나의 인터넷으로 PC, 스마트폰, TV등 각종 전자기기에서 인터넷을 할 수 있게 된다. 이것을 가능하게 해주는 기술이 NAT이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;쉽게말해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;NAT는 공인 IP 하나를 가지고 여러개의 사설 IP와 연결해주는 기술을 말한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;그림2.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JbKTZ/btqzb8cWjC9/3SiBvKOkM9kKZ2ovb2IKEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JbKTZ/btqzb8cWjC9/3SiBvKOkM9kKZ2ovb2IKEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JbKTZ/btqzb8cWjC9/3SiBvKOkM9kKZ2ovb2IKEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJbKTZ%2Fbtqzb8cWjC9%2F3SiBvKOkM9kKZ2ovb2IKEK%2Fimg.png&quot; data-filename=&quot;그림2.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;공인IP의 경우 고유의 IP로 중복되지 않지만 사설IP의 경우 중복된 IP가 대부분이다. 이름 그대로 사설에서만 사용할 수 있는 IP인 것이다. 그렇기때문에 사설IP를 기반으로 네트워크 통신은 불가능하며 P2P연결도 불가능하게 된다.&lt;/p&gt;
&lt;p&gt;이러한 문제를 해결하기 위해 나온것이 Hole Punching이라는 기술이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;홀펀칭&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;철심 파일에 종이를 깔끔하게 꽂기 위해서 구멍을 내는 도구를 펀치라고 부른다. 네트워크의 막힌부분에 구멍을 낸다. 라는 의미로 홀펀칭이라고 이름이 지어졌다.&lt;/p&gt;
&lt;p&gt;홀펀칭은 NAT상황에서 P2P연결시에 필요하다. NAT는 막힌 벽이고 그것을 뚫어 P2P를 연결하는 것이 홀펀칭인 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;홀펀칭은 사용자만있어서는 구현할 수 없다. 중간에서 다리 역할을 해주는 Relay서버가 필요하다.&lt;/p&gt;
&lt;p&gt;언뜻 보면 P2P가 아닌 서버/클라이언트 구조처럼 보일 수 있지만 Relay서버는 연결시 다리역할을 할뿐 데이터 전송에 관여하지는 않는다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;그림4.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dMWB3m/btqzb8RVw6a/7JgzGBzuFw2FMVRGfG5Wmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dMWB3m/btqzb8RVw6a/7JgzGBzuFw2FMVRGfG5Wmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dMWB3m/btqzb8RVw6a/7JgzGBzuFw2FMVRGfG5Wmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdMWB3m%2Fbtqzb8RVw6a%2F7JgzGBzuFw2FMVRGfG5Wmk%2Fimg.png&quot; data-filename=&quot;그림4.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;처음엔 서버/클라이언트 방식과 같이 양측 모두 서버로 접속을 시도한다. 그러면 서버에선 접속된 클라이언트들의 정보를 가지고 클라이언트간 터널을 만들어주고 이 터널을 기반으로 통신하게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;그림5.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H0BoI/btqzcLa8vt8/b5M9JWKCDX9hPFFU68HLeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H0BoI/btqzcLa8vt8/b5M9JWKCDX9hPFFU68HLeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H0BoI/btqzcLa8vt8/b5M9JWKCDX9hPFFU68HLeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH0BoI%2FbtqzcLa8vt8%2Fb5M9JWKCDX9hPFFU68HLeK%2Fimg.png&quot; data-filename=&quot;그림5.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이렇게 터널을 연결하여 NAT환경에서 P2P구조를 생성하고 통신이 가능하게된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Project1 - FileTransfer</category>
      <author>알터.</author>
      <guid isPermaLink="true">https://program-factory.tistory.com/7</guid>
      <comments>https://program-factory.tistory.com/7#entry7comment</comments>
      <pubDate>Fri, 18 Oct 2019 16:26:22 +0900</pubDate>
    </item>
    <item>
      <title>2. 관련 기술 조사</title>
      <link>https://program-factory.tistory.com/6</link>
      <description>&lt;p&gt;P2P를 통한 File Transfer를 만들기위해서 필요한 기술을 조사해봤다.&lt;/p&gt;
&lt;p&gt;구글에서 찾아본 예시는 대부분 Wifi로 Local 에서 파일전송, 공인IP를 이용한 방법 등이 대부분이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Wifi를 이용한 방법은 같은곳에 있을땐 참 좋은방법이지만, 멀리떨어져 다른 네트워크를 사용하면 사용할 수 없는 방법이다..&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;공인IP를 사용할경우 멀리서도 파일전송이 가능해서 좋다. 다만 스마트폰의 모바일 데이터는 공인IP가 아닌 사설IP를 받아온다.. 따라서 사용할 수 없는 방법이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그외 P2P연결에 대한 방법을 찾다가 홀펀칭(Hole Punching)이라는 연결 기술을 찾을 수 있었다.&lt;/p&gt;
&lt;p&gt;NAT - NAT 환경에서 사용할 수 있는 방법이라 적합한 기술이라 판단되어 사용하기로 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;파일 전송은 다른 통신에서도 가장 많이 사용되는 소켓을통해 구현 할 것이다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;소켓을 사용함으로써 다른 프로그램 제작시에도 도움될것이라 생각했기 때문에 선택했다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Project1 - FileTransfer</category>
      <author>알터.</author>
      <guid isPermaLink="true">https://program-factory.tistory.com/6</guid>
      <comments>https://program-factory.tistory.com/6#entry6comment</comments>
      <pubDate>Fri, 18 Oct 2019 14:44:39 +0900</pubDate>
    </item>
    <item>
      <title>1. 개요</title>
      <link>https://program-factory.tistory.com/5</link>
      <description>&lt;p&gt;파일 전송에는 여러가지 방법이 있고 쓰임새도 다양하다.&lt;/p&gt;
&lt;p&gt;간단하게는 친구와 사진공유 부터 업무상 문서 공유 영상, 프로그램등 다양한 파일을 전송하거나 받기도 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;흔히 이메일, 웹 클라우드 또는 카카오톡, 텔레그렘과 같은 메신져를 이용하여 파일을 주고받는다.&lt;/p&gt;
&lt;p&gt;하지만 해당 방법들에는 공통적인 단점이 있다.&lt;/p&gt;
&lt;p&gt;서버에 파일을 올리고 받고.. 시간 소모도 있고 일정기간이지만 서버의 리소스를 차지하게 된다.&lt;/p&gt;
&lt;p&gt;이러한 부분을 신경쓰지 않기 위해선 P2P통신을 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이미 다양한 P2P File Transfer 서비스가 운영되고 있지만 요즘 사용자에게 PC보다 더 친숙한 안드로이드 스마트폰을 타겟으로 직관적인 어플리케이션을 만들어보고 싶다는 생각을 하게 되었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;안드로이드 어플리케이션은 대표적으로 2가지 언어를 사용한다.&amp;nbsp; Java 또는 Kotlin. 그 중 구글이 적극적으로 밀고있는 Kotlin 을 사용하기로 하여 프로젝트를 진행하기로 결정했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGihC2/btqy7JMqhDy/1fIdwMJegmVBQV2pc0mDGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGihC2/btqy7JMqhDy/1fIdwMJegmVBQV2pc0mDGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGihC2/btqy7JMqhDy/1fIdwMJegmVBQV2pc0mDGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGihC2%2Fbtqy7JMqhDy%2F1fIdwMJegmVBQV2pc0mDGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Project1 - FileTransfer</category>
      <author>알터.</author>
      <guid isPermaLink="true">https://program-factory.tistory.com/5</guid>
      <comments>https://program-factory.tistory.com/5#entry5comment</comments>
      <pubDate>Fri, 18 Oct 2019 13:21:53 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript]확인, 취소 Confirm Dialog 띄우기</title>
      <link>https://program-factory.tistory.com/4</link>
      <description>&lt;p&gt;Javascript를 이용한 Confirm Dialog를 띄우는 방법입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;HTML 소스&lt;/p&gt;
&lt;pre class=&quot;brush: xml;&quot;&gt;&amp;lt;body&amp;gt;
  &amp;lt;button id=&quot;button&quot;&amp;gt;confirm&amp;lt;/button&amp;gt;
  &amp;lt;h5 id=&quot;text&quot;&amp;gt;취소&amp;lt;/h5&amp;gt;
&amp;lt;/body&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Javascript 소스&lt;/p&gt;
&lt;pre class=&quot;brush: js;&quot;&gt;&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
    document.getElementById(&quot;button&quot;).onclick = function() {
      var bool = confirm(&quot;yes or no&quot;);
      var text = document.getElementById(&quot;text&quot;);
      if (bool) {
        text.innerHTML = &quot;확인&quot;;
      } else {
        text.innerHTML = &quot;취소&quot;;
      }
    }
&amp;lt;/script&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;결과&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999502395B97440309&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999502395B97440309&quot; width=&quot;500&quot; height=&quot;114&quot; filename=&quot;confirmDialog.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;소스 및 예제페이지 확인&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;button class=&quot;linkBtn&quot; onclick=&quot;window.open('https://jsfiddle.net/tdwaz1b5/4/')&quot;&gt;페이지 이동&lt;/button&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Web</category>
      <author>알터.</author>
      <guid isPermaLink="true">https://program-factory.tistory.com/4</guid>
      <comments>https://program-factory.tistory.com/4#entry4comment</comments>
      <pubDate>Tue, 11 Sep 2018 13:28:35 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript/jQuery]버튼 클릭, 더블클릭 이벤트</title>
      <link>https://program-factory.tistory.com/3</link>
      <description>&lt;p&gt;Javascript와 jQuery를 이용한 클릭, 더블클릭 이벤트 소스입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;HTML소스&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;brush: xml;&quot;&gt;&amp;lt;body&amp;gt;
  &amp;lt;button id=&quot;click&quot;&amp;gt;Click&amp;lt;/button&amp;gt;
  &amp;lt;button id=&quot;dblclick&quot;&amp;gt;doubleClick&amp;lt;/button&amp;gt;
&amp;lt;/body&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Javascript 소스&lt;/p&gt;
&lt;pre class=&quot;brush: js;&quot;&gt;&amp;lt;script src=&quot;http://code.jquery.com/jquery-1.4.4.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
    $(document).ready(function() {
      $(&quot;#click&quot;).click(function() {
        alert(&quot;click&quot;);
      });
      $(&quot;#dblclick&quot;).dblclick(function() {
        alert(&quot;double click&quot;);
      });
    });
&amp;lt;/script&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;결과&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9956623E5B908B781C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9956623E5B908B781C&quot; width=&quot;500&quot; height=&quot;182&quot; filename=&quot;DoubleClick.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;소스 및 예제페이지 확인&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;button class=&quot;linkBtn&quot; onclick=&quot;window.open('https://jsfiddle.net/3zj2koxp/2/')&quot;&gt;페이지 이동&lt;/button&gt;&lt;/p&gt;</description>
      <category>Web</category>
      <author>알터.</author>
      <guid isPermaLink="true">https://program-factory.tistory.com/3</guid>
      <comments>https://program-factory.tistory.com/3#entry3comment</comments>
      <pubDate>Thu, 6 Sep 2018 11:09:53 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript/jQuery]Table 특수키(Ctrl, Shift)를 이용한 다중선택</title>
      <link>https://program-factory.tistory.com/2</link>
      <description>&lt;p&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;Javascript와 jQuery를 사용한 Table 다중 선택 소스입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;html Table 생성&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;brush: xml;&quot;&gt;&amp;lt;body&amp;gt;
  &amp;lt;table class=&quot;selectTable&quot;&amp;gt;
    &amp;lt;thead&amp;gt;
      &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;title1&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;title2&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;title3&amp;lt;/td&amp;gt;
      &amp;lt;/tr&amp;gt;
    &amp;lt;/thead&amp;gt;
    &amp;lt;tbody&amp;gt;
      &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;content1&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;content2&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;content3&amp;lt;/td&amp;gt;
      &amp;lt;/tr&amp;gt;
      &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;content4&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;content5&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;content6&amp;lt;/td&amp;gt;
      &amp;lt;/tr&amp;gt;
      &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;content7&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;content8&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;content9&amp;lt;/td&amp;gt;
      &amp;lt;/tr&amp;gt;
    &amp;lt;/tbody&amp;gt;
  &amp;lt;/table&amp;gt;
&amp;lt;/body&amp;gt;
&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;css 설정&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;brush: css;&quot;&gt;&amp;lt;style&amp;gt;
    .selectTable {
      border: 1px solid #000000;
    }

    #select {
      background-color: #BDBDBD;
    }
&amp;lt;/style&amp;gt;
&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;javascript설정&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;brush: js;&quot;&gt;&amp;lt;script src=&quot;http://code.jquery.com/jquery-1.4.4.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
  var lastIndex = 0;

    $(document).ready(function() {
      $(&quot;.selectTable tbody tr&quot;).click(function() {
        var select = $(this);
        var index = select.index();
        select.attr(&quot;id&quot;, &quot;select&quot;);
        if(!window.event.ctrlKey &amp;amp;&amp;amp; !window.event.shiftKey) {
          select.siblings().removeAttr(&quot;id&quot;);
        } else if(window.event.shiftKey) {
          for(var i=Math.min(lastIndex, index);i&amp;lt;Math.max(lastIndex, index);i++) {
            $(&quot;.selectTable tbody tr&quot;).eq(i).attr(&quot;id&quot;, &quot;select&quot;);
          }
        }
        lastIndex = index;
      });
    });
&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;결과&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996E19445B8E31E120&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996E19445B8E31E120&quot; width=&quot;500&quot; height=&quot;202&quot; filename=&quot;TableMultiSelect.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;추가 옵션&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;-블록지정 방지&lt;/p&gt;
&lt;pre class=&quot;brush: xml;&quot;&gt;&amp;lt;body oncontextmenu=&quot;return false&quot; ondragstart=&quot;return false&quot; onselectstart=&quot;return false&quot;&amp;gt;
&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;소스 및 예제페이지 확인&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;button class=&quot;linkBtn&quot; onclick=&quot;window.open('https://jsfiddle.net/n24Lm8ox/4/')&quot;&gt;페이지 이동&lt;/button&gt;&lt;/p&gt;</description>
      <category>Web</category>
      <author>알터.</author>
      <guid isPermaLink="true">https://program-factory.tistory.com/2</guid>
      <comments>https://program-factory.tistory.com/2#entry2comment</comments>
      <pubDate>Tue, 4 Sep 2018 16:28:43 +0900</pubDate>
    </item>
  </channel>
</rss>