프로젝트-2 (클론) git에서 실습 소스 가져오기

손원진·2023년 2월 7일
0

[SPRING]

목록 보기
4/15

git허브 소스복사

  1. git repository를 띄워서 clone a git repository에 복사한 주소를 넣어주면 된다.

  1. 계산기와 관련된 소스를 전부 git에서 import한다.

데스크톱 애플리케이션


특징 .

  • pc에 설치한 후 실행 (알집프로그램, 알쇼)

  • 사용자 화면출력, 업무관련 작업 실행, 데이터 처리를 모두 pc에서 실행

  • 배포가 번거롭다 , 보안에 취약하다.

  • 인사정보나 , 회계정보가 exe만 실행하면 실행파일 내부에 데이터가 있어서 database 접근이 가능하기 때문에 보안에 취약함

클라이언트 * 서버 애플리케이션

서버는 비즈니스 로직과 , 데이터로직을 처리하고

클라이언트는 프리젠테이션 로직만을 실행한다.

기존에는 클라이언트가 직접 dbms서버에 접근이 가능해서, id나 비밀번호 조회를 살 수 있었는데, 클라이언트 서버로 바뀌면 서버를 통해 dbms에 접근을해서 외부에 데이터 노출을 막을 수 있다.

실습 (클라이언트 서버 애플리케이션

CalculatorFrame -> calculatorServer 로 네트워크 통신을 했었는데

CalculatorFrame -> CalculatorAgent -> CalculatorServer로 3단계에 거쳐서 진행

CalculatorServer

 public static void main(String[] args) throws Exception {
 
		CalculatorServer app = new CalculatorServer(8888);
        
		app.service();
	}
		
        //통신 포트번호 8888설정 후 계산기 서비스 실행 
        
        public void service() throws Exception {
        
		ServerSocket serverSocket = new ServerSocket(port);
        
		System.out.println("CalculatorServer startup:");
		
		Socket socket = null;
		
		while(true) {
        
			try {
            
				System.out.println("waiting client...");
				
				socket = serverSocket.accept();            
				System.out.println("connected to client.");
				
				processRequest(socket);
				System.out.println("closed client.");
				
			} catch (Throwable e) {
            
				System.out.println("connection error!");
                
			}
		}
	}//new ServerSocket(port)에서 설정한 포트번호로 서버소켓 생성 
    
    //serverSocket.accept 클라이언트의 연결을 기다렸다가 연결이 이뤄지면 요청을 처리함. 
    
    //processRequest 클라이언트 소켓으로 부터 입출력을 위한 스트림 객체를 준비
    
    private void processRequest(Socket socket) throws Exception {
    
		Scanner in = new Scanner(socket.getInputStream());
		PrintStream out = new PrintStream(socket.getOutputStream());
			
		String operator = null;
		double a, b, r;
		
		while(true) {
        
			try {
            
				operator = in.nextLine(); //입력한 연산자 받아오기 
				
				if (operator.equals("goodbye")) {
                
					out.println("goodbye");
					break;
					
				} else {
                
					a = Double.parseDouble(in.nextLine());//입력한 값 받아오기 1
					b = Double.parseDouble(in.nextLine());//입력한 값 받아오기 2
					r = 0;
				
					switch (operator) {
                    
					case "+": r = a + b; break;
					case "-": r = a - b; break;
					case "*": r = a * b; break;
					case "/": 
						if (b == 0) throw new Exception("0 으로 나눌 수 없습니다!");
						r = a / b; 
						break;
					default:
						throw new Exception("해당 연산을 지원하지 않습니다!");
					}
                    
					out.println("success");
					out.println(r);
				}
				
			} catch (Exception err) {
				out.println("failure");
				out.println(err.getMessage());
			}
		}
		
		try {out.close();} catch (Exception e) {}
		try {in.close();} catch (Exception e) {}
		try {socket.close();} catch (Exception e) {}
	}
    

CalculatorFrame

역할 -- 고객데이터를 받아서 전달 - 화면단에 뿌림

	//버튼클릭  이벤트 처리 actionPerformed
	@Override
	public void actionPerformed(ActionEvent event) {
    
		if (event.getSource() == equal) {
        
			compute();   
            
		} else {
                
			clearForm();
		}
	}//이벤트 객체를 조사해서 이벤트가 발생한 버튼이 무엇인지 알아냄 
    
    
    private void compute() {
    
		double a = Double.parseDouble(operand1.getText()); 
		double b = Double.parseDouble(operand2.getText());
		double r = 0;
		
		try {
        
			r = calcAgent.compute(operator.getText(), a, b);
			result.setText(Double.toString(r));
			
		} catch (Exception err) {
        
			JOptionPane.showMessageDialog(
				null, err.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
		}
	}
    
    

CalculatorAgent

소켓을 통해 입출력 할 수 있도록 스트림 객체를 준비 
private void compute() {

		double a = Double.parseDouble(operand1.getText()); 
		double b = Double.parseDouble(operand2.getText());
		double r = 0;
		
		try {
        
			r = calcAgent.compute(operator.getText(), a, b);
			result.setText(Double.toString(r));
			
		} catch (Exception err) {
        
			JOptionPane.showMessageDialog(
				null, err.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
		}
	}
  // compute는 사용자가 입력한 연산자와 두개에 입력값을 서버에 전송합니다. success면 정상적으로 처리되었다는 것이므로 double형으로  바꿔서 리턴합니다.  

위 클라이언트 - AGENT - SERVER구조에 문제점은 여러명에 클라이언트가 접속할 수 없다는 것이고

장점은 계속 업데이트하고 다운로드를 안해도 서버에있는 최신데이터는 통신을 통해 반영을 할 수 있다는 것이다.

다중 클라이언트 요청처리


위 방식은 하나에 서버에서 여러개 클라이언트의 요청을 처리하지 못해, 처리중의 경우 다른 사용자는 대기하는 형태이다. 이걸 한번 개선해보자.

이런 문제점을 해결하기 위해선 THREAD를 사용해야한다.

서버에 스레드가 요청을 대신 처리하고 응답을 할 수있도록 만들어야함

THREAD로 여러 동시요청을 서버에서 처리할 수 있다

EXAMPLE

server

public class CalculatorServer {

	private int port;
	
	public CalculatorServer(int port) {
   
		this.port = port;
	}
	
	public void service() throws Exception {
   
		ServerSocket serverSocket = new ServerSocket(port);
		System.out.println("CalculatorServer startup:");
		
		Socket socket = null;
		
		while(true) {       
       
			try {
           
				socket = serverSocket.accept(); //여기까지 동일하지만 
				System.out.println("connected to client.");
				
				new CalculatorWorker(socket).start(); //스레드인 calculator worker를 사용함 
				
			} catch (Throwable e) {
           
				System.out.println("connection error!");
			}
		}
		
	}
	
	public static void main(String[] args) throws Exception {
   
		CalculatorServer app = new CalculatorServer(8888);
		app.service();
	}
}

calculator worker

public class CalculatorWorker extends Thread {

	static int count;
	
	Socket socket;
	Scanner in;
	PrintStream out;
	int workerId;
	
	public CalculatorWorker(Socket socket) throws Exception {
   
		workerId = ++count;
		this.socket = socket;
		in = new Scanner(socket.getInputStream());
		out = new PrintStream(socket.getOutputStream());
       
	}
	
	@Override
	public void run() {
   
		System.out.println("[thread-" + workerId + "] processing the client request.");
		
		String operator = null;
		double a, b, r;
		
		while(true) {
       
			try {
           
				operator = in.nextLine();
				
				if (operator.equals("goodbye")) {
               
					out.println("goodbye");
					break;
					
				} else {
               
					a = Double.parseDouble(in.nextLine());
					b = Double.parseDouble(in.nextLine());
					r = 0;
				
					switch (operator) {
                   
					case "+": r = a + b; break;
					case "-": r = a - b; break;
					case "*": r = a * b; break;
					case "/":                     
						if (b == 0) throw new Exception("0 으로 나눌 수 없습니다!");
						r = a / b; 
						break;
                       
					default:
						throw new Exception("해당 연산을 지원하지 않습니다!");
					}
                   
					out.println("success");
					out.println(r);
				}
				
			} catch (Exception err) {
           
				out.println("failure");
				out.println(err.getMessage());
			}
		}
		
		try { out.close(); } catch (Exception e) {}
		try { in.close(); } catch (Exception e) {}
		try { socket.close(); } catch (Exception e) {}
		
		System.out.println("[thread-" + workerId + "] closed client.");
	}
}

반복되는 요청만 socket으로 받아서 처리함 기존에는, process가 사용자가 직접 종료하기 전까지는 끝나지 않았는데, 쓰레드가 서버가 생성함과 동시에 복제로 같은동작을 실행하는 worker를 계속 만들어내서 처리하도록 진행함.

장점 스레드 - 작업에 병행 처리가 가능 -> 동시작업
단점 - 스레드와 소켓을 사용해 코드가 복잡해짐

profile
매일 한 걸음

0개의 댓글