백준 1092 : 문제링크

  • 문제유형 :

    • 탐욕 알고리즘
  • 설명

    • 크레인과 박스를 무게 기준으로 내림차순 정렬한다
    • 무거운 박스부터 크레인이 옮기도록한다
    • 크레인의 수 N, 박스의 수 M일때 시간복잡도는 O(NM)이다
  • 풀이

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    import sys

    n = int(input())
    cranes = list(map(int, input().split()))

    m = int(input())
    boxes = list(map(int, input().split()))

    if max(cranes) < max(boxes):
    print(-1)
    sys.exit()

    positions = [0] * n
    checked = [False] * m

    cranes.sort(reverse=True)
    boxes.sort(reverse=True)

    result = 0
    count = 0

    while True:
    if count == len(boxes):
    break
    for i in range(n):
    while position[i] < len(boxes):
    if not checked[position[i]] and cranes[i] >= boxes[position[i]]:
    checked[position[i]] = True
    position[i] += 1
    count += 1
    break
    position[i] += 1
    result += 1

    print(result)

Comment and share


백준 5719 : 문제링크

  • 문제유형 :

    • 그래프
    • 크루스칼 알고리즘
  • 설명

    • 정점의 개수 N이 최대 1000이므로, 가능한 통로의 개수는 약 N^2이다
    • 크루스칼 알고리즘은 간선의 개수가 E일 때 O(ElogE)로 동작하므로 해결할 수 있다 (정렬 알고리즘 시간복잡도)
  • 풀이

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    import math
    import sys

    input = sys.stdin.readline

    def get_distance(p1, p2):
    a = p1[0] - p2[0]
    b = p1[1] - p2[1]
    return math.sqrt((a * a) + (b * b))

    def get_parent(parent, n):
    if parent[n] == n:
    return n
    return get_parent(parent, parent[n])

    def union_parent(parent, a, b):
    a = get_parent(parent, a)
    b = get_parent(parent, b)
    if a < b:
    parent[b] = a
    else:
    parent[a] = b

    def find_parent(parent, a, b):
    a = get_parent(parent, a)
    b = get_parent(parent, b)
    if a == b:
    return True
    else:
    return False

    edges = []
    parent = {}
    locations = []
    n, m = map(int, input().split())

    for _ in range(n):
    x, y = map(int, input().split())
    locations.append((x, y))

    length = len(locations)

    for i in range(length - 1)
    for j in range(i + 1, length):
    edges.append((i + 1, j + 1), get_distance(location[i], location[j]))

    for i in range(1, n + 1):
    parent[i] = i

    for i in range(m):
    a, b = map(int, input().split())
    union_parent(parent, a, b)

    edges.sort(key=lambda data: data[2])

    result = 0
    for a, b, cost in edges:
    if not find_parent(parent, a, b):
    union_parent(parent, a, b)
    result += cost

    print("%0.2f" %result)

Comment and share


백준 5719 : 문제링크

  • 문제유형 :

    • 그래프
    • 다익스트라 최단 경로 알고리즘
  • 설명

    • 다익스트라 최단 경로에 포함되는 모든 간선을 추적한다
    • 최단 경로에 포함되는 모든 간선을 추적할 때 DFS를 사용하여 추적하여 제외시킨다
    • 제외된 간선 외에서 다익스트라 최단 경로 알고리즘으로 차선 최단 경로를 찾는다
  • 풀이

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    from collections import deque
    import heapq
    import sys

    input = sys.stdin.readline

    def dijkstra():
    heap_data = []
    heapq.heappush(heap_data, (0, start))
    distance[start] = 0
    while heap_data:
    dist, now = heapq.heappop(heap_data)
    if distance[now] < dist:
    continue
    for i in adj[now]:
    cost = dist + i[1]
    if distance[i[0]] > cost and not dropped[now][i[0]]:
    distance[i[0]] = cost
    heapq.heappush(heap_data, (cost, i[0]))

    def bfs():
    q = deque()
    q.append(end)
    while q:
    now = q.popleft()
    if now == start:
    continue
    for prev, cost in reverse_adj[now]:
    if distance[now] == distance[prev] + cost
    dropped[prev][now] = True
    q.append(prev)

    while True:
    n, m = map(int, input().split())
    if n == 0:
    break
    start, end = map(int, input().split())
    adj = [[] for _ in range(n + 1)]
    reverse_adj = [[] for _ in range(n + 1)]
    for _ in range(m):
    x, y, cost = map(int, input().split())
    adj[x].append((y, cost))
    reverse_adj[y].append((x, cost))
    dropped = [[False] * (n + 1) for _ in range(n + 1)]
    distance = [1e9] * (n + 1)
    dijkstra()
    bfs()
    distance = [1e9] * (n + 1)
    dijkstra()
    if distance[end] != 1e9:
    print(distance[end])
    else:
    print(-1)

Comment and share


백준 10282 : 문제링크

  • 문제유형 :

    • 그래프
    • 다익스트라 최단 경로 알고리즘
  • 설명

    • 정점의 개수 N, 간선의 개수 D
    • 우선순위 큐를 이용하여, 시간복잡도 O(NlogD)로 해결할 수 있습니다
  • 풀이

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    import heapq
    import sys
    input = sys.stdin.readline

    def dijkstra(strat):
    heap_data = []
    heapq.heappush(heap_data, (0, start))
    distance[start] = 0
    while heap_data:
    dist, now = heapq.heappop(heap_data)
    if distance[now] < dist:
    continue
    for i in adj[now]:
    cost = dist + i[1]
    if distance[i[0]] > cost:
    distance[i[0]] = cost
    heapq.heappush(heap_data, (cost, i[0]))

    for _ in range(int(input())):
    n, m, start = map(int, input().split())
    adj = [[] for i in range(n + 1)]
    distance = [1e9] * (n + 1)
    for _ in range(m):
    x, y, cost = map(int, input().split())
    adj[y].append((x, cost))
    dijkstra(start)
    count = 0
    max_distance = 0
    for i in distance:
    if i != 1e9:
    count += 1
    if i > max_distance:
    max_distance = i
    print(count, max_distance)

Comment and share


Goal

  • Cookie와 Session이 왜 필요한 이유
  • Cookie란 무엇인지에 대해 이해한다
  • Session이란 무엇인지에 대해 이해한다
  • Cookie와 Session의 차이에 대해 이해한다

쿠키와 세션의 사용 이유

HTTP 프로토콜의 특징

  1. 비연결지향(Conectionless)
    • HTTP는 클라이언트가 요청(Request)을 서버에 보내고, 서버는 클라이언트에 요청에 맞는 응답(Response)를 보내면 바로 연결을 끊는다
  2. 상태 정보를 유지 안 함(Stateless)
    • 연결을 끊는 순간 클라이언트와 서버의 통신은 끝나면 상태 정보를 유지하지 않는다

쿠키와 세션의 필요성

  • HTTP 프로토콜은 위와 같은 특징으로 모든 요청간의 의존관계가 없다
  • 즉, 현재 접속한 사용자가 이전에 접속했던 사용자와 같은 사용자인지 아닌지 알 수 있는 방법이 없다
  • 계속해서 연결을 유지하지 않기 때문에 리소스 낭비가 줄어드는 것이 큰 장점이지만, 통신할 때마다 새로 연결하기 때문에 클라이언트는 매 요청마다 인증을 해야한다는 단점이 있다
  • 이전 요청과 현재 요청이 같은 사용자의 요청인지 알기 위해서는 상태를 유지해야한다
  • HTTP프로토콜에서 상태를 유지하기 위한 기술로 쿠키와 세션이 있다

쿠키 (Cookie)

쿠키란?

  • 쿠키는 클라이언트(브라우저) 로컬에 저장되는 키와 값이 들어있는 작은 데이터 파일한다
  • 유효한 시간을 명시할 수 있으며, 유효 시간이 정해지면 브라우저가 종료되어도 쿠키가 유지된다는 특징이 있다
  • 쿠키는 클라이언트의 상태 정보를 로컬에 저장했다가 참조한다

구성요소

  • 쿠키의 이름(name)
  • 쿠키의 값(value)
  • 쿠키의 만료시간(Expire)
  • 쿠키를 전송할 도메인 이름(Domain)
  • 쿠키를 전송할 경로(Path)
  • 보안 연결 여부(Secure)
  • HttpOnly 여부(HttpOnly)
  • 지속 쿠키
    • 만료 날짜/시간을 지정하지 않으면 항상 유지하라는 것으로 판단하고 지속 쿠키에 저장된다
    • 파일로 저장되므로 브라우저가 종료되어도 쿠키는 남아있다
  • 세션 쿠키
    • 만료 날짜/시간을 지정하면 세션 쿠키로 저장된다
    • 브라우저 메모리에 저장되므로 브라우저가 종료되면 쿠키는 사라지게 된다

동작 방식

스크린샷 2020-11-10 오후 9 36 25

  1. 웹 브라우저가 서버에 요청
  2. 상태를 유지하고 싶은 값을 쿠키(Cookie)로 생성
  3. 서버가 응답할 때 Http Response Header의 Set-Cookie에 쿠키를 포함해서 전송
    1
    Set-Cookie: id=chan
  4. 전달받은 쿠키는 웹 브라우저에서 관리하고 있다가, 다음 요청 때 쿠키를 Http 헤더에 넣어서 전송
    1
    cookie: id=chan
  5. 서버에서는 쿠키 정보를 읽어 이전 상태 정보를 확인 후 응답

쿠키 사용 예

  • 아이디, 비밀번호 저장
  • 쇼핑몰 장바구니

쿠키의 제약사항

  • 클라이언트에 최대 300개까지 쿠키를 저장할 수 있다

  • 서버 도메인 하나당 최대 20개의 쿠키를 저장할 수 있다

  • 하나의 쿠키 값은 최대 4KB까지 저장할 수 있다

    쿠키는 사용자가 별도로 요청하지 않아도 브라우저(Client)에서 서버에 요청시 Request Header에 쿠키 값을 자동으로 넣어 보낸다

    그렇다고 모든 쿠키 값을 모든 요청에 넣어서 비효율적으로 동작하지 않고 지정 도메인에 해당하는 쿠키 값만을 제공한다

세션(Session)

세션이란?

  • 세션은 쿠키를 기반으로 동작하지만, 사용자 정보 파일을 브라우저에 저장하는 쿠키와 달리 세션은 서버 측에서 관리한다
  • 서버에서는 클라이언트를 구분하기 위해 세션 ID를 부여하며 웹 브라우저가 서버에 접속해서 브라우저를 종료할 때까지 인증상태를 유지한다
  • 접속 시간에 제한을 두어 일정 시간 응답이 없다면 정보가 유지되지 않게 설정이 가능하다
  • 사용자에 대한 정보를 서버에 두기 때문에 쿠키보다 보안에 좋지만, 사용자가 많아질수록 서버 메모리를 많이 차지하게 된다
  • 동접자 수가 많은 웹 사이트인 경우 서버에 과부하를 주게 되므로 성능 저하의 요인이 된다
  • 클라이언트가 Request를 보내면, 해당 서버 엔진이 클라이언트에게 유일한 ID를 부여하는데 이것이 세션이다

동작 방식

스크린샷 2020-11-10 오후 11 21 26

  1. 웹 브라우저가 서버에 요청
  2. 서버가 해당 웹 브라우저(클라이언트)에 유일한 ID(Session ID)를 부여함
  3. 서버가 응답할 때 HTTP Header(Set-Cookie)에 Session ID를 포함해서 전송
    • 쿠키에 Session ID를 JSESSIONID라는 이름으로 저장
      1
      Set-Cookie : JSESSIONID=g3r2sddh
  4. 웹 브라우저는 이후 웹 브라우저를 닫기까지 다음 요청 때 부여된 Session ID가 담겨있는 쿠키를 HTTP Header에 넣어서 전송
    1
    Cookie : JSESSIONID=g3r2sddh
  5. 서버는 세션 ID를 확인하고, 해당 세션에 관련된 정보를 확인한 후 응답

세션도 쿠키를 사용하여 값을 주고받으며 클라이언트의 상태 정보를 유지한다

즉, 세션이 상태 정보를 유지하는 수단으로 쿠키를 사용한다

쿠키와 세션의 차이

  • 저장 위치
    • 쿠키는 클라이언트(브라우저)의 메모리 또는 파일에 저장
    • 세션은 서버 메모리에 저장
  • 보안
    • 쿠키는 로컬에 저장되고, 특히 파일로 저장되는 경우가 있어 탈취, 변조에 위험하고 Request/Response시에 스니핑당할 위험이 있다
    • 세션은 클라이언트 정보 자체가 서버에 저장되어 있으므로 비교적 안전하다
  • 라이프 사이클
    • 쿠키중 지속 쿠키는 브라우저가 종료하더라도 저장되어있다
    • 세션은 만료시간/날짜를 정해서 기간이 지나면 자동으로 삭제하고 세션쿠키에서 세션 아이디를 정한 경우, 브라우저 종료시 세션아이디가 삭제된다
  • 속도
    • 쿠키는 클라이언트에 저장되어 있기 때문에 서버 요청시 속도가 빠르다
    • 세션은 정보가 서버에 있기 때문에 처리가 요구되어 비교적 느린 속도를 낸다

참고 - 캐시

  • 브라우저 캐시는 이미지(.png, .jpg)나 css, js파일등이 사용자의 브라우저에 저장되는 것이다
  • 이를 이용해서 같은 자원을 로드(load)해야할 경우에, 해당 자원을 다시 서버에 요청하지 않고 브라우저에 캐시되어 있는 자원을 쓰는 방식이다
  • 자원이 브라우저 캐시에 저장되면 브라우저에 있는 결 재사용하기 때문에 경우에 따라서 자원이 변경되어도 변경된 자원을 참조할 수 없는 경우가 있다
  • 따라서 사용자는 브라우저 캐시를 지워주거나 서버에서 클라이언트에 응답을 보낼 때 header에 자원 캐시 만료시간을 명시하는 방식을 사용하여 위와같은 문제를 해결할 수 있다

Comment and share

Web-HTTP

in Web, HTTP

HTTP

정의

  • HTTP(Hyper Text Transfer Protocol)는 웹 서버(Apache, Nginx 등)와 클라이언트(브라우저)가 인터넷 상에서 HTML문서와 같은 리소스들을 주고받을 수 있도록 하기 위해 만든 프로토콜(통신 규약)

    스크린샷 2020-11-10 오후 4 51 43

  • HTTP통신은 클라이언트가 데이터를 요청(request)하면 그 요청을 처리하여 서버가 다시 클라이언트에게 응답(response)하는 큰 흐름을 따른다

  • 어떠한 데이터의 형태도 주고 받을 수 있다

특징

  • 무상태(stateless) & 비연결성(Connectionless)
    • 한 번의 요청에 대해 TCP통신을 설정한 후 한 번의 요청에 대한 응답이 처리되면 TCP연결을 끊어 버리는 형태의 통신
    • TCP연결을 끊어 버리는 형태의 통신으로 연속적인 통신에 부적합
    • 하지만, 인터넷과 같이 다수의 사용자를 대상으로 한 Pull방식의 사용자가 필요한 문서 서비스를 전달 받는 구조에는 적합한 통신 구조
    • 한 번의 요청에 대해 한 번의 응답으로 트랜잭션이 종료되므로 연속적인 작업 처리에 필요한 트랜잭션 상태 정보를 관리하기 위한 Overhead가 없다
    • HTTP를 상업적으로 이용하면서 이러한 구조는 큰 단점이 되었다
      • 대안 기술: Cookies & Session Tracking

HTTP Request Message의 구조

3가지 부분으로 구성

스크린샷 2020-11-10 오후 5 17 15

  • start line(request line)

    • HTTP Method: GET, POST 등 action을 정의
    • Request target: request가 전송되는 uri(end point)
    • HTTP Version
  • headers

    • 클라이언트와 서버가 요청 또는 응답으로 부가적인 정보를 전송할 수 있도록 해주며, key:value 값으로 되어있다
    • Host: (가상 호스팅을 위해) 서버의 도메인명과 서버가 리스닝하는 (부가적인) TCP 포트를 특정한다
    • User-Agent: 요청을 보내는 클라이언트에 대한 정보
    • Accept
      • MIME 타입으로 표현
      • 클라이언트가 이해 가능한 컨텐츠 타입이 무엇인지 알려준다
      • 서버는 제안 중 하나를 선택하고 사용하며 Content-Type 응답 헤더로 클라이언트에게 선택된 타입을 알려준다
    • Cache-Control(HTTP/1.1)
      • Cache를 이용하여 웹 서버와 클라이언트간의 요청과 응답 횟수를 줄여 대역폭을 향상하기 위해 사용된다
      • 만기일(expiration)과 유효일(validation)을 지정
    • Connection
      • 트랜젝션 종료후에 네트워크 연결을 유지할지 말지를 결정한다
      • HTTP/1.0은 트랜젝션 이후의 커넥션을 종료한다
      • colse : 연결을 끊음
      • keep alive : 연결을 지속
    • Content-Type
      • 해당 요청이 보내는 메세지 body의 타입
      • 예를 들어 JSON을 보내면 application/json
    • Content-Length: 메세지 body의 길이
  • blank line: 요청에 대한 meta 정보가 전송되었음을 알린다

  • body:

    • 해당 request의 실제 메세지/내용이 들어있다
    • XML, HTML, JSON 데이터가 들어갈 수 있다

HTTP Response 구조

스크린샷 2020-11-10 오후 6 56 58

  • status line

    • response의 상태를 간략하게 나타내며, 3부분으로 구성되어 있다

      • HTTP Version
      • status code: 응답 상태를 나타내는 코드
      • status text: 으답 상태를 설명(ex: Not Found)
    • headers

      • request의 header와 동일하다
      • response에서만 사용되는 header값이 있다. (예: User-Agent가 없고, Server가 있음)
    • blank line

    • body: 실제 응답하는 데이터를 나타낸다

Comment and share

Web-Servlet

in Web, Servlet

Goal

  • Web Service의 기본적인 동작 과정을 이해한다
  • Servlet을 이해한다

Servlet이란

Servlet의 개념

웹 기반의 요청에 대한 동적인 처리가 가능한 하나의 클래스

  • Server Side에서 돌아가는 Java Program
  • 개발자가 작성하는 부분

Servlet의 기본적인 동작과정

스크린샷 2020-11-10 오전 10 49 45

  1. Web Server는 HTTP Request를 Web Container(Servlet Container)에게 위임한다
    1. web.xml설정에서 어떤 URL과 매핑되어 있는지 확인
    2. 클라이언트(browser)의 요청 URL을 보고 적절한 Servlet을 실행
  2. Web Container는 service() 메소드를 호출하기 전에 Servlet객체를 메모리에 올린다
    1. Web Container는 적절한 Servlet 파일을 컴파일(.class 파일 생성)한다
    2. .class 파일을 메모리에 올려 Servlet 객체를 만든다
    3. 메모리에 로드될 때 Servlet객체를 초기화하는 init()메소드가 실행된다
  3. Web Container는 Request가 올 때 마다 thread를 생성하여 처리한다.
    • 각 thread는 Servlet의 단일 객체에 대한 service() 메소드를 실행한다
  • Servlet Program에서 Thread의 역할
    • Thread의 역할: Servlet의 doGet()또는 doPost()를 호출
    • Web Container(Servlet Container)는 thread의 생성과 제거를 담당한다
      • 하지만 thread의 생성과 제거의 반복은 큰 오버헤드를 만든다
      • 이를 위해서 Tomcat(WAS)는 “Thread Pool”이라는 적절한 매커니즘을 사용해서 오버해드를 줄인다
    • 즉, WAS는 Servlet의 Life cycle을 담당한다
      • 웹 브라우저 클라이언트의 요청이 들어왔을때 Servlet 객체의 생성은 WAS가 알아서 처리한다
      • WAS 위에서 Servlet이 돌아다니고 개발자는 이 Servlet을 만들어야한다

Servlet Life Cycle

스크린샷 2020-11-10 오전 11 18 28

  • 클라이언트에 요청이 들어오면 WAS는 해당 요청에 맞는 Servlet이 메모리에 있는지 확인한다

    • 만약 메모리에 없다면 해당 Servlet Class를 메모리에 올린 후(Servlet 객체 생성)
      • init() 메소드 실행 후 service() 메소드를 실행
    • 메모리에 있다면 바로 service 메소드 실행
      1
      2
      3
      4
      5
      if(메모리에 없음) {
      // 해당 서블릿 클래스를 메모리에 올림
      // init() 메소드를 실행
      }
      // service() 메소드를 실행
  • init()

    • 한 번만 수행된다
    • 클라이언트의 요청에 따라 적절한 Servlet이 생성되고
      이 Servlet이 메모리에 로드될 때 init() 메소드가 실행된다
    • 역할: Servlet 객체를 초기화
  • service()

    • 응답에 대한 모든 내용은 service()메소드에 구현해야한다
    • Servlet이 수신한 모든 request에 대해 service() 메소드가 호출된다
      • HttpServlet을 상속받은 Servlet클래스에서 service()메서드를 오버라이드하지 않았다면, 그 부모인 HttpServlet의 service()가 호출된다
      • HttpServlet의 service()메소드는 템플릿 메소드 패턴으로 구현되었다
      • service()메소드는 request의 type(HTTP Method: GET, POST, PUT, DELETE)에 따라 적절한 메소드(doGet, doPost, doPut, doDelete)를 호출한다
      • 즉, 하위 클래스에서 doGet, doPost등의 메소드를 오버라이드 해두면 HttpServlet의 service()메소드가 요청에 맞는 메소드를 알아서 호출할 수 있게 된다
    • 메소드가 return하면 thread는 종료된다
  • destory()

    • 한 번만 수행된다
    • Web Application이 갱신되거나 WAS를 종료할 때 호출된다
    • 역할: Servlet 객체를 메모리에서 제거

Servlet 메서드 구현 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    // `javax.servlet.http.HttpServlet`를 상속받은 Servlet 클래스
public class LoginServlet extends HttpServlet {
// doPost()를 재정의
protected void doPost(HttpServletRequest request, HttpServletResponse response throws ServletException, IOException {
// read form fields
String username = request.getParameter("username");
String password = request.getParameter("password");

// get response writer
PrintWriter writer = response.getWriter();

/* 여기서 -> DB 접근 등 Business Logic 부분을 처리 */

// build HTML code (view 생성 부분)
String htmlResponse = "<html>";
htmlResponse += "<h2>Your username is: " + username + "<br/>";
htmlResponse += "Your password is: " + password + "</h2>";
htmlResponse += "</html>";

// return response
writer.println(htmlResponse);
}
}
  • WAS는 웹 브라우저로부터 요청을 받으면

    1. 요청할 때 가지고 있는 정보를 HttpServletRequest객체를 생성하여 저장한다
    2. 웹 브라우저에게 응답을 보낼 때, 사용하기 위한 HttpServletResponse 객체를 생성한다
    3. 생성된 HttpServletRequest, HttpServletResponse 객체를 Servlet에게 전달한다
  • 일반적으로 javax.servlet.http.HttpServlet를 상속받은 Servlet클래스를 작성한다

    1. HttpServletRequest request 파라미터를 통해서 사용자가 입력한 data를 읽는다
    2. HttpServletResponse 파라지터를 통해서 출력/결과를 생성한다
  • Servlet 클래스에 doGet() 또는 doPost()중 적어도 하나를 재정의하여 작성한다

    • protected doGet()(HttpServletRequest request, HttpServletResponse response){}
    • protected doPost()(HttpServletRequest request, HttpServletResponse response){}
  • HttpServletRequest request 객체

    • 사용자가 입력한 내용을 request 객체에 받아온다

      • Http 프로토콜의 Request정보를 Servlet에 전달
    • 헤더 정보, 파라미터, 쿠키, URI, URL, Body의 Stream등을 읽어 들이는 메소드가 있다.

    • getHeader(“원하는 헤더 이름”)

      • 원하는 헤더 정보를 확인할 수 있다
    • getParameter()

      • 이 메소드를 호출하여 parameter값을 가져온다
        • parameter값은 URL또는 form의 input tag를 통해서 넘어올 수 있다
      • Ex.
        1
        2
        String name = request.getParameter("firstname");
        int year = Integer.parseInt (request.getParameter("year"));
    • getParameterValues()

      • parameter가 여러 개의 값을 반환할 때 이 메소드를 호출한다. (Ex. checkbox)
        1
        String languages[] = request.getParameterValues("language");

Servlet Concurrency

스크린샷 2020-11-10 오후 1 35 15

  • Java 서블릿 컨테니어/ 웹 서버는 일반적으로 멀티 쓰레드 환경이다.

    • 같은 Servlet에 대한 여러 개의 요청이 동시에 실행될 수 있어 runtime에 따라 결과가 달라질 수 있다
    • 즉, Servlet은 메모리에 한 번 올라오고 멀티 쓰레드 환경에서 여러 thread는 하나의 Servlet을 공유하기 대문에 Concurrency Control가 필요하다
  • Servlet의 service() 메소드 안의 변수

    • 정적 변수, 맴버 변수: 공유하는 자원이므로 상호 배제가 필요
    • 지역 변수: thread마다 독립적으로 생성

Servlet Annotation

스크린샷 2020-11-10 오후 1 44 53

  • Servlet API 3.0은 javax.servlet.annotation이라는 새로운 패키지를 도입했다.
    • Tomcat 7이상에서 사용가능
  • Annotation은 Web Deployment Descriptor파일(web.xml)의 XML 설정을 대체할 수 있다
  • Annotation Type
    • @WebServlet: 서블릿 선언
    • @WebInitParam: 초기화 매개 변수 지정
  • Ex)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @WebServlet(value = "/Simple", 
    initParams = {@WebInitParam(name="foo", value="Hello "),
    @WebInitParam(name="bar", value=" World!")})
    public class Simple extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.setContentType("text/html");
    PrintWriter out=response.getWriter();

    out.print("<html><body>");
    out.print("<h3>Hello Servlet</h3>");
    out.println(getInitParameter("foo"));
    out.println(getInitParameter("bar"));
    out.print("</body></html>");
    }
    }

Comment and share


Goal

  • Static Pages와 Dynamic Pages 과정을 이해한다
  • Web Server와 WAS의 차이를 이해한다
  • Web 서비스 구조(Web Service Architecture)에 대해 이해한다

Static Pages와 Dynamic Pages

스크린샷 2020-11-10 오전 12 05 07

Static Pages

  • Web Server는 파일 경로 이름을 받아 경로와 일치하는 file contents를 반환한다.
  • 항상 동일한 페이지를 반환
  • Ex) image, html, css, javascript파일

Dynamic Pages

  • 인자의 내용에 맞게 동적인 contents를 반환
  • 웹 어플리케이션 서버에 의해서 실행되는 프로그램을 통해 만들어진 결과물 (Servlet: WAS위에 돌아가는 Java Program)
  • Servlet의 doGet()을 구현

Web Server와 WAS의 차이

스크린샷 2020-11-10 오전 12 15 07

Web Server

  • Web Server의 개념
    • 웹 브라우저 클라이언트로부터 HTTP 요청을 받아 정적인 컨텐츠(.html .jpeg .css등)를 제공하는 컴퓨터 프로그램
  • Web Server의 기능
    • HTTP 프로토콜을 기반으로 하여 클라이언트(웹 브라우저 또는 웹 크롤러)의 요청을 서비스하는 기능을 담당한다
    • 요청에 따라 아래의 두 가지 기능 중 적절하게 선택하여 수행한다
    • 기능 1)
      • 정적인 컨텐츠 제공
      • WAS를 거치지 않고 바로 자원을 제공한다
    • 기능 2)
      • 동적인 컨텐츠 제공을 위한 요청 전달
      • 클라이이언트 요청(Request)를 WAS에 보내고, WAS가 처리한 결과를 클라이언트에게 전달(응답, Response)한다
  • Web Server의 예
    • Ex) Apache Server, Nginx, IIS등

WAS(Web Application Server)

  • WAS의 개념

    • DB조회나 다양한 로직 처리를 요구하는 동적인 컨텐츠를 제공하기 위해 만들어진 Application Server
    • HTTP를 통해 컴퓨터나 장치에 애플리케이션을 수행해주는 미들웨어(소프트웨어 엔진)이다.
    • 웹 컨테이너(Web Container) 혹은 서블릿 컨테이너(Servlet Container)라고도 불린다
      • Container란 JSP, Servlet을 실행시킬 수 있는 소프트웨어
      • WAS는 JSP, Servlet 구동 환경을 제공한다
  • WAS의 역할

    • WAS = Web Server + Web Container
    • Web Server 기능들을 구조적으로 분리하여 처리하고자하는 목적으로 제시되었다.
      • 분산 트랜젝션, 보안, 메세징, 쓰레드 처리등의 기능을 처리하는 분산 환경에서 사용된다.
      • 주로 DB서버와 같이 수행된다
    • 현재는 WAS가 가지고 있는 Web Server도 정적인 컨텐츠를 처리하는데 있어서 성능상 큰 차이가 없다.
  • WAS의 주요 기능

    1. 프로그램 실행환경과 DB 접속 기능 제공
    2. 여러 개의 트랜잭션(논리적인 작업 단위)관리 기능
    3. 업무를 처리하는 비지니스
  • WAS의 예

    • Ex) Tomcat, JBoss, Jeus, Web Sphere등

Web Serve와 WAS를 구분하는 이유

  • Web Serve가 필요한 이유?

    • 웹 브라우저(클라이언트)에 이미지 파일(정적 컨텐츠)를 보내는 과정을 생각해보자
      • 이미지 파일과 같은 정적인 파일들은 웹 문서(HTML 문서)가 클라이언트로 보내질 때 함께 가는 것이 아니다.
      • 클라이언트가 HTML문서를 먼저 받아오고 그에 맞게 필요한 이미지 파일들을 다시 서버로 요청하면 그 때서야 이미지 파일을 받아온다.
      • Web Server를 통해 정적인 파일들을 Application Server까지 가지 않고 앞단에서 빠르게 보내줄 수 있다.
    • Web Server에서는 정적 컨텐츠만 처리하도록 기능을 분배하여 서버의 부담을 줄일 수 있다
  • WAS가 필요한 이유?

    • 웹 페이지는 정적 컨텐츠와 동적 컨텐츠가 모두 존재한다
      • 사용자의 요청에 맞게 적절한 동적 컨텐츠를 만들어 제공해야 한다
      • 이때, Web Server만을 이용한다면 사용자가 원하는 요청에 대한 결과값을 미리 만들어 놓고 서비스를 해야한다
      • 하지만 이렇게 수행하기에는 자원이 절대적으로 부족하다
    • 따라서 WAS를 통해서 요청에 맞는 데이터를 DB에서 가져와서 비지니스 로직에 맞게 그때 그때 결과를 만들어서 제공함으로써 자원을 효율적으로 사용할 수 있다.
  • 그렇다면 WAS가 Web Server의 기능도 모두 수행하면 되지 않을까?

    1. 기능을 분리하여 서버 부하 방지
      • WAS는 DB조회나 다양한 로직을 처리하느라 바쁘기 때문에 단순한 정적 컨텐츠는 Web Server에서 빠르게 클라이언트에게 제공하는 것이 좋다
      • WAS는 기본적으로 동적 컨텐츠를 제공하기 위해 존재하는 서버
    2. 물리적으로 분리하여 보안 강화
      • SSL에 대한 암복호화 처리에 Web Server를 사용
    3. 여러 대의 WAS를 연결 가능
      • Load Balancing을 위해서 Web Server를 사용
      • fail over(장애 극복), fail back처리에 유리
      • 특히 대용량 웹 어플리케이션의 경우(여러 개의 서버 사용) Web Server와 WAS를 분리하여 무중단 운영을 위한 장애 극복에 쉽게 대응할 수 있다
      • 예를 들어, 앞 단의 Web Server에서 오류가 발생한 WAS를 이용하지 못하도혹 한 후 WAS를 재시작함으로써 사용자는 오류를 느끼지 못하고 이용할 수 있다.
    4. 여러 웹 어플리케이션 서비스 가능
      • 예를 들어, 하나의 서버에서 PHP Application과 Java Application을 함께 사용하는 경우
    • 즉 자원 이용의 효율성 및 장애 극복, 배포 및 유지보수의 편의성을 위해서
      Web Server와 WAS를 분리한다
    • Web Server를 WAS 앞에 두고 WAS를 Web Server에 플러그인 형태로 설정하면 더욱 효율적인 분산처리가 가능하다

Web Service Architecture

  • Architecture 종류
    1. Client -> Web Server -> DB
    2. Client -> WAS -> DB
    3. Client -> Web Server -> WAS -> DB

스크린샷 2020-11-10 오전 10 24 24

  • 3번 구조의 동작 과정
    1. Web Server는 웹 브라우저 클라이언트로부터 HTTP 요청을 받는다
    2. Web Server는 클라이언트의 요청(Request)을 WAS에 보낸다
    3. WAS는 관련된 Servlet을 메모리에 올린다
    4. WAS는 web.xml을 참조하여 해당 Servlet에 대한 Thread를 생성한다 (Thread Pool 이용)
    5. HttpServletRequest와 HttpServletResponse 객체를 생성하여 Servlet에 전달한다
      1. Thread는 Servlet의 service() 메소드를 호출한다
      2. service()메소드는 요청에 맞게 doGet()또는 doPost()메소드를 호출한다
      3. protected doGet(HttpServletRequest request, HttpServletResponse response)
    6. doGet()또는 doPost()메소드는 인자에 맞게 생성된 적절한 동적 페이지를 Response객체에 담아 WAS에 전달한다
    7. WAS는 Response객체를 HttpResponse형태로 바꾸어 Web Server에 전달한다
    8. 생성된 Thread를 종료할고, HttpServletRequest와 HttpServletResponse 객체를 제거한다

Comment and share


백준 1325 : 문제링크

  • 문제유형 :

    • 그래프 탐색

    • BFS

  • 설명

    • DFS, BFS를 수행할 때마다 방문하게 되는 노드의 개수를 계산
    • 가장 노드의 개수가 크게 되는 시작 정점을 출력
  • 풀이

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    from collections import deque

    n, m = map(int, input().split())
    adj = [[] for _ in range(n + 1)]

    for _ in range(m):
    x, y = map(int, input().split())
    adj[y].append(x)

    def bfs(v):
    q = deque([v])
    visited = [False] * (n + 1)
    visited[v] = True
    count = 1
    while q:
    v = q.popleft()
    for e in adj[v]:
    if not visited[e]:
    q.append(e)
    visited[e] = True
    count += 1
    return count

    result = []
    max_value = -1

    for i in range(1, n + 1):
    c = bfs(i)
    if c > max_value:
    result = [i]
    max_value = c
    elif c == max_value:
    result.append(i)
    max_value = c

    for e in result:
    print(e, end = " ")

Comment and share


백준 1012 : 문제링크

  • 문제유형 :

    • 그래프 탐색

    • DFS

  • 설명

    • 연결 요소의 개수를 세는 문제
    • 모든 정점에 대하여 BFS를 수행하고, 한 번 방문한 정점은 다시 확인하지 않음
    • BFS를 수행한 총 횟수를 계산
  • 풀이

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    import sys
    sys.setrecursionlimit(100000)

    def dfs(x, y):
    visited[x][y] = True
    directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
    for dx, dy in directions:
    nx, ny = x + dx, y + dy
    if nx < 0 or nx >= n or ny < 0 or ny > m:
    continue
    if array[nx][ny] and not visited[nx][ny]:
    dfs(nx, ny)

    for _ in range(int(input())):
    m, n, k = map(int, input().split())
    array = [[0] * m for _ in range(n)]
    visited = [[False] * m for _ in range(n)]
    for _ in range(k):
    y, x = map(int, input().split())
    array[x][y] = 1
    result = 0
    for i in range(n):
    for j in range(m):
    if array[i][j] and not visited[i][j]:
    dfs(i, j)
    result += 1
    print(result)

Comment and share

Yechan Kim

author.bio


author.job