client / server



server 기반 모델   vs   p2p 모델




server 기반 모델


- 전용 서버를 두는 모델

- 안정적인 서비스 제공

- 공유 데이터의 관리와 보안이 용이





P2P 모델


- 전용 서버없이 각 클라이언트가 서버역할까지 동시에 수행

- 자원 활용의 극대화

- 보안이 취약하고 자원관리의 어려움







TCP / UDP


소켓 : 프로세스간의 통신에 사용되는 end point ( 소켓간의 커넥션이 되면 point to point)


TCP/UDP 는  OSI 7 계층의 전송 계층에 해당( tcp/ip protocol 에 포함 , 4layer)



 항목

tcp 

udp 

 연결방식

 연결기반

- 연결 후 통신

- 1:1 통신

비 연결기반

- 1:1 , 1:n, n:n 통신

- 연결없이 통신 ( 소포를 예를 듬) 

 특징

 - 신뢰성 있는 데이터 전송

 - 데이터의 전송 순서 보장

 - 데이터의 수신 여부 확인

 - 패킷 관리 할 필요 없다.

 - udp 보다 느림

- 비신뢰성 전송

- 데이터의 전송 순서가 바뀔 수 있다.

- 수신 여부 확인하지 않음

- 패킷 관리해야함.

 

 관련클래스

  serversocket, socket

 datagramsocket, datagrampacket, multicastsocket












 


개념


I/O (입출력) - 입력 , 출력 / 두 대상 간의 데이터를 주고 받는 것



Stream -  데이터를 운반 하는데 사용되는 연결통로

         -  연속적인 흐름

         -  입출력을 동시에 수행하려면, 2개의 스트림이 필요하다.





간단한 코드지만 아래의 코드를 살펴보자.


import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;


public class FileTest {


public static void main(String args[]) {


FileInputStream fis = null;

FileOutputStream fos = null;


try {

fis = new FileInputStream("log.txt");

fos = new FileOutputStream("back_log.txt");


int data = 0;

byte[] b = new byte[1];


while ((data = fis.read(b)) != -1) {

System.out.println(data);

fos.write(b);

fos.flush();

}


} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

System.out.println("File Not found");

e.printStackTrace();

} catch (IOException e1) {

// TODO Auto-generated catch block

System.out.println("File Not found");

e1.printStackTrace();

}finally {

if(fos!=null) {

try {

fos.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

if(fis!=null) {

try {

fis.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}


}

}




네트워크, 특히 서버에서 예외 처리와 close() 메소드는 매우 중요하다.


만일 close() 메소드를 try 문에 포함시켜서 한다고 가정하자. 


서버에서 예외가 발생하면 스트림은 닫히지 않고 메모리 누수가 발생할 요소가 있다.


꼼꼼한 예외처리와 try catch, finally 는 자바 네트워크에서 중요한 요소이다.





스트림의 종류


바이트 기반 스트림 


  - inputstream , outputstream


  - 1byte 단위




 문자 기반 스트림

 

  - reader, writer

  -  문자 단위














 개념



Process - 실행중일 프로그램.  쓰레드와 자원으로 구성


Thread -   하나의 작업을 실행하는 작업 단위.




interruptedexception - 서버가 도중에 끊키거나 서버에 문제가 생겼을 때 발생하는 예외



Thread 의 스케쥴링은 자바  jvm 내에서 작업의 순서가 저장된다.


- > 작업의 우선순위를 보장받지 못한다는 말과 같다.





 예제를 보면서 이해해보자..


import Thread.Thread1;

import Thread.Thread2;


public class Test {


public static void main(String[] args) {


Thread1 thread1 = new Thread1();

thread1.start();


Thread thread2 = new Thread(new Thread2());

thread2.start();

Thread thread3 = new Thread();

thread3.start();

int sum = 0;


for (int i = 0; i < 10; i++) {

sum = +i;

try {

Thread.sleep(500);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println("Main Thread = " + sum);


}


}

}






코드를 아래와 같은 그림으로 나타 낼 수 있다.








=> 메인 쓰레드에서 쓰레드 3개가 돌고 있다...         쉽다.





또한  setPriority()  메소드를 통해 우선순위를 설정할 수 있다.







멀티쓰레드의 장 단점



 장점

  - 자원을 보다 효율적으로 사용한다.

  - 사용자에 대한 응답성이 향상된다.

  - 작업이 분리되어 코드가 간결해진다.

 단점

  - 동기화에 주의

  - 교착상태가 발생하지 않게 조심 해야한다.

  - 쓰레드가 효율적으로 실행되게끔 고려해야한다.











Thread Groop 


- 관련된 쓰레드를 그룹으로 다루는 것이다.


- 쓰레드 그룹은 반드시 하나 이상 포함된다. 포함하지 않으면 자연스럽게 메인 쓰레드에 포함된다.


- 쓰레드 그룹으로 부터 우선순위를 상속받기 때문에, 같은 쓰레드 그룹에 있는 쓰레드들은 우선순위를 공유한다.. 


(쉽다)










 Daemon Thread



-    어렵게 생각할 것 없다. 데몬은 쓰레드가 계속 실행되고 있는 상태이다.

-    가장 간단하게 while 문으로 무한 루프 돌리면 된다.. 























Synchronized Block, Synchronized method



동기화(Synchronized)


- 공유 데이터(나머지 synchronized 된부분) 에 lock을 걸어 작업중이던 쓰레드가 마칠때까지 다른 쓰레드에게 제어권이 넘어가지 않게 보호한다.

- 교착상태에 주의해야 한다.



쓰레드는 같은 프로세스 내 데이터를 공유하기 때문에 일관성에 영향을 끼칠 수 있다. 

만약 공유하는 자원을 처리하던 중 다른 쓰레드가 접근하기라도 한다면 ? 


즉 동기화를 통해, 위와 같은 상황을 방지하고 어느 한 시점에 하나의 쓰레드만 접근하여 자원을 선점하고 프로그래머는 이를 효율적으로 관리할 필요가 있다. 


예를 들어, 작업 중인 문서에 누군가 들어와 편집을 해서 내가 했던 자료가 날라갔다고 가정하면 큰 낭패 일 것이다. 작업중인 문서에 lock을 걸어 다른 사람의 편집권한을 막는 것과 같은 이치라고 생각하면 된다.


ex) Singleton Pattern의 인스턴스를 여러 객체가 접근 할 때, Static으로 정의된 객체를 여러 객체가 접근 할 때, 하나의 객체에 여러 개의 쓰레드가 접근하려고 할 때.. 




 





사용법


(1) 특정 객체 인스턴스에 lock을 걸려고 할 때 - synchronized block

private Worker wokrer = new Worker();


public void work(){

synchronized(worker){


//input


}


}



(2) 메소드에 lock을 걸 때 - synchronized method

public synchronized work(){


//input code

Worker worker = new Worker();

}



특정 인스턴스의 사용을 동기화 할 것이냐?  혹은 메소드 자체를 동기화 할 것이냐?의 구분의 차이로 인식하면 쉬울 것 같다. 

사소하지만 주의깊게 생각해야 할 점이 있다면, (1) 번의 경우 synchronized 된 부분이 임계 영역이라면, (2) 번의 경우 메소드 전체가 임계영역이 된다는 점이다.





Sample Code


class Worker { private Object obj; private int count=0; public Worker() { } public synchronized void writeData(Object obj) { this.obj = obj; count++; } public Object getObj() { return obj; } public void setObj(Object obj) { this.obj = obj; } @Override public synchronized String toString() { return "Worker [obj=" + obj + ", count=" + count + "]"; } } public class Main { public static void main(String[] args) {

//Worker라는 하나의 인스턴스를 공유할 것이다. Worker worker = new Worker(); Thread thread1 = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub while (true) { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } worker.writeData("Writer1"); System.out.println("Data Print :"+worker.toString()); } } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub while (true) { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } worker.writeData("Writer2"); System.out.println("Data Print :"+worker.toString()); } } }); thread1.start(); thread2.start(); } }



- WriteData 메소드와 toString 메소드를 동기화함에 따라 순차적인 Count 증가 및 Data를 Write할 수 있었다.





=>결과 출력







위의 방법처럼 synchronized 된 메소드를 구성했다면 , 객체를 synchronized 하여 구성하는 것도 쉽게 할 수 있을 것이다.

















로그란?


log. 컴퓨터 혹은 시스템 상태를 관찰할 수 있도록 에플리케이션이 제공하는 정보. 


- 로그를 통해 프로그램의 특정 상황이나 발생되는 이벤트의 정보를 얻을 수 있다.

- 로그를 통해 개발자는 시스템의 현재 상황에 대한 정보를 얻을 수 있고 향후 시스템을 개선하기 위해 노력하여야 한다.


 즉 프로그램과 개발자가 소통할 수 있는 창구라고 생각한다.







로그 레벨


 - log4j 라이브러리는 자주 활용되며 OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE 로 나눌 수 있다.

OFF       :  로그 사용 해제
FATAL    :  시스템 혹은 애플리케이션의 종료를 유발 할 수 있는 아주 심각한 오류가 발생한 상태 
ERROR   :  특정 이벤트나 상황에서 오류가 발생한 상태
WARN    :  앞으로 오류를 발생할 만한 요소에 대한 경고를 나타냄
INFO      :  시스템 시작 또는 종료 등 상태 변경에 대한 정보를 제공하는 단계

DEBUG   :   디버그. 시스템 흐름에 대한 정보를 제공할 때 사용

TRACE    :  DEBUG 단계보다 더 자세한 정보를 제공할 때 사용

'programming > Exception' 카테고리의 다른 글

# 예외처리 (1) - 예외처리의 중요성  (0) 2018.02.24


예외처리에 대한 생각



프로그램에서 예외는 발생할 수 밖에 없고, 특히 예외로 인해 서버 프로그램이 작동을 멈춘다면 문제가 발생할 요소가 있다.  적어도 발생한 예외가 어떤 예외이며, 이것이 무시해도 될 수준인지 아니면 반드시 처리를 해야하는 것인지 그것도 아니라면 시스템 자체를 종료시켜야하는지에 대해 생각해봐야한다.

시스템에서 훌륭한 기능보다 중요한 것이 손쉬운 보완이라고 생각한다. 예외는 프로그램의 보완에 있어 첫걸음이 될 것이다.

첫 단추를 잘 꿰 메야 한다는 말이 있듯이, 프로그램을 설계하고 구축하는 첫 단계에서 수많은 예외상황에 생각하고자 스스로 노력하자.


 
1. 에러와 예외는 어떻게 다른가? 

error : 시스템 단계에서 발생. 시스템의 비정상적인 상황이므로 예외처리가 아닌 시스템 환경을 개선해야 한다.
Exception : 프로그램 로직에서 발생. 프로그래머가 작성한 로직에서 예외를 예상하여 구분하고 처리해야 한다.


2. 예외의 구분 

                                    예측가능한 예외 vs 예측 불가능한 예외

* 예측 가능한 예외 
 - 프로그램에서 당연히 발생 할 수 밖에 없는 상황.    ex) 로그인 실패, 데이터 조회 실패 .. 등

* 예측 불가능한 예외
 - 에러와 같은 수준의 레벨.     ex) 버그, 시스템의 메모리 문제 .. 등
 - 시스템 환경에서 개선해야 한다. 

 

  
                                     Runtime Exception vs 그 밖의 예외

* Runtime Exception (unchecked Exception)

 - 실행 단계에서 확인합니다.
 - 그렇기 때문에 처리를 강제하지 않습니다.
 - ex) nullpointerException , IndexOutOfBoundsException, .. 등
 - 하지만 이 또한 버그이기 때문에 반드시 인지하고 처리해야 할 의무가 있습니다.



* 그 밖의 예외 (checked Exception)
  - 컴파일 단계에서 확인합니다.
  - 예외에 대한 처리를 강제합니다.
  - ex) IOException .. 
  



3. 예외를 잡은 이 후의 행동



(1) 예외를 잡았다면 반드시 처리해야 한다.

  - 하지만 그 예외가 에러라면? 저라면 시스템 환경을 개선하고 처리하지 않겠습니다.

  - 시스템을 종료하거나 혹은 예외에 대한 상황을 처리 할 수 있다.



(2) 로그를 반드시 남겨야 한다.

 - 예외가 어떤 예외인지 구체적으로 명료하게 로그로 남겨야 한다.  

 - 예외가 발생한 원인, 시스템의 정보, 이외 반드시 판단 가능한 메세지.

 - 로그는 프로그래머가 처리 상황을 판단 할 수 있는 구체적인 증거입니다. 특히 서버 개발자에겐..

  


(3) 새로운 예외를 던질 수 있다.

 - 세세한 예외를 더 추상화하여 던진 경우이다.  

 - 예외 원인에 대한 정보가 부족할 경우 새로운 예외를 던짐으로써, 구체적인 정보를 얻을 수 있다.

 


(4) 예외 무시

 - 큰 이상이 없다고 판단되면 예외를 무시할 수 있다.

 - 좋은 방법은 아니다.





4. 예외처리 패턴



(1) 예외복구

try{ .... } catch(SQLException e) {

logger.error("Insert Query Failed . Method Name '' , User id is blar...");

e.printstackTrace();

}finnally{

..

예외에 대한 처리작업을 수행해야 할 것이다.

doAnything();

}

 => 예외복구에 대해 반드시 인지해야 되는 점은 프로그램이 정상적으로 작동하게끔 수행해야 한다는 것이다. 비록 예외가 발생되었어도 프로그램 로직에 의해 시스템이 종료 혹은 계속해서 수행할 수 있어야 할 것이다.




(2) 예외회피

public void process() throws Exception {

......

}



  => 예외를 메소드에 정의함으로써, 예외에 대한 처리를 수행하지 않고 있다. 또한 추상클래스인 Exception을 예외로 던졌기 때문에, 구체적인 예외에 대한 처리가 부족하다. 즉, 좀 더 세부적인 예외를 잡아먹고 있다. 예외회피를 불가피하게 해야할 경우를 제외한다면, 신중하게 선택해야 할 것이다.

 



(3) 예외전환

try{ .... } catch(Exception e) {

... 추상 Exception에 대한 정보 또한 로그로 남기면 좋을 것이다..

throws New SQLException("Exception is SQLException. Insert Query Failed . Method Name '' , User id is blar...");

}

 => 예외를 중첩하여 사용하여 어떤 예외에 대한 처리인지 분명하게 처리하였다. 만일 복구가 불가능 한 예외에 대한 처리라면 RuntimeException으로 전환하여 다른 예외에 대해 일일히 처리하지 않게끔 할 수 있다. 










예외에 대해 정리하면서 느낀 생각은, 개발자라면 항상 예외에 대해 염두하고 있어야 한다는 점입니다.  (특히 나같은 초급개발자라면..)


예외를 잡았다면 반드시 처리해야 할 것이며, 예외 상황에 대한 충분한 로그를 남겨야 할 것입니다. 충분히 예외상황에 대해 인지하고 처리를 했다면 유지보수 측면에서 혹은 협업단계에서 효율적으로 시스템을 개선할 수 있을 것입니다.


 

=> 예외의 목적은 시스템 개선이다!!










참고사이트 : https://www.slideshare.net/dhrim/ss-2804901

'programming > Exception' 카테고리의 다른 글

#예외처리 (2) - log level  (0) 2018.02.24

+ Recent posts