순서


1. 소개 

2. Abstract Factory 패턴 

3. State 패턴

4. chain of Responsibility 패턴 

5. Adapter 패턴

6. Bridge 패턴 

 

http://brad2014.tistory.com/344  <---  1,2편 (abstract factory 패턴) 은 여기링크.


3. State 패턴



* JDBC state 패턴은 위 전체 JDBC 패턴 모식도중 빨강 네모상자 안에서만 이루어집니다.

JDBC state 패턴을 공부하기 전에 잠시 JDBC 의 트랜잭션을 살펴보도록합시다.  


 JDBC 트랜잭션 기초 

JDBC API의 Connection 객체는 트랜잭션을 위하여 commit() 메소드와 rollback() 메소드를 제공한다.

 Connection 객체에는 setAutoCommit  이란 메소드가 있는데 기본값이 true 로 설정이 되어 있다. 

하나의 쿼리당 자동시작~자동커밋이 일어난다는 이야기이다그러나  여러 개의 쿼리 문장이 하나의 작업으로 수행되어야
할경우에  각각의 문장이 자동으로 작동되지 못하게 해야한다.
오토커밋이 자동으로 작동되지 못하게 하려면 
setAutoCommit(false); 
로 지정해야 한다.


자 그럼 begin() 은 어딨느냐?? 


AutoCommit = true 일경우



암시적으로 각각의 액션시 (각각 SQL 문에서)  자동으로 BEGIN()



AutoCommit = false  일경우



이건 좀 희안하다. setAutoCommit(false) 를 호출하여 오토커밋코드를 끄면  시스템은 이 호출과 동시에 


BEGIN 요청을 하게 된다. 이후의 commit() 과 rollback() 함수안에서  각각 작업을 한후에 마지막


에  begin() 을 요청하며 함수가 끝난다. 



그 밖에 setAutoCommit 을 통해 모드를 바꾸면  동시에 commit() 1회 발생한다.




코드1) 

 Connection conn = DriverManager.getConnection(.....); // connection 객체생성

conn.setAutoCommit(false); // 오토커밋 꺼버리고  

Statement stmt = conn.createStatement(); // statement 객체생성 String SQL = "INSERT INTO Employees VALUES (106, 20, 'Rita', 'Tez')";  

stmt.executeUpdate(SQL); conn.commit(); // 수동 커밋 ㄱㄱ 씽~




위의 JDBC 소개를 왜 했냐면 



 JDBC 에는 오토커밋이라는 상태를 가질것이냐, 안가질것이냐~  2가지 상태(STATE) 가 있다라는것을 말하고자 한것이다.







쉽게 설명한 State 패턴~  




state 패턴은 "상태에 기반을 둔 행위를 클래스로 만들어 놓은것이다.  즉 상태별 클래스를 만든것"



무슨이야기인지 실생활에 맞추어 설명해보면 


보통 사람들은   밥을 먹고, 길을 걷고 , TV 를 보는 행위를 한다. <-- 일반적인 행동..(함수) 

하지만 상태에 따라서 조금씩 달라질수있는데,


몸이 굉장히 아픈 상태에서는 = 죽을 천천히 먹을것이며

몸이 가뿐하며 돈이 많은 상태에서는 = 소고기를 폭풍흡입할것이다.


 ( 이런것은 자동차게임같은것에서 '달리다' 는 같지만 부스터를 사용했다처럼 상태를 갖는곳에 모두 사용될수있다)


"먹는다" 라는 행위를 상태 ( 아프냐, 안아프냐 ) 에따라서 다르게 행동하는 함수를 만들자는것인데 ..


사람이라는 클래스가 있다고 해보고 , 다음 코드를 보자.


class Person {

    public eat(){

    }

}


아래처럼  상태에 따라 다른 코드를  모두 클래스 내부에 넣는다면 


class Person {

    boolean state = 0;  // true 은 멀쩡함 , false 은 아픔 

   

    public eat(){

       if(state == true){

           // 폭풍흡입

       }

       else {

           // 겨우 목구멍에 넘김

       }

    }

 

}


이렇게 될것이다.  보통 이렇게도 많이 짠다. 이게 가독성 및 유지보수에 더 좋을수도있다.디자인패턴을 써서 퍼트리는것보다


(무조건적인 패턴 남발이 좋은건 아니다. 잘 판단해서 사용하자) 


State 패턴에서는 아래와 같이 짜는데 


위에 언급했듯이 state 패턴은 "상태에 기반을 둔 행위를 클래스로 만들어 놓은것이다. "


따라서 상태 ( 아프냐, 안아프냐를 ) 를 클래스로 만들고 상태에 기반을 둔 행위( eat , walk ) 를 함수로 만들어보자.


interface State{

  

    public void eat();

    public void walk();


}


class PainState implements Eat{


public void eat(){

     // 죽먹기

}


public void walk(){

...

}


}


class NormalState implements Eat{


public vodi eat(){

    // 고기 폭풍흡입 

}

public void walk(){

...

}


}


이렇게 상태에 따라서 먹는 클래스를 만들게 되는데, 전체 코드를 대략 만들어보면~(익명내부클래스로 인터페이스 상속기법)


class Person {

   

    private interface BodyState {   // 상태마다 공통으로 가져야할 행위를 나타내는 인터페이스

void eat();

void walk();

void setBodyState(boolean state);

    }


    private BodyState normal = new BodyState() {    // 멀쩡할때의 행위를 구현한 클래스


public void eat(){ .... 잘먹는다 ....}

public void walk(){ .... 잘 걷는다 ....}

public void setBodyState(boolean state){

if(state == false){

currentBodyState = pain;   // 상태 바꾸기

}

}

   }


    private BodyState pain = new BodyState() {    // 아플때  행위를 구현한 클래스


public void eat(){ .... 못 먹는다 ....}

public void walk(){ .... 못 걷는다 ....}

public void setBodyState(boolean state){

if(state == true){

currentBodyState = normal;   // 상태 바꾸기

}

}

   }



    public eat(){

        currentBodyState.eat();   // 이렇게 if 혹은 switch 문을 제거하였다. 현재 상태에 따라서 행동하게됨.

    }


public walk(){

currentBodyState.walk();   // 이렇게 if 혹은 switch 문을 제거하였다. 현재 상태에 따라서 행동하게됨.

}


    public setBodyState(boolean state){   // 외부에서 상태를 바꿔줌 ( 이 예에서는 하느님이 바꾸어주시겠지요 ^^) 

         currentBodyState.setBodyState(state); 

    }

 

    private State  currentBodyState = normal;

}



자 간단한 State 패턴 활용예를 살펴보았다. 이제 본격적으로 JDBC 에서 어떻게 활용되는지 살펴보자.


일단 위의 예를 이해했다면 JDBC 예는 누워서 떡먹기이다.





 JDBC 에서의 State 패턴 



 JDBC 에는 오토커밋이라는 상태를 가질것이냐, 안가질것이냐~  2가지 상태(STATE) 가 있다. 를 먼저 상기해보자.


 JDBC 의 connection 클래스 내부에서 저 오토커밋의 상태에 따라서 rollback, commit 가 다르게 일어난다.


다음 클래스 다어그램을 살펴보자.



 

               (그림 1) 


 이것은 (그림1) 위의 일반적인 State 패턴 예에서의 클래스 다이어그램이다.  사람 클래스가 상태클래스를 포함하고 있으며 


상태클래스는 Normal , Pain 2가지를 가지고있다는것을 확인하자. 





                                                                      (그림 2)

      

    이것은 JDBC 에서의 State 패턴인데, 위의 그림 1 과 똑같다. JDBCConnection 은 AutoCommitBehavior 을 구현한 


         concrete State 들에 따라서 행동을 하게된다.


코드를 살펴보면 이해가 더 빠를것이다.


다시 JDBC 의 수동커밋에 대한 예제 코드를 다시 보자


Connection conn = DriverManager.getConnection(.....); // connection 객체생성

conn.setAutoCommit(false); // 오토커밋 꺼버리고  

Statement stmt = conn.createStatement(); // statement 객체생성 String SQL = "INSERT INTO Employees VALUES (106, 20, 'Rita', 'Tez')";  

stmt.executeUpdate(SQL); conn.commit(); // 수동 커밋 ㄱㄱ 씽~


 conn.setAutoCommit(false)이 부분이 어떻게 구현되었는지 JDBCConnection 코드를 통해 살펴보자.


        

 public class JDBCConnection extends java.sql.Connection {


     public void commit() {

         autoCommitState.commit();    // 오토커밋 상태에 따라서  commit 을 처리한다.

     }


     public void rollback(){

autoCommitState.rollback();    // 오토커밋 상태에 따라서  rollback을 처리한다.

    }


    publci void setAutoCommit( boolean enable ){      // 이게 위의 예제에서  conn.setAutoCommit(false)이다.

autoCommitState.setAutoCommit(enable);

    }


    ....


    // 내부에 상태 인터페이스 및 내부익명클래스로 상태 클래스 2개를  만들어준다.

    private interface AutoCommitBehavior{

       void close();

       void commit();

       void rollback();

       void setAutoCommit( boolean enable );

    }

   

    private AutoCommitBehavior  enabled = new AutoCommitBehavior{   

   void close() { /* 아무것도 안한다 */ }

       void commit() { /* 아무것도 안한다 */ }

       void rollback() { /* 아무것도 안한다 */ }

       void setAutoCommit( boolean enable ){

if(enable == false){

   database.begin();

   autoCommitState = disabled;

}

       }


   }


   private AutoCommitBehavior  disabled = new AutoCommitBehavior{   

   void close() { 

       database.commit();

   }

       void commit() {

           database.commit();

           database.begin();

        }

       void rollback() 

           database.rollback();

           database.begin();

        }

       void setAutoCommit( boolean enable ){

if(enable == true){

   database.begin();

   autoCommitState = enabled;

}

       }


   }


    private AutoCommitBehavior  autoCommitState = enabled;

 }


코드를 유심히 살펴보면, 사실 State 패턴에 관한건 금방 이해할것이다.  autoCommitState 의 상태에 따라서 


rollback, commit 등이 이루어지고있다.패턴과 상관없이 기능적으로 코드 몇군데를 보면 보통 우리는 원격의 


DB에 접근을 하기때문에 dabatase 로 RPC 콜을 날려줄 것지만, 1부에 말했다시피, 임베디드DB 이기때문에 


database.commit() 처럼 직접 호출해주는 부분이 있다.


그 밖에 헤깔릴수있는 부분은 , 


왜 database.begin(); 이 commit / rollback 함수 안에 있냐 ? 


왜 setAutoCommit 을 호출하면 database.begin(); 을 해주냐? 


인데, 이것이 궁금하다면  이 게시물 가장 처음에 있는  JDBC 트랜잭션 기초를 다시 읽어보자~


다음엔 Adapter 패턴에 대해서 알아보자.



레퍼런스 :  실용주의 디자인 패턴 (http://www.kangcom.com/sub/view.asp?sku=200607180006)




p.s  해당글에 대한 질문이 올라온것에 대한 답변 



질문: 



State 패턴의 의도가 상태별 클래스를 만들어두는 것이라고 하셨는데,

위 예제처럼 내부에서 사용보다 외부로 빼서 확장성있게도 사용이 이루어지나요?


답변:


보통 외부로 빼서 구현합니다. 본문의 예가 "일반적" 이라고 보기 힘듭니다.

자바라는 언어가 저렇게 내부클래스를 지원하니 그 기능을 십분 발휘한것일뿐이에요 ^^


사실 디자인패턴을 쓰면  소스를 너무 퍼트려 놓는데, 때로는 그게 가독성에 지장을 줄수도

있지 않겠습니까. (if , switch 문이 전체맥락보기 편할때가 많은거 같습니다. 소스수정도 IDE 가 워낙 강력해

서 뭐... 개인적인 생각입니다.) 


따라서 자바 언어의 기능을 살려서,  유연함을 주되,  소스를 찾으러 멀리가지 않게 하였다. 정도로 보시면 될거 같습니다. (클래스 내부에 있는 인터페이스를 보고 전체 상태별 기능을 한눈에 보게하자)


아래 코드처럼 외부 클래스를 컴포지션해서 할수도 있습니다. (DI  로도 )

class people {

    state n_state = new normalState;

    state p_state = new painState;

    state s;

    eat(){

         s.eat();

    }

    setState(int i){

         if(i ==  0)

         	s = n_state;

         else (i == 1)

                s = p_state;

    }

}

interface state{

   eat();

}

class normalState implements state{

     eat(){ ....}

}



class painState implements state{

     eat(){ ....}

}


원하는 답변인지 잘 모르겠네요 ;;;    

혹 다른 생각하시는 구현이 있으면 보여주시면 의사소통이 원할할듯 합니다. 감사합니다.

JDBC 기본 트랜잭션 


JDBC API의 Connection 객체는 commit() 메소드와 rollback() 메소드를 제공한다.

기본적으로 Connection 객체에 setAutoCommit 이란 메소드가 있는데 기본값이 true 로 설정이 되어 있다. 

하나의 쿼리당 자동시작~자동커밋이 일어난다는 이야기이다.

그러나  여러 개의 쿼리 문장이 하나의 작업으로 수행되어야 할경우에  각각의 문장이  자동으로 작동되지 못하게 해야한다.

오토커밋이 자동으로 작동되지 못하게 하려면 setAutoCommit(false); 로 지정해야 한다.



자 그럼 begin() 은 어딨느냐?? 


AutoCommit = true 일경우



암시적으로 각각의 액션시 (각각 SQL 문에서)  자동으로 BEGIN()



AutoCommit = false  일경우



이건 좀 희안하다. setAutoCommit(false) 를 호출하여 오토커밋코드를 꺼넣으면 시스템은 이 호출과 동시에 BEGIN 요청을 하게


된다. 이후의 commit() 과 rollback() 호출은 해당 SQL 을 호출한 뒤에 다시 BEGIN() 을 요청하게된다. 




그 밖에 setAutoCommit 을 통해 모드를 바꾸면  동시에 commit() 1회 발생한다.






JDBC Savepoint  

번역: http://www.tutorialspoint.com/jdbc/jdbc-transactions.htm


새로운 JDBC 3.0 Savepoint interface 는 추가적인 트랜잭션기능을 제공하는데 . Oracle's PL/SQL 같은 많은 현대 DBMS 에서는 그들의 환경내에 savepoints 를 지원하고있다.  당신이 세이프포인트를 세팅할때 트랜잭션안에 논리적 롤백 포인트를 정의할수있다.

만약 에러가  세이프포인트뒤에 발생하면 , 모든 변경사항 또는  세이브포인트 후에 만들어진 변화를 undo 를 하기위해  롤백메소드를  사용할수있다. 

Connection 객체는 2가지 새로운 메소드로 세이브포인트를 요리할수있도록 도와준다.

  • setSavepoint(String savepointName):  새로운 세이브포인트를 정의하고 그 객체를  리턴받는다.

  • releaseSavepoint(Savepoint savepointName): 세이브포인트 삭제. 

 rollback (String savepointName) 는  특정 세이브포인트로 작업을 롤백한다.


다음 예를 통해 살펴보자.

try{ conn.setAutoCommit(false); Statement stmt = conn.createStatement(); // Savepoint 설정 Savepoint savepoint1 = conn.setSavepoint("Savepoint1"); String SQL = "INSERT INTO Employees " + "VALUES (106, 20, 'Rita', 'Tez')"; stmt.executeUpdate(SQL); String SQL = "INSERTED IN Employees " + "VALUES (107, 22, 'Sita', 'Tez')"; stmt.executeUpdate(SQL); conn.commit(); }catch(SQLException se){ conn.rollback(savepoint1); }


문제가 생기면 savepoint1 까지 롤백된다. insert 문은 작동안하겠지


좀더 구체적인 예를 살펴봅시다.

//STEP 1. 관련 패키지 임포트 import java.sql.*; public class JDBCExample { static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost/EMP"; static final String USER = "username"; static final String PASS = "password"; public static void main(String[] args) { Connection conn = null; Statement stmt = null; try{ //STEP 2: JDBC 드라이버 등록 Class.forName("com.mysql.jdbc.Driver"); //STEP 3: connection 맺고 System.out.println("Connecting to database..."); conn = DriverManager.getConnection(DB_URL,USER,PASS); //STEP 4: 오토 커밋 않하게함 conn.setAutoCommit(false); //STEP 5: statment 생성 System.out.println("Creating statement..."); stmt = conn.createStatement(); //STEP 6: 모든 데이터 가져오기 String sql = "SELECT id, first, last, age FROM Employees"; ResultSet rs = stmt.executeQuery(sql); System.out.println("List result set for reference...."); printRs(rs); // STEP 7: 세이브 포인트1 설정 Savepoint savepoint1 = conn.setSavepoint("ROWS_DELETED_1");  

// STEP 8: ID = 110 삭제

System.out.println("Deleting row...."); String SQL = "DELETE FROM Employees WHERE ID = 110"; stmt.executeUpdate(SQL);  

// 엇.. 잘못된 놈을 지웠네.. //STEP 8: Rollback the changes afetr save point 2. conn.rollback(savepoint1); // STEP 9: 세이브 포인트 2 설정 Savepoint savepoint2 = conn.setSavepoint("ROWS_DELETED_2");  

System.out.println("Deleting row...."); SQL = "DELETE FROM Employees WHERE ID = 95"; stmt.executeUpdate(SQL); //STEP 10: Now list all the available records. sql = "SELECT id, first, last, age FROM Employees"; rs = stmt.executeQuery(sql); System.out.println("List result set for reference...."); printRs(rs); //STEP 10: Clean-up environment rs.close(); stmt.close(); conn.close(); }catch(SQLException se){ //Handle errors for JDBC se.printStackTrace(); // If there is an error then rollback the changes. System.out.println("Rolling back data here...."); try{ if(conn!=null) conn.rollback(); }catch(SQLException se2){ se2.printStackTrace(); }//end try }catch(Exception e){ //Handle errors for Class.forName e.printStackTrace(); }finally{ //finally block used to close resources try{ if(stmt!=null) stmt.close(); }catch(SQLException se2){ }// nothing we can do try{ if(conn!=null) conn.close(); }catch(SQLException se){ se.printStackTrace(); }//end finally try }//end try System.out.println("Goodbye!"); }//end main public static void printRs(ResultSet rs) throws SQLException{ //Ensure we start with first row rs.beforeFirst(); while(rs.next()){ //Retrieve by column name int id = rs.getInt("id"); int age = rs.getInt("age"); String first = rs.getString("first"); String last = rs.getString("last"); //Display values System.out.print("ID: " + id); System.out.print(", Age: " + age); System.out.print(", First: " + first); System.out.println(", Last: " + last); } System.out.println(); }//end printRs() }//end JDBCExample

다음처럼 컴파일하고

C:\>javac JDBCExample.java
C:\>

JDBCExample 실행하면 다음과 같이 나오게된다. 

C:\>java JDBCExample
Connecting to database...
Creating statement...
List result set for reference....
ID: 95, Age: 20, First: Sima, Last: Chug
ID: 100, Age: 18, First: Zara, Last: Ali
ID: 101, Age: 25, First: Mahnaz, Last: Fatma
ID: 102, Age: 30, First: Zaid, Last: Khan
ID: 103, Age: 30, First: Sumit, Last: Mittal
ID: 110, Age: 20, First: Sima, Last: Chug

Deleting row....
Deleting row....
List result set for reference....
ID: 100, Age: 18, First: Zara, Last: Ali
ID: 101, Age: 25, First: Mahnaz, Last: Fatma
ID: 102, Age: 30, First: Zaid, Last: Khan
ID: 103, Age: 30, First: Sumit, Last: Mittal
ID: 110, Age: 20, First: Sima, Last: Chug

Goodbye!
C:\>


ORACLE  Savepoint
펌 : http://reiphiel.tistory.com/entry/jdbc-transaction-savepoints

  

SQL예(오라클)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
INSERT INTO TEST_USER (NAME) VALUES ('JOHN');
 
SAVEPOINT MARK;
INSERT INTO TEST_USER (NAME) VALUES ('MARK');
 
SAVEPOINT JACK;
INSERT INTO TEST_USER (NAME) VALUES ('JACK');
 
SAVEPOINT PAUL;
INSERT INTO TEST_USER (NAME) VALUES ('PAUL');
 
ROLLBACK TO JACK;
 
INSERT INTO TEST_USER (NAME) VALUES ('JANE');
 
COMMIT;


실행 결과




SQL문은 실행한 결과는 위와 같은데 SAVEPOINT로 특정 세이브포인트까지 롤백을 하게되면 롤백실행한 


부분부터지정한 세이브 포인트까지 롤백 되는 것을 알수있다. 



구조적으로 나중에 지정한 세이브포인트는 직전 세이브 포인트에 종속적이라고 보면 되겠다. 


중첩된 트랜잭션이라고 보면 되겠다. 그리고 지정한 세이브포인트 이전과 롤백을 실행한 이후의 SQL에는 


영향을 미치지 않았다는 것을 알 수 있다.



디자인 패턴을 공부할때 가장 유념해야할 단어는 "의도" 이다.  절대 모양 (구조) 가 아니다.  그리고 구현함에 있어서 책 등에 나와 있는 모양 그대로 구현하려고 할 필요도 없다. 너무 잘 하려고 하다보면 아예 하지도 못할지도 모른다.  "의도" 만 확실히 이해한 다음에 구현을 이것저것 거침없이 하다보면.... 코딩에 대한 재미는 생겨날 것이다. 재미는 실력향상을 의미하기도 하고 ~  

JDBC 는 자바에서 정한 DB 와의 관계에 대한  행동 지침이다. 행동지침을 공통화하려면 어느 정도의 유사성이 있어야 한다. 세상에는 많은 자동차가 있지만 행동 지침은 비슷하다. 그러기에 운전자들이 다른 메이커의 자동차를 운전하더라도 어느정도는 쉽게 할수있지 않은가.. 마찬가지로  세상에는 많은  DB 가 있고.   각각의 DB 에서 데이터를 가져오는 방법(행동) 이  DB  마다 다르다면 따로 따로 공부를 해야하지만 , 행동지침이 정해져 있고, 모든 DB 가 그것에 맞춰서 개발을 한다면 , 개발자는 정해져있는 행동지침 ( JDBC ) 만 공부하면 된다.  

JDBC  를 디자인패턴과 함게 묶은 이유는 ,  일단 디자인 패턴을 이해하는 가장 효율적인 방법은 다른사람(특히 구루들) 이 잘 구현해놓은 코드(패턴)을 보고 감흥하는것인데 JDBC 를 구현한 코드들에는 몇몇개의 패턴이 뚜렷하게 녹아져 있다.  

순서

1. 소개 

2. Abstract Factory 패턴 

3. State 패턴

4. Adapter 패턴

5. Bridge 패턴 

6. chain of Responsibility 패턴

 



1. 소개 

이 글은 JDBC 에 녹아져있는 패턴들을 살펴볼것인데 , 그 전에  DB 에 대해서 잠시 살펴보자.

가. DB  

A 군은  학교/학원에서 자바 / 객체지향 프로그래밍을 배웠습니다.  무엇을 만들어 볼까 생각하다가 "오키" 에 물어보니 DB 를 만들어 보라는 댓글을 보고 DB 에 대해 곰곰히 생각해 보았습니다.  데이터를 저장한다라..   - .-a
그래 결심했어!! 이름은 HAMASQL 이라고 짓고 . 
일단 데이타베이스는 '폴더' 라고 하자.  그리고 테이블을 '파일' 이라고 하자.!! 그리고 파일에 한줄씩 콤마(,) 로 나누어서 컬럼을 구분하고 , 각각의 데이터를 문자열로 넣자.  이렇게 되면 데이타베이스 하나에 테이블이 여러개 들어갈것이다.

PSEUDO  코드 

class HAMADatabase {

   public  createDatabase(String db_path , String db_name) {

             makeDirectory(db_pathdb_name);    // db_path위치에 , db_name이라는 폴더를 만들어라.

   }

}

class Table {

  String [] column;

   public  createTable(String db_path, String name, String column){

makeFile(db_path, name);       // db_path 데이타베이스에 name 이라는 테이블( 파일 ) 을 만들고,               

    this.column = column.split(',');   // 컬럼은 column 문자열에서 , 로 토큰을 나누자.      

   }

   public insertRow(...) ...

   public deleteRow(...) ...

   public updateRow(...) ...

   public select(...) ...

}

class Cursor {

    ...

}

                                                                     (코드 -1)

자 일단 데이터를 저장하는 방법과 클래스를 작성했고 (-.-)  
이제 사용자와의 커뮤니케이션을 해야하는데 SQL  언어를 통해서 명령을 받아드려야지.
SQL 엔진은 인터프리터 패턴으로 개발하자. (http://brad2014.tistory.com/200자 이제 SQL 엔진도 개발했고 

(-.-;;  이 글은 JDBC  디자인패턴이 목적이니 양해를..이제 JDBC 인터페이스만 구현하면 될것 같다.  !!!

나. JDBC 

                             (그림 1: http://docstore.mik.ua/orelly/java-ent/jenut/ch18_01.htm 이미지참조)

위의 이미지는 java.sql 패캐지에 포함되어 있는 개별 JDBC 드라이버를 만들기 위한 뼈대(인터페이스) 입니다.우리는 저기에서 Connection / Driver / PreparedStatement/ ResultSet / 등을 구현하면서 패턴이 어떤식으로 적용되는지 자세하게 살펴볼 것입니다.

먼저 인터페이스 각각을 간략하게 설명하자면 java.sql 패키지는 전체 JDBC API 를 포함합니다.  SQL 구문을 데이타베이스에 보내며 그것에 따른 결과셋을 가져오는데  Driver 인터페이스는 특정 데이타베이스를 위한 JDBC 구현을 하게되며 , Statement 등등은 SQL 구문을 실행하는데 사용됩니다.  ResultSet 은 데이타베이스에 의해 SQL 명령이 실행되어진후에 결과 데이터 를 담게되며, 커서등을 통해서 최종 사용자가 데이터를 사용하게됩니다. ResultSetMetaData 는 ResultSet 의 메타데이터를 담당하게되며 DatabaseMetaData 는 데이타베이스 전체에 대한 메타데이터를 제공합니다.

다. JDBC 구현 전체 클래스 다이어그램 및 패턴 

                                       (그림 2) 

이것은 "실용주의 디자인 패턴 그림 4-18" 을 조금 각색한 그림이다.힘들게 그리고 이렇게 올려두니 매우 뿌듯하다. ^^
간략히 소개하자면

1. 연한주황색은 인터페이스이다. 이것은 java.sql 패키지에서 기본적으로 제공하는것으로 "공통 행위 지침" 이다.  
2. 검정색 네모칸은 우리가 구현한 클래스를 나타낸다. 인터페이스를 상속받았다. (  ◁-----  : 인터페이스 상속
3. 색깔이 있는 동그란원은 특정 패턴을 나타낸다. 그것과 연결된 점선은 해당 패턴에 포함된 클래스들이다. 
4. <----  점선 화살표는 의존관계를 나타낸다. DriverManager 는 HAMADriver / HAMADriver 는 HAMAConnection 의존한다.
5. ◆-----  다이아몬트 직선은복합연관(컴포지트) 관계이며, ◇------ 빈다이아몬드 직선은 집합연관 관계이다.

   중요한 차이점은 복합연관 관계는 좀더 강한 결합관계를 가진다. 즉  HAMAResultSet 이 소멸되면 Cursor 도 소멸한다. 

위의 JDBC 구현을  사용하는 예 살펴보자. 

static final String JDBC_DRIVER = "com.hama.jdbc.HAMADriver"; static final String DB_URL = "jdbc:hama://localhost/EMP"; // 1. JDBC driver 등록 Class.forName(JDBC_DRIVER); // 2. DB 로의 connection conn = DriverManager.getConnection(DB_URL,USER,PASS); // 3. Statement 를 통한 Query 명령 stmt = conn.createStatement(); String sql = "SELECT id, age FROM Employees";   // 4. result set 으로 부터 데이터 가져오

ResultSet rs = stmt.executeQuery(sql); // 5. 커서를 통해 한 로우씩 while(rs.next()){ // 6. 한 컬럼씩 가져오기 int id = rs.getInt("id"); int age = rs.getInt("age"); } (코드 -2)                    

MySQL 을 사용할때  jdbc:mysql  를 사용한것처럼 jdbc:hama 를 사용하였으며 , DriverManager 는 저것을 통해 DB를 구분한다.  나의 디비를 접속하기위해 새로만든 com.hama.jdbc.HAMADriver  를 사용한다. MySql 을 사용한다면 

com.mysql.jdbc.Driver 를 사용해야할것이다.

1. 내가 만든 JDBC 드라이버 클래스를 로딩한다. (로딩함과 동시에 내부에서 HAMADriver 인스턴스를 생성한후에 DriverManager 에게 넘겨준다.)
2.  DriverManager 는 1번에서 얻게된 HAMADriver  를 통해서 디비에 접속한후에 HAMAConnection 객체를 얻는다. 
3. HAMAConnection 클래스를 통해서 HAMAStatement 객체를 생성한다. 
4. HAMAStatement  클래스를 통해서 디비에 쿼리명령을 실행후 ResultSet 로 테이블의 일부분의 데이터를 가져온다. 
5. ResultSet 안의 커서를 통해서 ROW 별로 접근한다.
6. 하나의 컬럼에 접근한다. 

자 JDBC 에 대해 전반적인 사항을 알아보았다. 이제 진짜 패턴에 대해서 집중해서 살펴보자. 



2. Abstract Factory 패턴 

JDBC 에서 사용하는 패턴중 가장 눈에 뛰는 패턴은 "Abstract Factory" 이다.  위의 그림 2를 보면 Abstract Factory 으로 빼곡한 모습을 볼수있다. 한부분을 떼어내 보면 아래 그림과 같다.

                    (그림 3) 
공장역활을 하는것은 Driver 이며 , 공장이 만들어 내는것은 Connection 이다.
JDBC 에서 특이한것은 생산품이 다시 공장역할을 한다는것인데 Connection  이 생산품에서 
공장역할을 하게되면 , Connection   의 생산품은 ?  그렇다 Statement 클래스가 된다. 

Abstract Factory 의 모호함

패턴중에 가장 이름에 현혹되지 말아야하는 패턴이 Abstract Factory  라고 생각한다. 서두에도 말했다시피 패턴은 "의도" 가 가장중요한데 , 이 패턴은 이름으로 의도를 느끼기에는 좀 힘든면이 있다. Abstract Factory 는 의도를 전혀 나타내고 있지 못한다. Abstract Factory 는 단지 Abstract Factory 패턴에서 이루어지고있는 "의도" 에 하나의 부품일 뿐이다.  Abstract Factory 는 Bridge 패턴과 함께 , 패턴이라기보다는 아키텍처를 나타낸다고 볼만큼 규모가 있는 느낌의 패턴이다.  그래서 실제로 일반개발자가 이 패턴을 사용할일은 그다지 많지 않다. 

팩토리!!! 란 무엇인가?  

팩토리는 무엇인가를 만들어 주는 공장이다. 실생활에서 우리는 공장에 집중하지 않는다. 공장에서 만들어주는 "어떤것"에 더 친숙하고 집중하게 되는데 Abstract Factory 패턴에서도 마찬가지이다. Abstract Factory 는 무엇인가를 만들어주는것이며, 실제 만들어지는것이 우리가 집중해야할 "어떤것" 이다.  이름에서 느껴지듯이 Abstract Factory  는 실제 무엇을 만들수있는 공장이 아니다. 어떤 방식으로 만들라는 "행동지침" 만 정의하며 실제 공장은 concrete Factory 라고 한다.  위의 JDBC 에서는 그림 1을 보자. Abstract Factoryjdbc.sql.Driver 인터페이스이며  Concrete Factory 는 그것을 구현상속한 HAMADriver 가 된다.  팩토리는 공장이며, 위에 말한것처럼 "어떤것" 을 만들어주는 역할을 한다고 했다. 그럼 HAMADriver  라는 Concrete Factory 가 만들어주는 "어떤것" "상품" 은 무엇이 될까?

그것은 바로 jdbc.sql.Connection 을 상속받은 HAMAConnection 이 바로 Concrete Product 가 된다.   

코드로 보면 (PSEUDO

// abstract factory   :  필요한 생산품 ( Connection ) 을 생산하는 추상공장 


interface Driver {

public Connection connect(String url);

}


// concrete factory  :  실제 필요한 생산품 ( HAMAConnection or MySQLConnection ) 을 생산하는 실제공장 

class HAMADriver implements java.sql.Driver{


public Connection connect(String url) {

return new HAMAConnection(url);

}


}

// abstract product  : 생산품의 공통  행동 양식을 나타내는 인터페이스 ( Connection )

interface Connection {

public close();

public commit();

public createStatement();

}


// concrete Product  : 구체적인 생산품  ( HAMAConnection or MySQLConnection  )

class HAMAConnection implements java.sql.Connection{


   private HAMADatabase database;

   public HAMAConnection(Sting url) {

database = new Database(url);

   }

   public close() {

      ...

   }

   public commit() {

     . ..

   }

   public Statement createStatement() {

return new HAMAStatement(database);

   }


}

이걸 왜 쓰는건가?  

실생활에서 공장에는 여러가지의 공장(자동차, 핸드폰) 이 있을수 있다. 

=> JDBC 를 구현하는 DB 에는 여러가지가 있다.

생산되는 제품(핸드폰) 은 회사마다 내부작동법 (아이폰, 갤럭시 ) 이 다양할수있다. 

=> Connection 하는 방법, 데이터를 가져오는 방법은 DB 마다 다르다. 

이처럼 공장과 생산품을 클래스로 분류시켜놓으면 새로운 공장 / 새로운 생산품을 기존의 시스템에 끼워넣을때 

기존의 코드는 전혀 건드리지 않아도 된다는 장점이 있습니다. 대규모의 프로덕트'군'의 추가/삭제가 유연해 진다는것이지요.

여기에 중요한 장점이 추가되는데 

공장이나 생산품을 사용하는 방법은 회사마다 내부 구현은 다르지만 , 사용자한테는 동일합니다. 핸드폰의 경우를 예로들면 내부적으로는 다르겠지만 외부적으로는 ,"통화하기" "인터넷보기" 처럼 같으며 자동차를 예로들면 엔진은 다르겠지만 "핸들돌리" "브레이크 밟기" 는 동일합니다.

무슨 이야기냐하면. Abstract Factory 를 사용하면 클라이언트는 어떤 프로덕트 '군' 이 추가되더라도 기존에 사용하는 방식 그대로 사용할수 있게됩니다. 위의 예에서 MySQL 의 JDBCDriver 를  사용하던 방법대로 HAMA DB 의 JDBCDriver ( 위에서는 HAMADriver) 를 어떤 추가적인 러닝커브 없이도 바로 사용할수 있다는 점이지요. ^^ 

단점 

만약 생산품이 원하는 기능이 없거나 그게 아니라면 Abstract Product 의 인터페이스를 추가하거나 고쳐야하며 이 이야기는 그것을 구현한 모든것의 변경을 요한다는 점이다.jdbc.sql.Driver 에서 어떤 큰 변경이 일어난다면 그것을 구현한 수 많은 데이타베이스 밴더( 오라클, MySQL 등) 이 골치아파진다는 이야기이다.

다른 사용 예

사용Abstract FactoryConcrete 
Factory

Abstract
Product
Concrete Product
JDBCjava.sql.DriverHAMADriver /
MySQLDriver
java.sql.ConnectionHAMAConnection/
MySQLConnection
Collection 
Collection LinkedList /
Tree / 
IteratorLinkedListIterator/
TreeIterator
UI systemUIFactoryWindowUIFactory/
LinuxButton
ButtonWindowButton / 
LinuxButton 


다음에는 State 패턴에 대해서 알아보겠습니다~ 




레퍼런스 :  실용주의 디자인 패턴 (http://www.kangcom.com/sub/view.asp?sku=200607180006)



네트워크를 사용하는 대부분의 안드로이드 앱은 HTTP 을 사용해서 데이터를 주고 받는다. 

안드로이드는 두가지 HTTP 클라이언트 클래스를 가지고있는데, HttpURLConnection  과 Apache HTTP Client 이다. 

둘다 HTTPS 를 지원하며, 스트리밍 업로드, 다운로드 와 타임아웃 설정 , IPv6 및 커넥션 풀링등을 지원한다.


Apache HTTP Client

DefaultHttpClient 와 그것의 형제인 AndroidHttpClient 는 웹 브라우저에 맞춰진  HTTP 클라이언트 확장이다. 다양하고 유연

한 API 들을 가지고있는데 안정되고 거의 버그가 없다. 그러나 그런 커다란 API 사이즈는 하위호환성을 깨지 않고 개선 시키기

가 어려우며 안드로이드 팀은 그것을 적극적으로 사용하지 않는다.




HttpURLConnection

HttpURLConnection 는 대부분의 어플리케이션에 적합한 일반적인 목적의 가벼운 HTTP 클라이언트이다. 이 클래스는 조금 

기초적인 기반을 가지고있지만, 안정적으로 향상시킬수있기 쉽게 되어있다. 프로요 버전 이전에 HttpURLConnection 은 약간의 

버그를 가지고있었다. 특히 readable InputStream 에서 close() 를 부르는것은 커넥션 풀을 맛가게 할수 있었다.


private void disableConnectionReuseIfNecessary() {

   
// HTTP connection reuse which was buggy pre-froyo
   
if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
       
System.setProperty("http.keepAlive", "false"); // HTTP 커넥션 재사용은 HTTP 의 KeepAlive 옵션의 역할
   
}
} KeepAlive 란? http://brad2014.tistory.com/341


진저브레드 버전에서는 transparent response compression  를 추가했다. HttpURLConnection 는 자동적으로 이 헤더를 요청

에 추가하고 돌아오는 응답을 핸들링할것이다.


Accept-Encoding: gzip


만약 응답 압축이 문제가 있을때  class documentation  를 보면 어떻게 비활성화 시킬수있는지 나와있다.

HTTP 의 Content-Length 헤더는 압축된 사이즈를 돌려주기 때문에 비 압축 데이터의 버퍼 크기를 그것으로 잡으면 에러가 생길

수 있다. 대신해서  InputStream.read() 이 -1 을 리턴할때까지 읽어야한다. 

우리는 또한 진저브레드 버전에서 여러가지 HTTPS 향상을 이루어냈는데 HttpsURLConnection  는 SNI(Server Name 

Indication) 을 가지고 접속 시도를 한다. 그것은 IP 주소를 공유하기위해 multiple HTTPS 호스트를 허용한다. 또한 세션 티켓들

과 압축을 활성화 할수있다. 커넥션 실패일때 자동적으로 재시도한다. 이것은 오래된것에 대한 호환성을 깨지 않고  최신의 서버

에 접속할때 HttpsURLConnection 를 효율적이게 만든다.


아이스크림 샌드위치에서 응답캐쉬를 추가했고,  HTTP 요청은 3가지방법중 하나로  이루어진다.


- 완전한 캐쉬 응답은 로컬 스토리지로부터 직접적으로 서비스된다. 

- 상황에 따라서 캐쉬된 응답은 최신의 것이라는것이 웹서버에 의해 검증된다. 클라이언트는 “Give me /foo.png if it changed 

   since yesterday”  같은 요청을 보내며 , 서버는 업데이트된 내용을 보내주거나 304 Not Modified 상태를 보내준다.."컨텐츠

   가 그대로니깐 다운로드될 필요없다라는~"

- 캐쉬되지 않은 응답은 웹으로부터 서비스되며 이 응답은 후에 응답캐쉬에 저장될것이다.


리플렉션을 사용하여 디바이스상에 HTTP 응답캐쉬를 활성화하는 샘플. 이 샘플은 이전 버전에는 영향없이 아이스크림 샌드위치

버전부터 응답캐쉬를 작동시킨다. 


private void enableHttpResponseCache() {

   
try {
       
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
       
File httpCacheDir = new File(getCacheDir(), "http");
       
Class.forName("android.net.http.HttpResponseCache").getMethod("install", File.class, long.class)
           
.invoke(null, httpCacheDir, httpCacheSize);
   
} catch (Exception httpResponseCacheNotAvailable) {
   
}
}

* HTTP 응답상의 케쉬헤더를 세팅하기위해 웹서버를 설정해야한다. 



그래서 뭐가 좋은건데? 


apache HTTP client 는  Eclair and Froyo 에서 아주 작은 버그를 가지고있고 저 버전을 사용할땐 베스트이다.

진저브레드에서는 HttpURLConnection  가 베스트이다. 그것의 단순함과 작은 사이즈는 안드로이드에 딱이다.

Transparent comppression 과 응답캐싱은 네트워크 부하를 줄이고 속도를 향상시키며 베터리에도 좋다. 

새로운 어플리케이션은 HttpURLConnection   로 하자. 

 


정규표현식은 아주 가끔 쓰기때문에 항상 다시 볼때마다 헷갈리곤 하기에
주요 사용예를 내가 나중에 다시 봤을 때 편하도록 정리하여 보았다. 



정규 표현식의 용어들정규 표현식에서 사용되는 기호를 Meta문자라고  표현한다. 표현식에서 내부적으로 특정 의미를 가지는 문자를 말하며 간단하게 정리하면 아래의 표와 같다.

 표현식
의미 
 ^x
 문자열의 시작을 표현하며 x 문자로 시작됨을 의미한다.
x$
 문자열의 종료를 표현하며 x 문자로 종료됨을 의미한다.
 .x
 임의의 한 문자의 자리수를 표현하며 문자열이 x 로 끝난다는 것을 의미한다.
 x+
 반복을 표현하며 x 문자가 한번 이상 반복됨을 의미한다.
 x?
 존재여부를 표현하며 x 문자가 존재할 수도, 존재하지 않을 수도 있음을 의미한다.
 x*
 반복여부를 표현하며 x 문자가 0번 또는 그 이상 반복됨을 의미한다.
 x|y
 or 를 표현하며 x 또는 y 문자가 존재함을 의미한다.
 (x)
그룹을 표현하며 x 를 그룹으로 처리함을 의미한다.
 (x)(y)
그룹들의 집합을 표현하며 앞에서 부터 순서대로 번호를 부여하여 관리하고 x, y 는 각 그룹의 데이터로 관리된다.
 (x)(?:y)
그룹들의 집합에 대한 예외를 표현하며 그룹 집합으로 관리되지 않음을 의미한다. 
 x{n}
 반복을 표현하며 x 문자가 n번 반복됨을 의미한다.
 x{n,}
 반복을 표현하며 x 문자가 n번 이상 반복됨을 의미한다.
 x{n,m}
 반복을 표현하며 x 문자가 최소 n번 이상 최대 m 번 이하로 반복됨을 의미한다.

Meta 문자들 중에서 좀 더 특수하게 사용되는 문자들이 존재한다. '[]' 는 내부에 지정된 문자열의 범위 중에서 한 문자만을 선택하다는 특수한 의미를 가진다. 그리고 내부에서 Meta문자를 사용하면 다른 의미를 가지고 동작할 수 있으므로 잘 확인하고 사용해야 한다. 좀 더 특별한 용도로 사용되는 것들은 아래의 표와 같다. 

 

 표현식
의미 
[xy]
문자 선택을 표현하며 x 와 y 중에 하나를 의미한다.
 [^xy]
not 을 표현하며  x 및 y 를 제외한 문자를 의미한다.
 [x-z]
range를 표현하며 x ~ z 사이의 문자를 의미한다. 
 \^
escape 를 표현하며 ^ 를 문자로 사용함을 의미한다.
 \b
word boundary를 표현하며 문자와 공백사이의 문자를 의미한다.
 \B
non word boundary를 표현하며 문자와 공백사이가 아닌 문자를 의미한다.
 \d
digit 를 표현하며 숫자를 의미한다. 
 \D
non digit 를 표현하며 숫자가 아닌 것을 의미한다. 
 \s
space 를 표현하며 공백 문자를 의미한다. 
 \S
non space를 표현하며 공백 문자가 아닌 것을 의미한다.
 \t
tab 을 표현하며 탭 문자를 의미한다.
 \v
vertical tab을 표현하며 수직 탭(?) 문자를 의미한다.
 \w
word 를 표현하며 알파벳 + 숫자 + _ 중의 한 문자임을 의미한다. 
 \W
non word를 표현하며 알파벳 + 숫자 + _ 가 아닌 문자를 의미한다. 


정규표현식을 사용할 때 Flag 라는 것이 존재하는데 Flag를 사용하지 않으면 문자열에 대해서 검색을 한번만 처리하고 종료하게 된다. Flag는 다음과 같은 것들이 존재한다.

 Flag
의미 
 g
Global 의 표현하며 대상 문자열내에 모든 패턴들을 검색하는 것을 의미한다. 
 i
Ignore case 를 표현하며 대상 문자열에 대해서 대/소문자를 식별하지 않는 것을 의미한다.
 m
Multi line을 표현하며 대상 문자열이 다중 라인의 문자열인 경우에도 검색하는 것을 의미한다. 


사용 예제 

개별 숫자 - /[0-9]/g

전체에서  0~9사이에 아무 숫자 '하나'  찾음 

개발 문자 - /[to]/g

전체에서 t  혹은 o  를 모두 찾음 

단어 - /filter/g

전체에서  f 따로 i 따로 찾는게 아니라 'filter' 라는 단어에 매칭되는것을 찾음 

단어 제외 - /\b(?:(?!to)\w)+\b/g

전체에서 'to' 라는 단어를 빼고 다른 단어 매칭 /  확인결과 "Tutorial" 도 제외됨. 

단어 제외 - \b(?!\bto\b)\w+\b

전체에서 'to' 라는 단어를 빼고 다른 단어 매칭 /  확인결과 "Tutorial" 는 제외 안됨.  이게 더 정확하다고 볼수있을듯. 

 

이메일 - /^[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i

'시작을'  0~9 사이 숫자 or a-z A-Z 알바펫 아무거나로 시작하고  /  중간에 - _  . 같은 문자가 있을수도 있고 없을수도 있으며 / 

그 후에 0~9 사이 숫자 or a-z A-Z 알바펫중 하나의 문자가 없거나 연달아 나올수 있으며 /  @ 가 반드시 존재하고  / 

0-9a-zA-Z 여기서 하나가 있고  /  중간에 - _  . 같은 문자가 있을수도 있고 없을수도 있으며 / 그 후에 0~9 사이 숫자 or a-z A-Z 알바펫중 하나의 

문자가 없거나 연달아 나올수 있으며 /  반드시  .  이 존재하고  / [a-zA-Z] 의 문자가 2개나 3개가 존재 /   이 모든것은 대소문자 구분안함 

전화번호 - /^\d{3}-\d{3,4}-\d{4}$/

시작을 숫자 3개로하며 /   중간에 하이픈 -  하나 존재 /  숫자가 3~4개 존재하며 /  하이픈 하나 존재 /  숫자 4개로 끝남 

핸드폰 번호 - /^01([0|1|6|7|8|9]?)-?([0-9]{3,4})-?([0-9]{4})$/

시작을 숫자 01로 시작하며 그 후에 0,1,6,7,8,9 중에 하나가 나올수도 있으며 /  하이픈 - 하나 존재할수도 있으며 /  숫자 3~4개 이어지고 / 

또 하이픈 - 하나 존재할수도 있으며 /  숫자 4개가 이어짐 

URL - ^(https?):\/\/([^:\/\s]+)(:([^\/]*))?((\/[^\s/\/]+)*)?\/?([^#\s\?]*)(\?([^#\s]*))?(#(\w*))?$

^(https?):\/\/

([^:\/\s]+)

(:([^\/]*))?

((\/[^\s/\/]+)*)?\/?([^#\s\?]*)(\?([^#\s]*))?(#(\w*))?$



레퍼런스 : 

http://stackoverflow.com/questions/7820930/regex-how-to-exclude-single-word <-- 이론 
http://ccambo.blogspot.kr/2014/10/regular-expression.html   <-- 이론 
http://regexr.com/  <-- 테스트 

1. TCP/IP 에서의  Keepalive 


- 옵션이므로 설정여부는 상황에 따라 다르다.

TCP keepalive는 setsockopt()을 사용하여 소켓 옵션(SO_KEEPALIVE)을 설정하면 사용할 수 있게 됩니다.

소켓 옵션이 설정되면 tcp_keepalive_interval로 지정된 시간 동안 연결이 유휴 상태가 되었을 때 keepalive 탐색 패킷을 보냅니다.

- 두 지점간에 상대방의 안부를 묻기위해 payload 가 없는 패킷을 주기적으로 보내는것이다. (지정된 시간동안 서로 패킷교환이 없을 경우에 ) 

- 그 패킷에 반응이 없으면 접속을 끊는다. 

- NAS 같은것은 중간에서 두 지점사이에 데이타 교환이 없으면 , 큐의 오래된쪽으로 이동시켜 놓는데 (결국 임의로 삭제하면 , 두 지점의 연결이 

   갑자기  끊김)  Keepalive 옵션을 통해서 꾸준히 유지중이라고 NAS 에게 알려주는 장점이 있다.

-  keepalive를 사용하는 주된 이유는 종단 시스템 중의 하나가 다운될 때 발생할 수 있는 한쪽만 열린 연결 상태를 정리하는 것입니다. 


2. HTTP 에서의  Keepalive 


- http 는 특성상 커넥션을 유지하지 않습니다. 

- 하지만 keepalive 를 설정하면 유지하게 됩니다.

- KeepAliveTimeout   5 하면 5 초동안 유지됩니다.

- 서버는 연결을 맺을수있는 소켓을 생성하는데 한계가 있습니다.

- 따라서 연결을 오래 유지하면 , 다른 사람들이 연결을 못하게됩니다.

- 하지만 사람들이 적게 접속한다면, 소수의 사람이 빠르게 인터넷을 사용할수있습니다. (리소스를 얻기위해 재 접속이 필요없으니)

- 마찬가지로 서버의 메모리 용량이 무지 크다면,  KeepAlive 설정을 해줘도 넉넉한 커넥션을 맺을수 있겠지요.

- 너무 오래 놔둘 필요는 없고 2~5초 정도면 충분할듯합니다.


3. 소켓  timeout 이란 

첫째, Connection 에서의 타임아웃

=> 연결시도를 설정한 타임아웃까지는 해봐라~ 설정시간이 지나면 그냥 포기해~ 그게 편해~~

둘째. read/write 에서의 타임아웃 

=> 한쪽이 먼일이 생기거나, 랜선이 빠졌는데도 불구하고 오매불망 기다리고있을순 없잖아.  |
     타임아웃 시간까지만 기다리고 , 그만 잊고 새 색시 찾으러 가야지~  



소켓 옵션이 설정되면 tcp_keepalive_interval로 지정된 시간 동안 연결이 유휴 상태가 되었을 때 keepalive 탐색 패킷을 보냅니다.
응답 메시지가 수신될 때까지 또는 tcp_ip_abort_interval로 지정된 시간이 다 경과할 때까지 탐색 패킷을 보냅니다. 응답은 연결 상대측을 지연시키는 요소의 영향을 받습니다. 연결 상대측이 연결을 닫거나 다시 부팅을 하면 응답 메시지는 RST(reset packet)가 됩니다. 수신 주소에 도달할 수 없다는 ICMP 메시지를 수신하게 될 가능성도 있습니다. 라우터가 고장나거나 케이블 연결이 끊긴 경우에 그런 상황이 발생합니다. 그 외에도 많은 가능한 상황이 있습니다. 탐색 패킷 자체는 tcp_rexmit_interval로 지정된 간격으로 보내집니다.

keepalive를 15분 미만으로 설정해서는 안된다고 제안하는 이유 중의 하나는 바로 이것입니다. 그렇게 설정하면 TCP가 장애를 일으킬 가능성이 다분히 있습니다. tcp_rexmit_interval의 값은 3초로 기본 설정됩니다. 20초 정도로 높게 설정할 수도 있습니다. 그런데, tcp_keepalive_interval을 tcp_rexmit_interval 보다 작은 값으로 줄이면, 재전송하기 전에 keepalive 탐색 패킷을 보낼 것입니다. 하지만, 네트워크가 느리거나 팻 상태가 되면 재전송이 매우 중요합니다. 어쩌면 통신 상대측 시스템이 느려서 아직 응답하지 않은 것일 수도 있습니다. 재전송을 보내는 이유가 바로 이것입니다. 이것은 누군가에게 조금 전에 내가 한 말을 들었느냐고 묻는 것과 같습니다. 상대방이 없다고 판단되면 대화를 미리 중단하거나 상대방이 있는지 알아 보려고 시간을 낭비하게 될 것입니다. 상대측이 여전히 대화에 참여하고 있다면 그에게 직접 조금 전에 내가 한 말을 들었느냐고 다시 묻게 될 것입니다. 이렇게 되면 네트워크가 팻 상태가 됩니다. 네트워크가 팻 상태가 되면 될수록 제대로 작동이 되려면 재전송을 더 많이 해야 합니다. 그렇게 하여 TCP가 장애를 일으키게 됩니다.






레퍼런스:

http://egloos.zum.com/munhwan/v/1006786

http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/Network_Programing/Documents/Sockettimeout

'Network' 카테고리의 다른 글

Half close socket 이란  (0) 2015.09.07
SSH 터널링 상세이론  (0) 2015.07.14
홀펀칭 기초  (0) 2015.07.14
와이파이로 기기간 연결 강화한다  (0) 2015.06.11
모바일기기 wifi의 ip주소를 수동으로 설정하기  (0) 2015.06.11


프레임에 독립적인 가속(ease-in)과 감속(ease-out) 보간


이 방법은 Game Programing Gems vol 1의 2.1 보간법(Johm Olsan)에서 다루는 방법으로, 

프레임 변화율에 무관하게 가속 감속 보간을 실행한다.

(GPG Gems vol 1 - 2.1 보간 법 : 프레임율 독립적인 가-감속 보간)


아래 사진은 GPG 1권의 Ease In Out Interpolation 그래프이다.









프레임 율에 독립적으로 동작 하면서 가속과 감속 처리를 하기 위해서는 시간 기반(time based) 보간처리를 해야 한다.

(시간 기반 Animation 참조 )

즉, 현재 시간(t_1)에 이전 시간(t_0)를 빼줌으로서 delta time(dT)를 구해야 한다.


또한 가속 - 감속 처리를 위해서 가속도(Acceleration)값을 가중치(weight)로 이용해서 구한다.


우리는 보간 처리를 하기 위해서, 좌표의 변화량(변위)값을 구하는 것이 목적이다.

그럼으로 아래와 같은 물리 방정식을 이용해서 변위 값을 유도해 낼 수 있다.


가속도(acceleration) = 이동속도 / 이동시간 = deltaVelocity / deltaTime = (v_f - v_0) / (t_1 - t_0) = dV / dT

속도(velocity).= 이동거리 / 이동시간 = range / deltaT = (x_f - x_0) / (t_1 - t_0) = dR/ dT

변위(Displacement, range) = 속도 * 이동시간 = (x_f - x_0) = (d_f - d_0) = v * (t_1 - t_0) = v * dT


운동 방정식 1

a = (v_f - v_i) / (t_f- t_i)

v_f = v_i + aT

최종 속도 = 초기속도 + 가속도*시간

시간 = t_f - t_i = T


운동 방정식 2

등가속도 운동일 경우,

avg_v = (v_i + v_f) / 2

평균속도 = (초기속도 + 최종속도) / 2


평균속도는 시간에 따른 변위의 비율 과 등가속도 운동일 경우 식을 통하여 대수적으로 변형할 수 있다.

avg_v = deltaX / t

deltaX / t = (v_i + v_f) / 2

deltaX = (v_i + v_f) * t / 2


운동 방정식 3

dX = (v_i + v_f) * t / 2

변위 = (초기속도 + 최종속도) * 시간 / 2


(운동방정식 1) (운동방적식 3)에 치환하면 다음과 같은 식으로 유도할 수 있다.

deltaX = (v_i + v_i + aT) * T / 2

deltaX = v_i*T + (aT^2) / 2

변위 = 초기속도 * 시간 + 가속도 * 시간^2 / 2



Function 

F = v = a*t = (x_1 - x_0) / (t * t / 4) * t


(운동 방정식 3) 을 이용하여 가속도와 변위를 구한다.


displacement : x = x_0 + (v_0 * t) + a * t * t / 2

acceleration : a = (x_1 - x_0) / (t * t / 2)          <- v_0는 초기속도임으로 0으로 볼수 있다.

velocity : v = acceleration * t 


가속도 식에서 2로 나누는 값을 4로 나눠야 한다. 이는 가-감속식에서

변위의 중간 위치에서 단계가 계속 증가하는 것이 아니라 감속하기 때문이다.

(첨부한 엑셀 interpolation.xlsx에서 확인하도록 하자.)



Pseudo Code

// 보간 처리할 간격 구하기.

// EaseInOut 가-감속 보간 수식.

// 등가속도 운동으로 구한다.


n = 100;

x_final = 600;

time = 10.0f ;

acceleration = (x_final - x0) / (time * time / 4);

velocity = acceleration * deltaT;


deltaT = time / n;

remainingTime = time - deltaT;


do {

if (remainingTime > time/2) {

// 가속 처리

velocity += (acceleration * deltaT);

} else {

// 감속 처리

velocity -= (acceleration * deltaT);

}

x1 += (velocity * deltaT);

interpolation_values[interpolation_index++] = (x1 - x0);  // x 의 변화량을 보간 값으로 저장한다.

x0 = x1;


remainingTime -= deltaT;

} while(remainingTime > 0.0f);


Evaluation

range : i = 0, n = 600

time = 10.0f



Result

EaseInOut 가-감속 보간 결과


EaseInOut 가-감속을 위한 변화량 결과 ; (x_1 - x_0)

(변화량은 등가속도 운동을 함으로 일정한 간격으로 상승했다가 하강한다.)





http://www.gizma.com/easing/  <-- 여기 보면 Ease in / out 를 직접 확인해볼수있다.


'그래픽스' 카테고리의 다른 글

메쉬 생성 방법 소개  (0) 2015.07.21
메쉬 제네레이션 - delaunay triangulation  (0) 2015.07.21

   서울대에서 무들 사용법에 대해서 동영상으로 공개해놨습니다. 

   http://etl.snu.ac.kr/snuhtml/manual.php  요기 가시면 동영상 메뉴얼을 보실수있습니다.



+ Recent posts