91-미니프로젝트 / 2 페이지

mkdir 폴더만들기
gradle init
이클립스 설정 파일 만들기
Gradle의 빌드 스크립트 파일

빌드 : 컴파일, 배포 파일 생성, 테스팅, 문서 생성 등 App. 생성의 모든 단계
빌드 도구 : 컴파일, 배포 파일 생성, 테스팅, 문서 생성 등 App. 생성의 모든 단계에 관여하는 도구
빌드 명령서 : build script file

① Ant
설정 파일 : build.xml

② Maven
설정 파일 : pom.xml

Ant, Maven : XML 태그를 사용하여 명령을 기술
빌드 과정을 세밀하게 제어할 수 없다

③ Gradle
설정 파일 : build.gradle ← groovy로 작성
groovy 라는 프로그래밍 언어를 사용하여 명령을 기술
빌드 과정을 세밀하게 제어 가능
태그를 사용하니까

3단계
java -cp bin/main com.eomcs.app1.App add 100 200
add 100 200 ← 프로그램 아규먼트

4단계

5단계
프로그램 아규먼트 대신 키보드 입력 받기

6단계

7단계
클래스로 분류

8단계

Standalone Application
설치형 Application
새로운 기능이 추가되거나 기존 기능이 변경되면 각각의 컴퓨터에 다시 설치해야 된다.

9단계
Client / Server Application

서버쪽 변경이 있어도 클라이언트는 안 바꿔도 됨

네트워크 통신

애플리케이션 서버 (AS)
서버에서 실행하는 프로그램

Web + AS = WAS
스프링 부트가 WAS

Web Application 구조
웹 브라우저를 클라이언트 프로그램의 대행자로 사용
웹 브라우저와 통신하는 쪽은 웹 서버를 두자
서로 데이터를 주고 받을 때 규칙
통신 규칙 = 프로토콜
HTTP 프로토콜

모든 pc에 클라이언트 프로그램을 설치할 필요가 없음

웹 브라우저랑 통신하려면 웹 브라우저 규칙에 따라야 됨
HTTP 규칙에 따라서

http://localhost:8888/*/200/100
http ← 제일 먼저 프로토콜 정보 들어감
IP Address : localhost (호스트명)
PORT 번호 : 8888

URL 문법에서 +는 공백을 의미
URL에 있는 규칙에 어긋나지 않게 기존 충돌나지 않게 가공
URL Encoding

11단계: 웹 기술 도입 - 스프링 부트 사용하기

• 통신 프로그래밍 (소켓 프로그래밍)
TCP/IP ← 소켓 프로그래밍
UDP는 데이터니까...
UDP(User Datagram Protocol)
• 멀티 스레딩
• URL 디코딩
• 계산 작업 (업무)

ServerApp을 Spring Boot로 교체

계산 작업은 CalculatorController 클래스로 분리

웹 브라우저는 이제 Spring Boot에 요청하고 통신한다
Spring Boot가 CalculatorController를 call 한다

개발자는 이제 통신 프로그래밍, 멀티 스레딩, URL 디코딩 안 함
업무와 관련된 프로그래밍에 집중할 수 있다.

이게 바로 스프링 부트를 도입하는 이유

먼저 라이브러리를 가져오는 게 먼저

build.eclipse 파일 수정
스프링 부트 관련 라이브러리 추가하기

git/bitcamp-study/project-app1/app-server>
$ gradle cleanEclipse

git/bitcamp-study/project-app1/app-server>
$ gradle eclipse

스프링 부트를 도입한다고 하면
스프링 부트 관련 라이브러리를 포함시킨다
스프링 부트 코드 복붙

SpringApplication.run(ServerApp.class, args);

package com.eomcs.app1;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class ServerApp {

  public static void main(String[] args) throws Exception {
    SpringApplication.run(ServerApp.class, args);
  }

  @RequestMapping("/help")
  public String help() {
    StringBuilder strBuilder = new StringBuilder();
    strBuilder.append("[웹 계산기 도움말]\n");
    strBuilder.append("사용법: \n");
    strBuilder.append("URL 형식 => http://localhost:8888/calc?op=연산자&a=값1&b=값2\n");
    strBuilder.append("예) http://localhost:8888/calc?op=-&a=100&b=200\n");
    return strBuilder.toString();
  }

}

나중에 소스 코드 보기 편하라고 \n 붙이는 거

클래스 이름은 관례적으로 OOOController

package com.eomcs.app1;

import org.springframework.web.bind.annotation.RestController;

@RestController
public class CalculateController {

}

.1f ← 소수점 이하는 첫 번째 자리까지만 표시하겠다

스프링 부트를 도입하면 복잡한 코딩을 안 해도 된다
최대한 간단하게
목적에 관련된 코딩에 집중할 수 있게

http://localhost:8080/calc?op=-&a=100&b=200

integer.parseInt 이런 것도 안 써도 됨

12단계: 웹 기술 도입 - HTML/CSS/JavaScript로 UI 생성

Web Browser ---> Spring Boot ---> Calculator

                  form.html

form.html ← UI

요청 파라미터 (query parameter)

http://localhost:8080/calc/form.html

form.html이 안 열리면 .classpath에 등록되어 있는지 확인하기
없으면 .classpath를 갱신해야 됨
gradle eclipse 다시 하면 됨

✅ 스프링 부트를 사용하는 이유
클라이언트 / 서버 프로그램을 좀 더 쉽게 작성하기 위해서

com.eomcs.net.ex01

com.eomcs.net.ex01.Receiver.java

com.eomcs.net.ex01.Sender.java

Client / Server 용어

Client -----요청-----> Server
Client <-----응답----- Server

요청을 받는 쪽

host(호스트) : Application을 실행하는 컴퓨터

Client host
Server host

Windows 11 ← host OS

Linux      Windows   ← guest OS
VMWare     VMWare

local computer
remote computer

그냥 컴퓨터를 가리키고 싶을 때는 host
당신들이 사용하는 컴퓨터를 말할 때는 PC

호스트에서 실행 중인 서버 프로그램을 구분하는 번호이다.

1 ~ 1023 사이의 포트 번호는 특정 서버가 사용하기 위해 미리 예약된 번호다.

가능한 이 범위의 포트 번호는 사용하지 않는 것이 좋다.

같은 컴퓨터에서 다른 프로그램이 이미 사용중인 포트 번호는 지정할 수 없다.

포트 번호는 중복으로 사용될 수 없다.

유명 프로그램의 포트 번호도 가능한 한 사용하지 말라.

연결을 기다리고 있는 클라이언트가 있다면 제일 먼저 접속한 클라이언트의 연결을 승인한다.

연결과 승인

new ServerSocket(8888)

대기열 준비

대기열 : 클라이언트 연결 정보를 요청한 순서대로 보관
클라이언트 IP 주소, PORT 번호
클라이언트들의 IP 주소와 PORT 번호가 쌓인다

대기열에 정보가 기록된다

클라이언트도 포트 번호가 있음

new Socket() ① 연결 요청
new Socket() ② 연결 요청

Socket socket = serverSocket.accept();

accept() : Socket ← Socket을 리턴한다.

accept() ← 연결 정보를 하나 가져와서 Socket 생성 new Socket()
대기열에서 꺼내서 소켓 생성
만약 대기열에 아무런 클라이언트 연결 요청이 없다면 요청이 대기열에 놓일 때까지 기다린다.

클라이언트와 서버 소켓 사이에 통신 수행

소켓을 닫고
더 이상 다른 클라이언트 요청을 처리하고 싶지 않으면

소켓 프로그래밍 코드

클라이언트
new Socket(서버주소, 8888)

서버
new ServerSocket(8888)

  1. 클라이언트 접속 대기중
    accept()
  2. 접속
  3. 소켓 생성
    new Socket()
    대화를 나눌 소켓을 생성
    ------------------------------여기까지가 네트워킹
  4. 클라이언트 입출력 스트림 준비
    InputStream
    OutputStream - 데이터 전송
  5. 서버 입출력 스트림 준비
    OutputStream
    InputStream
  6. 데이터 쏘고 읽기
    OutputStream - 데이터 전송 (클라이언트)
    InputStream (서버)
    OutputStream - 데이터 전송 (서버)
    InputStream (클라이언트)

합이 맞아야 됨
한쪽에서 보내면 한쪽에서 읽어야 됨
서로 보내겠다고 하면 안 됨
서버에서 한 줄을 읽으면 서버창에 출력
상대편으로 데이터를 출력하고 싶으면 out 객체를 통해서 출력
한 줄 읽고 한 줄 쓰고
소켓을 닫으면 클라이언트와 연결이 끊긴다
서버소켓을 닫으면 클라이언트의 연결 요청을 받지 않는다

com.eomcs.net.ex01.Sender.java

원격 호스트의 IP 주소/도메인 이름(로컬일 경우, 127.0.0.1(localhost) : 현재 컴퓨터를 가리킨다.

new Socket(원격 호스트의 IP 주소/도메인 이름, 포트 번호)
로컬 호스트(Application을 실행하는 현재 컴퓨터)일 경우: 127.0.0.1 또는 localhost

localhost : Application을 실행하는 현재 컴퓨터

서버의 대기열에 등록된다면 리턴한다.

서버에서 한 줄 읽기 했으면 한 줄을 보낸다
서버에서 한 줄을 보내기로 했으면 한 줄을 읽는다

블로킹 메서드
리턴하지 않고 기다리는 거

보내는 쪽에서 int 값을 보내면 받는 쪽에서도 int 값을 받아야 됨

java -Dfile.encoding=UTF-8 -cp app/bin/main com.eomcs.net.ex01.Receiver

java -Dfile.encoding=UTF-8 -cp app/bin/main com.eomcs.net.ex01.Sender

대기열에 들어올 때까지 기다린다

한 줄을 보낼 때까지 기다린다

상대편> 엄진영입니다. 안녕하세요!

192.168.0.3

어느 정도 연결을 기다린다

local에서는 항상 테스트할 때 서버를 먼저 띄우고 클라이언트를 실행해야지 테스트 해 볼 수 있다.

기본으로 설정된 타임아웃 시간까지 연결되지 않으면 예외가 발생한다.

java -Dfile.encoding=UTF-8 -cp app/bin/main com.eomcs.net.ex01.Receiver2

java -Dfile.encoding=UTF-8 -cp app/bin/main com.eomcs.net.ex01.Sender2

java-lang bin 폴더 통째로 지우기
main에 아무것도 없지
Project - clean
java-lang만 체크하고 clean
main에서 refresh 해도 안 됨
gradle cleanEclipse
gradle eclipse

turn-in 방식

192.168.0.3

DataOutputStream out = new DataOutputStream(socket.getOutputStream());

바이트 보낼 거라 DataOutputStream 데코레이터 붙임
long 값을 출력하는 메서드
byte 배열을 출력하는 메서드가 있음

파일 크기 보내기
out.writeLong(file.length());
파일 길이를 long 값으로 리턴함
20억 = 2GB

파일 이름 보내기
out.writeUTF(file.getName());

파일에서 데이터를 읽을 때 사용하는 파일 입력 스트림

깨작깨작 별로 안 좋음

바이트 배열을 주고 받는 거

long 8개의 바이트를 보내는 거고

한글 3바이트
바이트 배열로 만들어서 보내는 거
long 값을 보내나 파일을 보내나 결국 바이트 배열을 보내는 거

보내기 전. 시작 시간.
보낸 후.

서버에서 응답을 기다린다
서버에서 한 줄의 문자열을 보낼 거

합이 맞아야 됨
클라이언트가 세 번 보내면 서버는 세 번 읽어야 됨
클라이언트에서 long을 보내면 서버는 long으로 읽어야 됨

DataInputStream in = new DataInputStream(socket.getInputStream());

파일 크기 읽기
in.readLong();

파일 이름 읽기

파일 사이즈 만큼 반복문을 돌려서
반복문을 다 돌았으면 클라이언트에 한 줄의 메시지를 보낸다

cd app
app까지 들어가기

java -Dfile.encoding=UTF-8 -cp bin/main com.eomcs.net.ex01.Receiver4

cd app

git/bitcamp-study/java-lang/app>
java -Dfile.encoding=UTF-8 -cp bin/main com.eomcs.net.ex01.Sender4

com.eomcs.net.ex01.Receiver5.java
BufferedOutputStream
BufferedInputStream

com.eomcs.net.ex02 예습하기

데이터베이스가 결국 네트워크 통신으로 이루어진다

new Socket(원격 호스트의 IP 주소/도메인 이름, 원격 호스트 프로그램의 포트 번호)

new ServerSocket(포트번호, 대기열크기)
대기열의 개수를 지정하지 않으면, 기본이 50개이다.

대기열이 꽉 찼을 때 클라이언트의 접속 요청은 어떻게 되는가?

과정

네트워크 연결을 기다리는 역할을 수행할 객체를 준비
new ServerSocket(포트번호)

new Socket(원격 호스트의 IP 주소/도메인 이름, 원격 호스트 프로그램의 포트 번호)

제일 먼저 접속한 클라이언트의 연결을 승인

클라이언트가 서버에 접속을 요청하면 그 정보를 "대기열"이라고 불리는 목록으로 관리한다.

accept()를 호출하면 대기열에서 순서대로 꺼내 해당 클라이언트와 연결된 소켓을 만든다.

서버와 연결되면 Socket 객체가 생성된다.
서버와의 연결이 이루어지면 Socket 객체를 리턴한다.

서버의 대기열에 등록된다면 리턴한다.

com.eomcs.net.ex02.Client0110.java

현재 실행 중인 프로그램과 포트 번호가 중복되어서는 안된다.

keyboard.nextLine();
키보드에서 한 줄을 입력받을 때까지 리턴하지 않는다

Address already in use
이미 포트 번호를 쓰고 있다는 거

new ServerSocket(8888)

포트 번호 : 프로그램을 구분할 때 사용하는 포트 번호

new Socket(서버주소, 서버 포트번호)
new Socket("localhost", 8888)

클라이언트의 포트 번호는 OS가 자동으로 부여한다.
서버쪽 포트 번호는 개발자가 지정한다.

Client든 Server든 프로그램을 구분할 때 사용할 포트번호는 반드시 있어야 한다.

포트 번호는 양쪽 다 반드시 있어야 한다.

클라이언트가 접속을 요청하면 대기열에 클라이언트 정보를 저장한다.
저장은 큐(FIFO) 방식으로 관리한다.

new ServerSocket(포트번호, 대기열크기)

ServerSocket과 대기열

new ServerSocket(8888)

대기열 ← 50개의 연결 정보를 저장

대기열 부족. 연결 거부.

클라이언트가 연결을 끊는다고 대기열이 비는 게 아님
서버에서 삭제해야 됨

서버에서 accept 승인해야
연결은 된 상태지만 입출력은 안 됨

기본이 50개

backlog = 대기열 개수

동시 사용자 50명

대기열 개수가 크면 클수록 한 번에 연결된 개수가
메모리를 더 많이 사용

로컬에서 접속할 때 타임아웃 설정이 정상적으로 동작되지 않는다.

타임 아웃을 설정하는 방법

소켓을 생성할 때는 서버랑 연결하지마 소켓만 생성해
Socket socket = new Socket();

SocketAddress socketAddress = new InetSocketAddress("localhost", 8888);
SocketAddress ← 추상클래스
SocketAddress의 서브 클래스 InetSocketAddress 객체

socket.connect(socketAddress, 10000);
connect() 명시적으로 호출
여기서 타임 아웃 시간 지정

대기열과 accept()

new ServerSocket(8888)
대기열 기본 50개

accept(): 대기열에서 맨 앞에 있는 한 개 꺼내서 소켓에 포장해서 리턴. new Socket()

맨 앞부터 연결 정보를 순서대로 꺼낸다(remove).
소켓 객체에 포장한 후 리턴한다.

FIFO (Queue)

0개의 댓글