반응형


putty 에서도 멀티탭을 지원하는 프로그램을 사용 가능하다.


여러개가 있지만


크게 두 가지가 좋다고(아래 참고 사이트에서) 하여


정리한다


> 이 제품은 업그레이드가 더 이상 되지 않는지... 비추천

-  PuTTY Connection Manager

   관련 링크 : http://www.thegeekstuff.com/2009/03/putty-extreme-makeover-using-putty-connection-manager/

    

puttycm.zip

 


> 이 제품은 꾸준히 업그레이드가 되고 있다고 함 ~(2014.03.01 기준)

putty-nd

   

putty_nd3.1.zip


기본 기능은 동일하고


다른 것보다 secureCRT의 chat 모드처럼 여러개의 창에 동시 입력하는 기능을 3.x 버전대에서 지원한다고 함...






특징비교

 트레이
최소화
기능

PuTTY 에이전트 기능 

(멀티탭)

핫키

포커스

reorder
Putty CMY (broke)YYNY
SuperPuttyY (broke)YNNN
mRemoteNGYYNNN
putty-ndNYYYN
MTPuTTYNYYYN







참고사이트  

- http://reznoa.wo.tc/blog/1201?category=4

- http://solutionencoding.blogspot.kr/2012/07/tabbed-ssh-in-windows-7.html

반응형

'UTILITY' 카테고리의 다른 글

Process Hacker  (0) 2014.03.26
SSH System Administration Tool  (0) 2014.03.01
윈도우 빠른 파일 검색 및 내용 검색  (1) 2014.02.11
Virtual BOX SATA 방식의 XP  (0) 2013.07.23
부팅 테스트 프로그램 MobaLiveCD  (0) 2013.03.27
반응형

개발자의 실수를 줄여주는 java.sql.Connection 만들기







흔히 close()를 하지 않아서 발생하는 자원 누수 현상을 줄여주는 Connection 클래스를 만들어본다.

JDBC API 사용시 흔히 하는 개발자의 실수

JDBC API를 사용하여 데이터베이스 프로그래밍을 할 때 가장 많이 사용되는 코드는 아마도 다음과 같은 형태일 것이다.

    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;
    
    try {
        conn = DBPool.getConnection(); //
        stmt = conn.createStatement();
        rs = stmt.executeQuery(..);
        ...
    } catch(SQLException ex) {
        // 예외 처리
    } finally {
        if (rs != null) try { rs.close(); } catch(SQLException ex) {}
        if (stmt != null) try { stmt.close(); } catch(SQLException ex) {}
        if (conn != null) try { conn.close(); } catch(SQLException ex) {}
    }

그런데 위와 같은 프로그래밍을 할 때 흔히 하는 실수가 close()를 제대로 해 주지 않는 것이다. 특히, 하나의 메소드에서 5-10개의 (PreparedStatement를 포함한)Statement와 ResultSet을 사용하는 경우에는 개발자의 실수로 같은 Statement를 두번 close() 하고 한두개의 Statement나 ResultSet은 닫지 않는 실수를 하곤 한다. 이처럼 close() 메소드를 알맞게 호출해주지 않을 경우에는 다음과 같은 문제가 발생한다.

  1. Statement를 닫지 않을 경우, 생성된 Statement의 개수가 증가하여 더 이상 Statement를 생성할 수 없게 된다.
  2. close() 하지 않으므로 불필요한 자원(네트워크 및 메모리)을 낭비하게 된다.
  3. 커넥션 풀을 사용하지 않는 상황에서 Connection을 닫지 않으면 결국엔 DBMS에 연결된 새로운 Connection을 생성할 수 없게 된다.
위의 문제중 첫번째와 두번째 문제는 시간이 지나면 가비지 콜렉터에 의해서 해결될 수도 있지만, 만약 커넥션 풀을 사용하고 있다면 그나마 가비지 콜렉션도 되지 않는다. 따라서 커넥션 풀을 사용하는 경우 Statement와 ResultSet은 반드시 닫아주어야만 한다. 하지만, 제아무리 실력이 뛰어난 개발자라 할지라도 각각 수십에서 수백줄로 구성된 수십여개의 .java 파일을 모두 완벽하게 코딩할 수는 없으며, 따라서 한두군데는 close()를 안 하기 마련이다. 운이 좋으면 빨리 찾을 수 있겠지만, 그렇지 않다면 close() 안한 부분을 찾는 데 몇십분, 몇시간, 심한 경우 1-2일 정도가 걸리기도 한다.

Statement를 자동으로 닫아주는 MVConnection 클래스 구현

실제로 필자도 앞에서 언근했던 문제들 때문에 고생하는 사람들을 종종 봐 왔었으며, 그때마다 그 버그를 고치기 위해서 소스 코드를 일일이 찾아보는 노가다를 하는 개발자들을 보기도 했다. 그래서 만든 클래스가 있는데, 그 클래스의 이름을 MVConnection이라고 붙였다. 이름이야 여러분의 입맛에 맛게 수정하면 되는 것이므로, 여기서는 원리만 간단하게 설명하도록 하겠다.

먼저, MVConnection을 구현하기 전에 우리가 알고 있어야 하는 기본 사항이 있다. JDBC API를 유심히 읽어본 사람이라면 다음과 같은 내용을 본 적이 있을 것이다.

  • Statement를 close() 하면 Statement의 현재(즉, 가장 최근에 생성한) ResultSet도 close() 된다.
  • ResultSet은 그 ResultSet을 생성한 Statement가 닫히거나, 또는 executeQuery 메소드를 실행하는 경우 close() 된다.
MVConnection은 바로 이 두가지 특성을 사용한다. 위의 두 가지 특징을 정리하면 결국 Statement만 알맞게 닫아주면 그와 관련된 ResultSet은 자동으로 닫힌다는 것을 알 수 있다. 따라서 ConnectionWrapper 클래스는 Connection이 생성한 Statement들만 잘 보관해두었다가 각 Statement를 닫아주기만 하면 되는 것이다. PreparedStatement나 CallableStatement는 Statement를 상속하고 있으므로 따로 처리할 필요 없이 Statement 타입으로 모두 처리할 수 있으므로, PreparedStatement와 CallableStatement를 위한 별도의 코드는 필요하지 않다.

다음은 MVConnection 클래스의 핵심 코드이다.

    public class MVConnection implements Connection {
        
        private Connection conn; // 실제 커넥션
        
        private java.util.List statementList; // statement를 저장
        
        public MVConnection(Connection conn) {
            this.conn = conn;
            statementList = new java.util.ArrayList();
        }
        
        public void closeAll() {
            for (int i = 0 ; i < statementList.size() ; i++) {
                Statement stmt = (Statement)statementList.get(i);
                try {
                    stmt.close();
                } catch(SQLException ex) {}
            }
        }
        
        public void close() throws SQLException {
            this.closeAll();            conn.close();
        }
        
        public Statement createStatement() throws SQLException {
            Statement stmt = conn.createStatement();
            statementList.add(stmt);
            return stmt;
        }
        
        public CallableStatement prepareCall(String sql) throws SQLException {
            CallableStatement cstmt = conn.prepareCall(sql);
            statementList.add(cstmt);
            return cstmt;
        }
        
        public PreparedStatement prepareStatement(String sql) throws SQLException {
            PreparedStatement pstmt = conn.prepareStatement(sql);
            statementList.add(pstmt);
            return pstmt;
        }
        
        ...
    }

위 코드를 보면 Statement를 저장하기 위한 List와 그 List에 저장된 Statement 객체를 모두 닫아주는 closeAll() 이라는 메소드가 정의되어 있다. 바로 이 List와 closeAll() 메소드가 이 MVConnection 클래스의 핵심이다. Statement를 생성해주는 메소드(createStatement, prepareCall, prepareStatement)를 보면 생성된 Statement를 statemetList에 추가해주는 것을 알 수 있다. 이렇게 저장된 Statement는 실제로 Connection을 닫을 때, 즉 Connection의 close() 메소드를 호출할 때 닫힌다. (코드를 보면 close() 메소드에서 closeAll() 메소드를 먼저 호출하고 있다.) 따라서, close() 메소드만 호출하면 그와 관련된 모든 Statement와 ResultSet은 자동으로 닫히게 된다.

위 코드에서 다른 메소드들은 모두 다음과 같이 간단하게 구현된다.

    public boolean getAutoCommit() throws SQLException {
        return conn.getAutoCommit();
    }

MVConnection은 java.sql.Connection을 implements 하기 때문에, 그 자체가 Connection으로 사용될 수 있다. 따라서 MVConnection을 사용한다고 해서 특별히 코드가 많이 변경되지는 않으며 다음과 같이 전체적으로 코드가 단순하게 바뀐다.

    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;
    
    try {
        // MV Connection 생성
        conn = new MVConnection(DBPool.getConnection());
        stmt = conn.createStatement();
        rs = stmt.executeQuery(..);
        ...
    } catch(SQLException ex) {
        // 예외 처리
    } finally {
        // conn 만 close() 해준다.
        if (conn != null) try { conn.close(); } catch(SQLException ex) {}
    }

때에 따라서는 Connection을 close() 하지 않고 커넥션 풀에 되돌려 놔야 할 때가 있다. 그런 경우에는 다음과 같은 형태의 코드를 사용하면 된다.

    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;
    
    try {
        // MV Connection 생성
        conn = new MVConnection(DBPool.getConnection());
        stmt = conn.createStatement();
        rs = stmt.executeQuery(..);
        ...
    } catch(SQLException ex) {
        // 예외 처리
    } finally {
        if (conn != null) try { 
            ((MVConnection)conn).closeAll();
            DBPool.returnConnection(conn);
        } catch(SQLException ex) {}
    }

즉, Connection을 닫지 않는 경우에는 위와 같이 커넥션 풀에 반환하기 전에 closeAll() 메소드 하나만을 호출해주면 된다. 그러면 Connection과 관련된 모든 Statement, ResultSet 등이 닫히게 된다.

결론

필자의 경우는 이 글에서 작성한 MVConnection을 실제 프로젝트에 응용하여 코드 작성의 편리함 뿐만 아니라 실수로 인해서 발생하는 시스템의 버그 문제를 어느 정도 해결할 수 있었다. 특히, Statement를 생성하거나 ResultSet을 생성할 때 발생하는 커서부족 문제를 획기적으로 줄일 수 있었다. 여러분도 이 클래스를 응용하여 보다 나은 방법으로 코딩의 실수 및 자원의 낭비를 줄일 수 있는 클래스를 작성해보기 바란다.

반응형
반응형

어느날 갑자기... PUTTY로 접속을 하려는데

다음과 같은 에러를 발생하며 접속이 안된다...

물론 id / password를 다 넣었다.

Server unexpectedly closed network connection

서버로 네트워크 연결이 예상지 못하게 종료되었습니다.

라는 뜻인데...

우선 로그를 살펴보았다.

/var/log/secure

 pam_unix(sshd:session): session opened for user test01 by test01(uid=100)
 pam_loginuid(sshd:session): set_loginuid failed opening loginuid
 pam_loginuid(sshd:session): set_loginuid failed

로그를보면 test01이라는 계정이 set_loginuid 의 열기 실패했다고 볼수 있다.

관련 내용을 구글링을 통해 검색해 보았다.

Server unexpectedly closed network connection

-> 즉 2가지 수정안인데... 나와 같이 특정계정만 막힌 경우는 해결되지 않았다.

 Server unexpectedly closed network connection"

라는 에러 메시지와 함께 접속 안 되는 경우가 생깁니다

그럴 경우에는 /etc/ssh/sshd_config 에서 UseDNS no 라고 추가 시켜 준 다음에

ssh 데몬(sshd)를 재시작(하거나 kill 로 죽인 다음에 다시 실행)하면 됩니다

추가
이전 키는 삭제 해야 합니다

리눅스에서는 ~계졍명/.ssh/known_hosts 에 해당하는 주소에 키를 삭제 하면 되고

윈도우에서 putty를 쓸 경우에는 레지스트리에서
HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\SshHostKeys
에 해당하는 키를 삭제하면 됩니다--moon.ft.co.kr

출처 : http://www.hostingland.co.kr/service/memo_view.htm?mode=view&code=memo&kind=h_qna&num=140448&idx_num=198

그러다가 로그의 내용을 중심으로 다시 구글링을 해보았다.

그랬더니 centos의 일종의 버그였다.

# grep pam_loginuid.so /etc/pam.d/*

/etc/pam.d/crond:session required pam_loginuid.so
/etc/pam.d/login:session required pam_loginuid.so
/etc/pam.d/remote:session required pam_loginuid.so
/etc/pam.d/sshd:session required pam_loginuid.so

위의 내용중 제일 하단에 결과를 보면 /etc/pam.d/sshd 파일의 세션 정보에서 pam_loguid.so를 사용함을 알수 있다.

즉, ssh를 통한 접속시 pam_loginuid를 이용하는 것을 알수 있다.

이부분을 # 처리하고

# service restart sshd

명령을 통해 sshd를 재시작하면 정상적으로 접속이 된다.

출처 : http://forums.powervps.com/showthread.php?p=19872

위의 출처를 통해 가보면 로그인을 통한 메모리 이득을 취할 수 있다고 하는데...

더 분석을 해봐야 겠다...
반응형

+ Recent posts