태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

eternally full with hope...

블로그 이미지
영원히 희망으로 가득하길...
by eternalbleu
  • 464618Total hit
  • 101Today hit
  • 316Yesterday hit

'CS&E'에 해당되는 글 71건

  1. 2008/07/03
    Proggy Programming Fonts
  2. 2008/07/01
    현대 컴퓨팅 발전의 시작. Memex (2)
  3. 2008/07/01
    자바 CLASSPATH 설정
  4. 2008/01/07
    도메인 기관 이전 이라는 것을 처음으로 해봤습니다.
  5. 2007/06/02
    Ray-Tracing Tutorial (3)
  6. 2007/05/31
    JSP를 이용해서 오라클 BLOB 다루기 (1)
  7. 2007/05/27
    TortoiseSVN Ignore Pattern
  8. 2007/02/20
    Internet Explorer BHO 사용시 Download Complete 이벤트 미발생 문제 (1)
  9. 2006/12/22
    rTorrent 사용법
  10. 2006/12/21
    GNU Makefile 작성법
IDE를 켜고 영어를 적다보면 생기는 비슷한 글자를 최대한 줄여주는 폰트가 바로 좋은 폰트 ㅎㅎㅎ

사용자 삽입 이미지

http://www.proggyfonts.com/

연산자나 브래킷을 강조해주는 폰트가 가장 편한듯함.

사용자 삽입 이미지

TRACKBACK 0 AND COMMENT 0

 오늘은 한 몇년만에 나름 진지한 글을 적어보려고 합니다. 어쩌다보니 3분동안 하고 싶은 주제로 이야기를 할 기회가 돼어서 그 3분의 준비를 위해서 이전에 알고 있던 내용을 다시 정리해보려고 합니다. (사실 아무 주제로나 말하라고 했지만... 재미있게 할 만한 말이 없더라구요)

 컴퓨터의 발전사 속에는 익히 사람들이 알다시피 소위 천재들이 곳곳에서 많은 활약을 했습니다.
 멀리는 튜링머신으로 유명한 알렌 튜링(Alan Turing)에서 시작해서, 마우스를 고안한 것으로 잘 알려진 더글라스 앵겔바트(Douglas Engelbart)가 있겠고, 가까이는 C++을 만든 뱐 스트라우스트럽(Bjarne Straustrup), Java를 고안한 제임스 고스링(James Gosling), 이 복잡한 프로그래밍 세상에 무지한 중생들(?)을 일깨우고자 DP를 제창한 GoF역시도 여기에서 빠질 수는 없겠습니다.

더글라스 엥겔바트의 the Demo 영상


  이런 많은 사람중에서도 제가 소개하고 싶은 사람은 바로 배니바르 부시(Vannevar Bush)라는 사람입니다. 아마 컴퓨터 역사에서 가장 사람들의 존경을 받는 사람은 튜링인듯 싶지만... (컴퓨터 분야의 위대한 업적을 남긴 과학자에게 주는 상의 이름이 튜링상인 것을 보면)
 하지만 저는 이 사람보다 배니바르 부시를 더욱 높게 평가하고 싶습니다. 이유는 이 사람이 제안한 메멕스라는 다소 황당한 기계장치 때문입니다.

 메멕스(Memex)의 영어 정식 명칭은 MEMory EXtender 입니다. 바로 해석하자면 기억 확장기? 정도로 말할 수 있겠죠?
 왜?? 기억 확장기라고 이 사람은 이 기계를 말했을까요?

사용자 삽입 이d미지

이 살짝 느끼하게 생긴 아자씨가 부시 아자씨


 이게 바로 부시가 제안한 메멕스라는 기계의 간단한 도면입니다. 그림이 하도 작으니 좀더 큰 그림으로 보죠.

사용자 삽입 이미지
: 애니메이션으로 보는 메멕스 (받아서 구경하삼)


 물론 당시에 부시가 제안한 것은 이 기계의 개념이었기 때문에 도면이라고 해봐야 참 조잡한 수준이었습니다. 문제는 이 사람이 이 기계를 제안하면서 내놓은 개념들이 참 의미심장하기 때문이죠. (대형 공학 계산용 컴퓨터만 존재하던 그 시기에 이런 소형 시스템을 고안했다는 것 자체로도 이 사람은 평범이라는 말을 거부한다고 생각합니다.)

 본래 이 시스템을 부시가 고안한 것은 1945년 경입니다. 2차 세계대전에서 과학기술이 전쟁의 무기로 사용되는 것을 목격한 전후 과학자들에게 본인이 가진 기술력을 인간의 지적 능력의 발전을 위해서 사용하자는 간단한 에세이를 기고하면서 였습니다.

 이 에세이에서 부시가 주장한 것은 인간이 가진 정보를 간편히 저장하고, 빠르게 검색할 수 있는 소형의 시스템이 필요하다고 피력하면서 제안한 것이 바로 메멕스. 기억 확장장치입니다.

 부시가 제안한 것 중에 가장 혁신적인 것은 현재 하이퍼링크의 전신이라고 할 수 있는 정보의 연결 시스템입니다. 부시는 당시 정보의 보고인 도서관에 존재하는 모든 정보를 필름 형태로 만들어서 이 기계에서 한개의 정보속에서 연결되는 다른 필름을 교차 참조해서 볼 수 있다고 고안했다. 어딘지 모르게 지금의 인터넷인 WWW의 형태와 굉장히 유사하다고 생각돼지 않나요? ㅎ

 단지 이 것만 이 기계에 들어가있느냐? 절대 아닙니다. ㅎㅎ

 정보를 단순히 연결만하는 장치가 메멕스는 아니겠죠? 당연히 처음 메멕스를 제안하는 목적이 정보의 저장, 검색 이었던 만큼 이 사람은 이를 위한 다양한 장치를 많이 고안했습니다. 일단 사진의 좌측에 보이는 장치는 바로 현대의 스캐너라고 생각할 수 있습니다. 그리고 가운데의 2개의 화면은 저장된 정보를 보여주는 일종의 현대의 모니터라고 할 수 있습니다. 사실상 모니터를 이용해서 그래픽이라는 것을 처음 표현한 이반 서더랜드의 스캐치패드라는 시험적인 프로그램이 나온게 1963년이니 이 사람은 정말로 세상을 앞서서 본 것이라고 할 수 있습니다. 또한 가장 오른쪽에 있는 버튼들은 저장된 정보를 검색할 수 있도록 해주는 키보드와 버튼들이죠.

사용자 삽입 이미지

Apple II

사용자 삽입 이미지

알테이어 8800

사실 최초의 개인용 컴에 관려된 의견은 분분한 듯 하다.

 중요한 점은 이런 모든 장치들이 부시가 메멕스를 제안한지 30년이 지난후에 개인용 데스크 탑이 나오게 돼었고, 50년이 지나서야 팀 버너스 리가 WWW를 고안하면서 웹의 세상이 열리면서 부시가 상상하던 세계가 열렸다는 점입니다.

사용자 삽입 이미지

텍스트 뿐이던 인터넷에 WWW 세상을 추가해 화려한 사진과 영상의 세계로 바꾸어버린 팀 버너스 리



 마치 현대의 컴퓨터를 50년전에 눈앞에 그려낸 것이죠.

 이 사람이 제안한 메멕스를 가만히 보고 있으면, 무슨 예언가가 예언을 한 것이 아닌가 싶을 정도로 컴퓨터의 발전은 메멕스를 향해서 달려왔습니다. 놀라운 MEMEX.

TRACKBACK 0 AND COMMENT 2

자바의 classpath 를 사용하는 이유는 프로그램을 작성하면서 참조하는 다양한 라이브러리의 경로를 명시하여, jvm 구동시 이를 동적으로 링크하기 위함이다.

 

 이를 지정하는 방법은 크게 두가지로 구분할 수 있다. 한가지는 시스템이 제공하는 환경변수 설정을 이용하는 방법, 두번째는 java 구동환경에서 option 을 설정을 통해서 명시적으로 지정하는 방법이다.

 

1.       환경 변수를 이용한 설정
 
운영체제는 시스템 운영상 필요한 경로를 시스템에 지정해두고서 참조하는 것이 가능하다. 이를 환경 변수라고 부르는데, 자바도 이곳에 필요한 경로를 설정해두고서 이용하는 것이 가능하다.

 
필요한 환경변수는 Path, CLASSPATH 두개의 환경변수가 필요하며, 첫번째 Path 는 운영체제가 명령어를 실행하면서 해당 명령어에 맞는 실행파일을 찾아가는 순서를 명시한 환경변수이다.

 
이곳에 아래와 같은 식으로 설정을 함으로써 어떤 폴더에서나 자바의 컴파일러인 javac를 접근할 수 있다.

PATH=C:\Program Files\Java\jre1.6.0_05\bin;%SystemRoot%\system32;%SystemRoot%;
CLASSPATH= .;C:\Program Files\Java\jre1.6.0_05\lib\;

 
문제는 이렇게 환경변수를 설정하는 경우 컴파일시 다른 버전의 컴파일러를 실행하기 위해서는 변수 설정이 안됐을 때와 마찬가지로 절대경로로 접근해야하는 문제가 존재한다. 이런 상황에서 변리한 버전 변경을 위해서 아래와 같은 테크닉을 이용한다.
 
또한, 상기에서 보면 CLASSPATH에 현재 경로를 의미하는 . 를 추가했는데, 이는 자바 컴파일러가 명시적으로 CLASSPATH를 지정할 경우 현재 경로를 보지 않기 때문에 환경 변수상에서 현재 폴더를 추가해야만 정상적인 실행이 가능하기 때문이다.

JAVAPATH= C:\Program Files\Java\jre1.6.0_05;
PATH= %JAVAPATH%\bin;%SystemRoot%\system32;%SystemRoot%;
CLASSPATH= .; %JAVAPATH%\lib\;

, 환경변수는 시스템내에서 %{environmental variables}%의 형대로 참조가 가능하다. 이렇게 설정을 할 경우 다른 버전의 자바 컴파일러를 사용할 경우 JAVAPATH 만을 변경해주면 된다.

 

Option 을 이용한 설정
 환경 변수를 시스템에 설정하지 않고도 클래스 패스를 지정하는 것이 가능한데, 이는 javac, java를 이용해서 실행할 때 –classpath 라는 옵션을 사용하는 것이다.
 
이 경우에는 윈도우의 경우 아래의 형태로 일단 사용이 가능하다.

java –classpath “C:\Program Files\Java\jre1.6.0_05\lib”;. HelloWorld

주의점은 경로상에 빈칸이 존재하는 경우에는 경로를 반드시 “”를 이용해서 묶어줘야 한다. 또한 만약 자바의 경로를 환경변수 상에 지정한 경우라면 아래와 같은 형태의 표현도 가능하다.

java –classpath %JAVAPATH%\bin;. HelloWorld

이 경우 마찬가지로 자바의 경로상에 빈칸이 존재하는 경우라면 환경변수 설정된 디렉토리를 “”로 묶어줘야 한다.
TRACKBACK 0 AND COMMENT 0

도메인 신청에 대해서 아무것도 모르던 때에 현재 도메인을 구입해서 상대적으로 가격이 엄청 비쌌던 후이즈에서 신청을 했었습니다. (후이즈는 왜 이렇게 비쌀까요?)

전 원래 그 가격에만 등록이 돼는 줄 알았는데... 쩝...

하여간 슬슬 기간도 반년정도만 남아서 dotname으로 등록 기관을 이전했습니다.

생각보다 엄청 간단하더군요. ;;

그냥 기존의 등록기관에서 AUTH CODE를 받아서 새로운 등록 기관으로 신청만 하면 돼더라는...

사용자 삽입 이미지

TRACKBACK 0 AND COMMENT 0
데브마스터에 올라온 레이트레이싱에 관련된 강좌 자료.

찾아본 레이트레이싱 자료중에서 가장 훌륭한 자료인 것 같습니다. 이론적인 설명에만 그치지 않고, 실재 구현에 대한 내용을 C++ 프로그래머의 입장에서 잘 설명된 글입니다.

사이트에 가면 실재 구현된 소스도 구할 수 있습니다. :)

TRACKBACK 0 AND COMMENT 3

1. JSP 를 이용한 BLOB 저장

-------------------------------------------------------------------------
File            file       = (File) param.get("sajin"); // 등록할 File
Blob            emptyBlob  = null;           
OutputStream    outstream  = null;
FileInputStream finstream  = null;
ResultSet rs = null;

try{
    // EMPTY_BLOB() 처리
    sql = "update table set sajin=EMPTY_BLOB() where id=?";
    ps = con.prepareStatement(sql);
    ps.setString(1, (String)param.get("id"));
    if ( ps.executeUpdate() < 0 ) throw new Exception();


    // 저장할 sajin Column 가져온다.
    sql = "select sajin from table where id=?";
    ps = con.prepareStatement(sql);
    ps.setString(1, (String)param.get("id"));
    rs = ps.executeQuery();
    if ( rs.next() ) emptyBlob = rs.getBlob(1);

    // db blob output stream
    oracle.sql.BLOB bol = (oracle.sql.BLOB) emptyBlob;
    outstream = bol.getBinaryOutputStream();
    int size = bol.getBufferSize();
    // 파일 input stream
    finstream = new FileInputStream(file);

   
    // 파일 읽어서 db에 넣기
    byte[] buffer = new byte[size];
    int length = -1;
    while ((length = finstream.read(buffer)) != -1) {
        outstream.write(buffer, 0, length);
    }
} catch (Exception e){
    throw(e);
} finally {
    if( rs          != null ) rs.close();
    if( finstream   != null ) finstream.close();              
    if( outstream   != null ) outstream.close();
}

-------------------------------------------------------------------------
즉, 다른 타입처럼 update문이나 insert를 이용하지 않는다.
다시 한번 정리하면, insert할 column을 EMPTY_BLOB()로 초기화
초기화된 column을 select 하여 OutputStream을 통해 file을 DB에 저장한다.


2. JSP 를 이용한 BLOB 브라우저에서 보기

-------------------------------------------------------------------------
package showImage;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;

public class ShowImageServlet extends HttpServlet
{

 public void doGet(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException
 {
  doPost(request, response);
 }

 public void doPost(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException
 {

        Connection con       = null;
        ResultSet rs         = null;
        PreparedStatement ps = null;
        InputStream is       = null;

        // Image를 가져오기위한 키값들
        String key1 = request.getParameter("key1"); // Primary key 1
        String key2 = request.getParameter("key2"); // Primary key 2
       
        String file_type    = null; // Image 파일 타입
        String content_type = null; // Image 보여주기위한 Content_type

        // Image 가져올 SQL
        final String SQL =
                " SELECT image_type, image                       " +
                "   FROM cu_basic_t                              " +
                "  WHERE key1 = '"+key1+"' AND key2 = '"+key2+"' ";


        try {
            con = UtilDB.getConnection();     // DB 연결
            ps  = con.prepareStatement(SQL);
            rs  = ps.executeQuery();          // SQL 실행

            // Image 가져오는 부분(content type도 정해준다.)
      if (rs!=null && rs.next()){

       file_type = rs.getString("image_type");
    is = rs.getBinaryStream("image");

    if (file_type.toUpperCase().equals("JPG"))      file_type = "jpeg";
    else if (file_type.toUpperCase().equals("GIF")) file_type = "gif";

    content_type = "image/" + file_type;    // "image/jpeg"나 "image/gif"
    response.setContentType(content_type);  // Content Type Set

                // Image를 Stream을 통해 out
    ServletOutputStream os = response.getOutputStream();
    int binaryRead;
    while ((binaryRead = is.read()) != -1)
    {
     os.write(binaryRead);
    }

   } else {
       throw new Exception("사진이 없습니다.");
   }
  }
  catch(ServletException e) {
      e.printStackTrace();
      throw e;
  }catch(IOException e) {
      e.printStackTrace();
      throw e;
  }
  catch(Exception e) {
      System.out.println("An error occurs : " + e.toString());
      e.printStackTrace();
  }
  finally {
      UtilDB.closeConnection(con, ps, rs); // DB 닫아준다.
  }
 }
}
package showImage;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;

public class ShowImageServlet extends HttpServlet
{

 public void doGet(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException
 {
  doPost(request, response);
 }

 public void doPost(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException
 {

        Connection con       = null;
        ResultSet rs         = null;
        PreparedStatement ps = null;
        InputStream is       = null;

        // Image를 가져오기위한 키값들
        String key1 = request.getParameter("key1"); // Primary key 1
        String key2 = request.getParameter("key2"); // Primary key 2
       
        String file_type    = null; // Image 파일 타입
        String content_type = null; // Image 보여주기위한 Content_type

        // Image 가져올 SQL
        final String SQL =
                " SELECT image_type, image                       " +
                "   FROM cu_basic_t                              " +
                "  WHERE key1 = '"+key1+"' AND key2 = '"+key2+"' ";


        try {
            con = UtilDB.getConnection();     // DB 연결
            ps  = con.prepareStatement(SQL);
            rs  = ps.executeQuery();          // SQL 실행

            // Image 가져오는 부분(content type도 정해준다.)
      if (rs!=null && rs.next()){

       file_type = rs.getString("image_type");
    is = rs.getBinaryStream("image");

    if (file_type.toUpperCase().equals("JPG"))      file_type = "jpeg";
    else if (file_type.toUpperCase().equals("GIF")) file_type = "gif";

    content_type = "image/" + file_type;    // "image/jpeg"나 "image/gif"
    response.setContentType(content_type);  // Content Type Set

                // Image를 Stream을 통해 out
    ServletOutputStream os = response.getOutputStream();
    int binaryRead;
    while ((binaryRead = is.read()) != -1)
    {
     os.write(binaryRead);
    }

   } else {
       throw new Exception("사진이 없습니다.");
   }
  }
  catch(ServletException e) {
      e.printStackTrace();
      throw e;
  }catch(IOException e) {
      e.printStackTrace();
      throw e;
  }
  catch(Exception e) {
      System.out.println("An error occurs : " + e.toString());
      e.printStackTrace();
  }
  finally {
      UtilDB.closeConnection(con, ps, rs); // DB 닫아준다.
  }
 }
}
-------------------------------------------------------------------------
JSP 기준이다.

보여줄 JSP에 다음을 추가

<img src="/servlet/ShowImageServlet?key1=<%=key1%>&key2=<%=key12%>"

  width="100" height="100" />

SRC에 image를 보여주도록 만들어진 서블릿을 입력

참고 (서블릿 실행을 위해 WAS(Jeus) 설정법)

WEB-INF\web.xml 내에 서블릿 등록을 등록하고 서버 재 Start시킨다.


   <servlet>
      <servlet-name>ShowImageServlet</servlet-name>
      <servlet-class>showImage.ShowImageServlet</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>ShowImageServlet</servlet-name>
      <url-pattern>/ShowImageServlet</url-pattern>
   </servlet-mapping>


학교 숙제를 하면서 계속 찾았는데, 인터넷에서 찾을 수 있는 소스중에서 가장 쉽게 나왔네요. BLOB에 대한 자료가 거의 없다 시피해서... (있더라도.. 상당히 길게 늘여적은 소스가 많아서;;)

혹시 나중에 필요하신분들을 위해서 남겨놓습니다.
TRACKBACK 0 AND COMMENT 1
SVN을 사용하면서 윈도우즈 상에서 생성되는 불필요한 파일을 커밋하지 않기 위한 ignore pattern 을 지정합니다. 대충 제가 정한 내용은 저에게 최적화된 내용이니 사람마다 다를 것이라고 생각하지만 필요한 분을 긁어서 붙여두고 사용하시길~~

설정하는 방법은 tortoisesvn setup 화면에서 하단과 같이 설정하면 다음부터 적용됨~

사용자 삽입 이미지


*/debug *\debug */Debug *\Debug */Release *\Release */release *\release *.obj *.pdb *.pch *.ncb *.suo *.bak *.tmp *.~ml *.class Thumbs.db *.o *.exec ~*.* *.~* _*.* .*
TRACKBACK 0 AND COMMENT 0
멤 과제 때문에 어쩔 수 없이 BHO 를 공부하면서 만지작거리고는 있는데...
당췌 일관된 이벤트가 발생하지 않으니... -_-

지가 알아서 자동으로 판단하고 보내주는 것은 좋은데 왜 설정은 못하게 해놓은 건지;;

가장 웃긴건 역시나 왜 이동 버튼을 누르면 DOCUMENTCOMPLETE 이 발생안하는지;;;; 주소 똑같이 다시 치고 이동버튼 누르면 발생하고.... --;;

아놔 장난하는거도 아니고;; 스파이 돌려보니

<00029> 0028074A S EM_SETMODIFY fModified:False
<00030> 0028074A R EM_SETMODIFY
<00031> 0028074A S WM_GETTEXT cchTextMax:4168 lpszText:02310000
<00032> 0028074A R WM_GETTEXT cchCopied:24 lpszText:02310000 ("")
<00033> 0028074A S WM_SETTEXT lpsz:0012AA74 ("http://www.google.co.kr/")
<00034> 0028074A S EM_GETMODIFY
<00035> 0028074A R EM_GETMODIFY fModified:False
바로 이동 버튼 누를때

<00030> 0028074A P WM_KEYDOWN nVirtKey:'G' cRepeat:1 ScanCode:22 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00031> 0028074A P WM_CHAR chCharCode:'0067' (103) cRepeat:1 ScanCode:22 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00032> 0028074A S EM_GETMODIFY
<00033> 0028074A R EM_GETMODIFY fModified:True
<00034> 0028074A S WM_IME_NOTIFY dwCommand:0000000B dwData:00000000
<00035> 0028074A R WM_IME_NOTIFY
<00036> 0028074A S WM_GETTEXT cchTextMax:520 lpszText:0012D2FC
<00037> 0028074A R WM_GETTEXT cchCopied:1 lpszText:0012D2FC ("")
<00038> 0028074A S EM_GETMODIFY
<00039> 0028074A R EM_GETMODIFY fModified:True
<00040> 0028074A S WM_WINDOWPOSCHANGING lpwp:0012C1B4
<00041> 0028074A R WM_WINDOWPOSCHANGING
<00042> 0028074A S WM_GETTEXT cchTextMax:4168 lpszText:02390000
<00043> 0028074A R WM_GETTEXT cchCopied:1 lpszText:02390000 ("")
<00044> 0028074A S WM_GETTEXTLENGTH
<00045> 0028074A R WM_GETTEXTLENGTH cch:1
<00046> 0028074A S WM_GETTEXT cchTextMax:4 lpszText:0012CADC
<00047> 0028074A R WM_GETTEXT cchCopied:1 lpszText:0012CADC ("")
<00048> 0028074A S WM_GETTEXT cchTextMax:520 lpszText:0012D4C4
<00049> 0028074A R WM_GETTEXT cchCopied:1 lpszText:0012D4C4 ("")
<00050> 0028074A P WM_PAINT hdc:00000000
<00051> 0028074A S WM_ERASEBKGND hdc:04011079
<00052> 0028074A R WM_ERASEBKGND fErased:True
새로 주소 치고 이동버튼 누를때

에디트 박스에서 수정 내용을 WM_GETMODIFY 라는 놈으로 가져오는 것 같기는 한데... -.-;;

설정이라도 하게 만들어뒀으면 좋으련만;;; 설정도 안되는거 같고.... 핸들이라도 얻을 수 있으면 이벤트라도 수동으로 날려볼텐데 -_-;;;

사용자 삽입 이미지

문제는 바로 이놈;;;



TRACKBACK 0 AND COMMENT 1
요즘 새롭게 떠오른 P2P 프로토콜이 있습니다.

바로 BitTorrent 라는 프로토콜로 Tracker 라는 교환서버를 기반으로 동작하는 P2P의 한 형태입니다. 자세한 사항은 위키 페디아를 참조하세요. 장점이자 단점은 검색이라는 것이 아닌 .torrent 파일을 가지고 교환된다는 점이죠. (대신에 .torrent 를 다루는 폐쇄형 공유 커뮤니티들이 더러 있습니다)

사용자 삽입 이미지

http://en.wikipedia.org/wiki/BitTorrent


사용자 삽입 이미지

이 게임은 클라이언트는 용량만 3GB이다

덕분에 torrent 파일이 없으면 다운로드는 요원한 일이라는 것은 장점이라면 장점. 단점이라면 단점이라면 단점입니다. 하지만 대용량 파일을 가진 컨텐츠를 배포해야하는 서비스에서는 이 만큼 좋은 배포 형태도 없죠.

가깝게는 블리자드사의 World Of Warcraft 한글판을 이 형태로 배포하고 있습니다. 서비스 제공자의 입장에서는 최소한의 비용 투자로 최대의 효과를 거두어 들이는 거죠 ^^

당연하겠지만 역시 리눅스 콘솔에도 이 프로토콜의 콘솔 클라이언트가 있습니다. rTorrent 라는 녀석입니다. ncurse 라이브러리를 이용해서 콘솔 프로그램임에도 불구하고 굉장히 편하게 사용할 수 있다는 장점이 있습니다.
(오페라 브라우저의 다운로드 매니저는 기본적으로 .torrent 를 지원합니다.)

이번에는 rTorrent 라는 프로그램을 사용해보려고 합니다.

우선은 aptitude 를 이용해서 rTorrent를 설치합니다.
사용자 삽입 이미지

aptitude install rtorrent

사용자 삽입 이미지

엔터키를 이용해 load> 라는 창에 .torrent 의 내용을 입력한다. (파일, URL 무관하다)

방향키로 다운로드 리스트 아이템을 선택하고 오른쪽 버튼을 누르면 해당 다운로드에 대한 정보를 볼 수 있다.
사용자 삽입 이미지사용자 삽입 이미지
사용자 삽입 이미지사용자 삽입 이미지
사용자 삽입 이미지사용자 삽입 이미지
사용자 삽입 이미지사용자 삽입 이미지

※ rTorrent 개발 페이지에서 가져온 단축키 내역입니다. 최신 버전과 약간 차이가 있는 듯합니다.

torrents 추가 및 제거
backspace URL, 파일 이름을 이용해서 torrent 를 추가한다. 디렉토리 내용을 보고 자동 완성하려고 Tab 키를 이용할 수 있다. 이때 ~/torrent/* 같이 와일드 카드 문자를 사용해서 입력하는 것이 가능하다.
return torrent 를 비 활성화된 상태로 남긴다는 점을 제외하면 backsapce 와 동일한 기능을한다. (활성화 단축키 ^s )
^O 선택된 torrent 를 위한 새로운 다운로드 디렉토리를 설정한다. torrent 가 아직 활성화된 상태가 아닐때만 동작한다.
^s 다운로드 시작. (완료 직전 이라면 해싱 작업을 먼저 시작한다)
^d 다운로드 중지. 혹은 정지된 다운로드를 제고
^r 다운로드와 무관하게 torrent 의 해싱 체크를 시작한다.

대역폭 제한
a/s/d 1/5/50 KB 씩 업로드 대역폭 증가.
z/x/c 1/5/50 KB 씩 업로드 대역폭 감소.
A/S/D 1/5/50 KB 씩 다운로드 대역폭 증가.
Z/X/C 1/5/50 KB 씩 다운로드 대역폭 감소.
※ 대역폭 제한은 단일 torrent 에 대한 제한이 아니라 전역적으로 제한된다.

네비게이션
1. 전역키
^q 프로그램 종료. (중복으로 명령을 내리면 트래커와 주고받는 신호를 무시하고 종료한다.)
up/down torrent 선택
left 이전 화면으로 복귀

2. 메인 뷰
right 다운로드 뷰로 전환
^r 토런트의 해시 체크 시작
+/- 토런트의 우선 순위 변경
l 로그 보기. Space 키로 종료
M-1 모든 다운로드 내역 보기
M-2 이름 순으로 모든 다운로드 내역 보기
M-3 시작된 다운로드 내역 보기
M-4 정지된 다운로드 내역 보기
M-5 완료된 다운로드 내역 보기
M-6 해싱중인 다운로드 내역 보기

3. 다운로드 뷰 키보기
right 토런트 파일 리스트로 전환
left 메인 뷰로 전환
1/2 최대 업로드 조절
3/4 최소 피어수 조절
5/6 최대 피어수 조절
o 트리커 리스트 출력.스페이스바로 한 구룹내의 트래커들을 순환. * 키를 이용해 선택된 트래커 의 활성화 설정을 토글
p 피어와 토런트 정보를 보기
t/T 트래커 요청 시작. 대문자 T를 이용하면 최소 요청 간격을 무시하고 강제로 요청을 할 수 있음.
u 전송 내역 보기
i Chunk 빈도 보기

4. 파일리스트 뷰
left 다운로드 뷰로 전환
space 파일 우선 순위 변경
* 모든 파일의 우선 순위 변경

TRACKBACK 0 AND COMMENT 0

※ 이 내용은 임대영 님의 강좌를 스크랩한 내용입니다.


GNU Make 강좌
임대영 RAXIS@hitel.net
v1.0, 1997년 8월 28일

--------------------------------------------------------------------------------
이 글에서는 컴파일 과정과 같이 반복되는 작업을 효과적으로 처리하는 GNU-Make에 대해서 설명한다.
--------------------------------------------------------------------------------

1. make (만든다 ?)
1.1 make 유틸리티
1.2 make의 필요성

2. 간단한 Makefile
2.1 Makefile 의 내부 구조
2.2 Makefile 예제
2.3 매크로의 사용
2.4 레이블의 사용

3. 매크로(Macro) 와 확장자(Suffix) 규칙
3.1 매크로란 무엇인가? (What is Macro)
3.2 미리 정해져 있는 매크로 (Pre-defined macro)
3.3 확장자 규칙 (Suffix rule)
3.4 내부 매크로 (Internal macro)

4. Makefile를 작성할 때 알면 좋은 것들
4.1 긴 명령어를 여러 라인으로 표시하기
4.2 확장자 규칙의 이용 (Use suffix rule !!)
4.3 매크로 치환 (Macro substitution)
4.4 자동 의존 관계 생성 (Automatic dependency)
4.5 다중 타겟 (Multiple target)
4.6 순환 make (Recursive MAKE)
4.7 불필요한 재컴파일 막기

5. make 중요 옵션 정리

6. Makefile 작성의 가이드라인

7. Makefile의 실제 예제
7.1 프로그램 제작에 쓰일 수 있는 Makefile
7.2 라이브러리와의 링크가 필요한 필요한 Makefile
7.3 LaTeX에서 쓰일 수 있는 Makefile

8. make 수행 시에 나타나는 에러들

1. make (만든다 ?)
1.1 make 유틸리티
영어 사전에서 make란 뜻은 누구나 알듯이 '만들다'라는 뜻의 동사이다. 그럼 make유틸리티는 왜 이름이 make인지 알 필요가 있을 것 같다. man으로 찾아보면 make에 대해 다음과 같이 설명하고 있다.

make - GNU make utility to maintain groups of programs
The purpose of the make utility is to determine automatically which pieces of a large program need to be recompiled, and issue the commands to recompile them.

우리말로 하면 make는 프로그램 그룹을 유지하는데 필요한 유틸리티이다. make유틸리티의 목적은 프로그램 그룹 중에서 어느 부분이 새롭게 컴파일되어야 하는지를 자동적으로 판단해서 필요한 커맨드(gcc따위)를 이용해서 그들을 재컴파일 시킨다고 되어 있다.

make는 일련의 프로그램 개발에만 쓰이지 않고, 컴파일러처럼 일종의 명령어 방식으로 처리되는 모든 곳에서 쓰일 수가 있다. 가령 LaTeX와 같은 경우도 .tex 파일에서 .dvi 파일을 만들고 다시 .ps 파일로 만드는 과정을 make를 사용해서 간단하게 만들 수가 있다.

쉽게 말하면 다음과 같은 경우에 make를 쓰면 유리합니다.

입력 파일이 바뀌면 자동적으로 결과 파일이 바뀌기를 원할 때, 기왕이면 좀 지능적으로 일이 수행되기를 바랄 때 말입니다.
위의 LaTeX 파일처럼 자동적으로 프로그램이 수행이 되기를 바랄 때... (배치(batch)의 개념이죠)

=> make는 위의 두 가지 개념을 모두 포함하고 있다고 봅니다. 보통 리눅스 프로그램에서는 make all을 입력하면 자세한 내막은 모르지만 자기가 알아서 모든 일을 다하죠... 그 다음으로 make install만 입력하면 되구요... 히...

GNU make는 보통 GNUmakefile, Makefile, makefile 중에서 하나가 있으면 그 파일을 읽게 된다. 하지만 일반적으로 Makefile을 추천하게 되는데, 그 이유는 우선 GNUmakefile은 기존의 make에서 인식을 못한다는 단점이 있고, makefile은 보통 소스 파일에 묻혀서 잘 안보이게 되기 때문이다.

Makefile은 make가 이해할 수 있도록 일종의 쉘 스크립트 언어같이 되어 있다(makefile database라 하기도 한다). 이 파일에는 결과 파일을 생성시키기 위한 파일들간의 관계, 명령어 등을 기술하고 있는데 이 강좌의 주된 목적이 바로 Makefile의 작성에 있다.

1.2 make의 필요성
우선은 make의 사용을 프로그램 개발과 유지 쪽으로 국한시키기로 한다. 보통 라인 수가 많아지면 여러 개의 파일로 나누어 (모듈로 나누어) 개발을 하게 된다. 이들은 알게 모르게 서로 관계를 가지고 있는데, 어느 하나를 필요에 의해 바꾸게 되었을 때 그 파일에 있는 함수를 이용하는 다른 파일도 새롭게 컴파일되어야 한다.

하지만 파일 수가 많은 경우 이를 일일이 컴파일을 하게 될 때, 그 불편함과 함께 컴파일하지 않아도 될 것도 컴파일을 하게 될 수도 있고, 컴파일해야 할 것도 미처 못하게 되는 경우가 있다(링크 에러의 원인이 되기도 하는데 에러의 원인을 제대로 찾기가 힘이 든다).

앞에서도 얘기했듯이 이런 상황에서 지능적으로 관계 있는 것만 새롭게 갱신을 할 필요가 있을 때 make파일은 빛을 발하게 된다.

2. 간단한 Makefile
2.1 Makefile 의 내부 구조
Makefile은 기본적으로 아래와 같이 목표(target), 의존 관계(dependency), 명령(command)의 세개로 이루어진 기분적인 규칙(rule)들이 계속적으로 나열되어 있다고 봐도 무방하다. make가 지능적으로 파일을 갱신하는 것도 모두 이 간단한 규칙에 의하기 때문이다.

--------------------------------------------------------------------------------

target ... : dependency ...
               command
               ...
               ...


--------------------------------------------------------------------------------

여기서 목표(target) 부분은 명령(command)이 수행이 되어서 나온 결과 파일을 지정한다. 당연히 목적 파일(object file)이나 실행 파일이 될 것이다.

명령(command)부분에 정의된 명령들은 의존 관계(depenency)부분에 정의된 파일의 내용이 바뀌었거나, 목표 부분에 해당하는 파일이 없을 때 이곳에 정의된 것들이 차례대로 실행이 된다. 일반적으로 쉘에서 쓸 수 있는 모든 명령어들을 사용할 수가 있으며 bash에 기반한 쉘 스크립트도 지원한다.

=> 참고: 참고로 목표 부분에는 결과 파일만 올 수 있는 것이 아니고, 보통 make clean 에서와 같이 간단한 레이블(label) 기능을 제공하기도 한다.

=> 명령 부분은 꼭 TAB 글자로 시작해야 한다. 그냥 빈칸 등을 사용하면 make 실행 중에 에러가 난다. 명심하세요. make가 명령어인지 아닌지를 TAB 가지고 구별하기 때문이죠.

2.2 Makefile 예제
간단한 Makefile을 만들어 본다. 우리가 만들려고 하는 프로그램은 main.c read.c write.c로 구성되어 있고 모두 io.h라는 헤더 파일을 사용한다고 가정한다. (흐... 구성을 간단하게 합시다.) 이들을 각각 컴파일해서 test 라는 실행 파일을 생성시킨다.

% gcc -c main.c
% gcc -c read.c
% gcc -c write.c

% gcc -o test main.o read.o write.o

위의 방식은 make를 쓰지 않고 그냥 명령어를 주는 방식이다. 파일의 수가 작아서 오히려 더 간단하게 보일 수 있으나, 파일이 100개정도 된다고 가정하면... 아찔...

그리고, 아래는 위와 똑같은 일을 수행하는 Makefile의 내용이다.

Makefile예제 1

--------------------------------------------------------------------------------

test : main.o read.o write.o
               gcc -o test main.o read.o write.o

main.o : io.h main.c
               gcc -c main.c
read.o : io.h read.c
               gcc -c read.c
write.o: io.h write.c
               gcc -c write.c

--------------------------------------------------------------------------------

(대충 알아보시겠어요? 참 TAB문자 쓰는 것 있지 마세요)

make는 Makefile의 내용을 보고, 내부적으로 어떻게 파일들이 의존하고 있는지 조사한다. 위의 Makefile을 바탕으로 의존 관계를 그림으로 나타내 보면 아래와 같다.

--------------------------------------------------------------------------------

                      +---------------+
                      |     io.h      |
                      +------+--------+
                             |
                   +---------+----------+
                   |                    |
  +--------------+  |  +------+-------+  |  +--------------+
  |    main.c    |  |  |    read.c    |  |  |   write.c    |
  +------+-------+  |  +------+-------+  |  +------+-------+
        |          |         |          |         |
  +------+-------+  |  +------+-------+  |  +------+-------+
  |    main.o    +--+--|    read.o    |  +--+   write.o    |
  +------+-------+     +------+-------+     +------+-------+
        |                    |                    |
        +--------------------+--------------------+
                     +-------|-------+
                     |     test      |
                     +------+--------+

--------------------------------------------------------------------------------

(텍스트 기반이라서 그림 그리기가 꽤 어렵네요. =)

위의 그림에서 보면 test 가 만들어지기 위해서는 main.o read.o write.o가 필요하게 각각의 목적 파일들은 모두 자신의 소스 파일과 io.h 에 의존함을 알 수가 있다.

가령 main.c를 고쳤다고 생각한다면 main.o가 컴파일되어 다시 생기고, test 도 다시 링크되어 갱신된다. 만약 io.h가 바뀌었다고 가정하면 모든 파일들이 컴파일되어서 목적 파일이 생기고, 그것들이 링크가 되어 test가 생긴다.

위와 같이 파일들을 구성한 다음 Makefile을 실행시켜 보자. Makefile의 실행은 그냥 make라고만 치면 된다.

% make
gcc -c main.c
gcc -c read.c
gcc -c write.c
gcc -o test main.o read.o write.o <- OK

=> 참고: 그냥 테스트에 불과하기 때문에 read.c writec io.h 는 모두 내용 없이 파일만 만들어 두기로 하고, main.c 에 간단히 printf 함수만 적어 봅시다. 정말 위와 같이 됨을 실감할꺼예요... 신기하게...

2.3 매크로의 사용
간단한 매크로 기능을 사용해 보자. main.o read.o write.o라는 것을 OBJECTS 라는 매크로로 바꾸는 것이 아래의 예제 2에 나와 있다.

Makefile예제 2

--------------------------------------------------------------------------------

OBJECTS = main.o read.o write.o

test : $(OBJECTS)
               gcc -o test $(OBJECTS)

main.o : io.h main.c
               gcc -c main.c
read.o : io.h read.c
               gcc -c read.c
write.o: io.h write.c
               gcc -c write.c


--------------------------------------------------------------------------------

위에서 보다시피 매크로는 그냥 프로그램 짤 때와 같이 사용해서 값을 대입한다. 대신 사용할 때는 반드시 $(..) 안에 넣어서 사용한다. 매크로 치환을 위한 특수한 방법이 아닐까... 히... 매크로의 사용법은 위와 같이 간단하므로 다양하게 정의해서 사용할 수 있다. 매크로에 대한 자세한 설명은 다음 장에서 언급하기로 한다.

2.4 레이블의 사용
목표 부분에 해당하는 부분이 그냥 레이블과 같이 사용될 수도 있다고 이미 설명하였다. 예제 2 에다가 목적 파일들을 모두 삭제하는 명령어를 추가하기로 한다.

Makefile예제 3

--------------------------------------------------------------------------------

OBJECTS = main.o read.o write.o

test : $(OBJECTS)
               gcc -o test $(OBJECTS)

main.o : io.h main.c
               gcc -c main.c
read.o : io.h read.c
               gcc -c read.c
write.o: io.h write.c
               gcc -c write.c

clean :
               rm $(OBECTS)

--------------------------------------------------------------------------------

레이블로 사용될 때는 당연히 의존 관계 부분은 없어도 된다. 그리고 clean을 실행시키려면 아래와 같이 한다.

% make clean
rm main.o read.o write.o <- OK

다음 장에서는...

지금까지는 Makefile의 간단한 예제를 가지고 무엇을 할 수 있는지 대충 알아보았습니다. 예제를 많이 쓰다 보니까 내용이 불어나게 됐군요. RCS와 달리 make는 한번 알고 있으면 정말 유용한 유틸리티입니다.

다음 장에서는 본격적으로 Makefile의 구성및 그 사용법을 자세히 알아 보고자 합니다. 그냥 일반적으로 Makefile 사용하시려면 오늘 한 것에 몇 가지만 더 알고 계시면 됩니다. 계속 예제 중심으로 이해가 잘되도록... 그럼 계속 봐주시면 감사.  

3. 매크로(Macro) 와 확장자(Suffix) 규칙
3.1 매크로란 무엇인가? (What is Macro)
앞에서 매크로에 대해서 대충 언급을 했다. 프로그램을 짜본 사람이나 로터스, 한글, 엑셀 등의 모든 패키지에서 매크로라는 것을 사용하게 된다. 은연중에 매크로의 정의는 대충 짐작하고 있을 것이다. 이미 알고 있는바와 같이 매크로는 특정한 코드를 간단하게 표현한 것에 지나지 않는다. Makefile에서 사용되는 매크로는 비교적 그 사용법이 간단하기 때문에 금방 익혀서 사용할 정도가 된다.

매크로의 정의는 프로그램을 작성할 때 변수를 지정하는 것처럼 하면 된다. 그리고, 매크로를 사용하기 위해서는 $(..)을 이용하면 된다. 아래는 매크로의 간단한 예제이다.

=> 참고: 매크로의 사용에서 ${..}, $(..), $..를 모두 사용할 수 있습니다. 그러나 대부분의 책에서는 $(..) 을 사용하라고 권하는군요.

Makefile예제 4

--------------------------------------------------------------------------------

OBJS = main.o read.o write.o

test : $(OBJS) <- (1)
gcc -o test $(OBJS)
               ..........

--------------------------------------------------------------------------------

첫 번째 장에서 다루었던 예제와 거의 비슷하다. 매크로는 사실상 복잡한 것을 간단하게 표시한 것에 지나지 않는다. (1) 번을 매크로를 안 쓰고 표현한다면 아마 아래와 같이 될 것이다.

Makefile예제 5

--------------------------------------------------------------------------------

test : main.o read.o write.o
gcc -o test main.o read.o write.o

--------------------------------------------------------------------------------

=> 참고: 예제 5가 더 쉽지 않느냐고 반문하는 사람은 매크로의 위력을 잘 모르는 사람입니다. 거의 모든 소프트웨어에서 매크로를 지원하는 이유를 한번 잘 생각해 봅시다. 예제 4 의 (1)부분이 이해하기 난해하다고 하실 지는 모르겠지만, 대충 형식이 정해져 있기 때문에 조금만 익숙해지면 오히려 더 편할 겁니다.

make에 관해 설명한 책에 다음과 같은 명언(?) 이 나온다.

Macro makes Makefile happy. (매크로는 Makefile 을 기쁘게 만든다.)

이 말은 Makefile을 작성함에 있어 매크로를 잘만 이용하면 복잡한 작업도 아주 간단하게 작성할 수 있음을 말해 주는 말이 아닐까 생각한다. 매크로에 대해서는 더 이상 말할 것이 없다. (너무 간단하죠 ?) 이제 남은 것은 여러분들이 자신의 매크로를 어떻게 구성하느냐이다. 어떤 것을 매크로로 정의해야 할지는 여러분들의 자유이며, 나중에 전반적인 지침을 설명할 것이다.

3.2 미리 정해져 있는 매크로 (Pre-defined macro)
여러분들보다 머리가 약간 더 좋은 사람들이 make 라는 것을 만들면서 미리 정해 놓은 매크로들이 있다. 'make -p' 라고 입력해 보면 make에서 미리 세팅되어 있던 모든 값들(매크로, 환경 변수(environment) 등등)이 엄청 스크롤 된다. 이 값들을 보고 미리 주눅 들 필요는 없다. 어차피 대부분의 내용들은 우리가 재정의 해주어야 하기 때문에 결론적으로 말하면 우리가 모두 작성한다고 생각하는 것이 마음이 편하다.,.

아래에는 대부분이 UNIX 계열의 make에서 미리 정해져 있는 매크로들 중에 몇 가지만 나열해 본 것이다.

Predefined Macro 예제 6

--------------------------------------------------------------------------------

ASFLAGS = <- as 명령어의 옵션 세팅
AS = as
CFLAGS = <- gcc 의 옵션 세팅
CC = cc (= gcc)
CPPFLAGS = <- g++ 의 옵션
CXX = g++
LDLFAGS = <- ld 의 옵션 세팅
LD = ld
LFLAGS = <- lex 의 옵션 세팅
LEX = lex
YFLAGS = <- yacc 의 옵션 세팅
YACC = yacc
MAKE_COMMAND = make

--------------------------------------------------------------------------------

=> 참고: 직접 make -p를 해서 한번 확인해 보세요. 과연 make는 내부적으로 어떤 변수들을 사용하고 있는지 알아봅시다. 매크로는 관습적으로 대문자로 작성되니까 이점에 유의해서 보세요. make는 쉘상에서 정의한 환경 변수값들을 그대로 이용한다는 것을 알고 계시기