10282번: 해킹

최흉최악의 해커 yum3이 네트워크 시설의 한 컴퓨터를 해킹했다! 이제 서로에 의존하는 컴퓨터들은 점차 하나둘 전염되기 시작한다. 어떤 컴퓨터 a가 다른 컴퓨터 b에 의존한다면, b가 감염되면

www.acmicpc.net

 

 

 

 


 

 

 

  • 풀이

 

다익스트라로 쉽게 풀 수 있을 거라고 생각했던 문제였지만 메모리 초과때문에 50분동안 고생했던 문제였습니다.

 

 

메모리 초과였던 코드와 통과 코드의 차이는 = 하나의 차이였습니다.

 

 

다익스트라에서 거리를 초기화시키면서 이동하는 distance라는 배열에서의 문제였습니다.

if(distance[next.b] < distance[now.b] + next.s) continue;   //메모리 초과 코드
if(distance[next.b] <= distance[now.b] + next.s) continue;   // 통과 코드

 

해당 문제는 = 하나의 차이로 어떻게 메모리 초과가 발생한 이유는 간단했습니다. 

d의 자료의 a,b,s 중 1,2,0이 있고 2,1,0이 있다고 가정합시다. 또한 다익스트라를 돌며 distance[1] = 10, distance[2] = 10으로 초기화 되어있습니다. 이 경우 1,2와 2,1를 계속 돌며 무한루프를 돌게되고 큐에 계속 추가되며 결국 메모리초과를 발생시키게 되었던 것이였습니다.

 

 

  • 코드

 

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class Main {
	static StringBuilder sb;
	static int n, d, c, count, sum;
	static int[] distance;
	static ArrayList<Node>[] array;

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(sb);
	}

	// 데이터
	private static void SetData() throws Exception {
		InputReader in = new InputReader(System.in);

		int testcase = in.nextInt();
		sb = new StringBuilder();
		distance = new int[10001];
		
		for(int i = 0; i < testcase; i++) {
			n = in.nextInt();
			d = in.nextInt();
			c = in.nextInt();
			
			array = new ArrayList[n+1];
			for(int j = 1; j <= n; j++)
				array[j] = new ArrayList<Node>();
			
			for(int j = 0; j < d; j++)  {
				int a = in.nextInt();
				int b = in.nextInt();
				
				array[b].add(new Node(a, in.nextInt()));
			}
			
			dijkstra();
			
			count = 0;
			sum = 0;
			for(int j = 1; j <= n; j++) {
				if(distance[j] == Integer.MAX_VALUE) continue;
				
				count++;
				sum = Math.max(sum, distance[j]);
			}
			sb.append(count + " " + sum).append("\n");
		}
	}
	
	private static void dijkstra() {
		PriorityQueue<Node> pq = new PriorityQueue<>();
		Arrays.fill(distance, Integer.MAX_VALUE);
		pq.add(new Node(c, 0));
		distance[c] = 0;
		
		while(!pq.isEmpty()) {
			Node now = pq.poll();
			
			for(Node next : array[now.b]) {
				if(distance[next.b] <= distance[now.b] + next.s) continue;
				
				distance[next.b] = distance[now.b] + next.s;
				pq.add(new Node(next.b, distance[next.b]));
			}
		}
	}
}

class Node implements Comparable<Node>{
	int b;
	int s;
	
	public Node(int b, int s) {
		this.b = b;
		this.s = s;
	}

	@Override
	public int compareTo(Node o) {
		// TODO Auto-generated method stub
		return this.s - o.s;
	}
	
}

class InputReader {
	private final InputStream stream;
	private final byte[] buf = new byte[8192];
	private int curChar, snumChars;

	public InputReader(InputStream st) {
		this.stream = st;
	}

	public int read() {
		if (snumChars == -1)
			throw new InputMismatchException();
		if (curChar >= snumChars) {
			curChar = 0;
			try {
				snumChars = stream.read(buf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (snumChars <= 0)
				return -1;
		}
		return buf[curChar++];
	}

	public int nextInt() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		int res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public long nextLong() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		long res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public int[] nextIntArray(int n) {
		int a[] = new int[n];
		for (int i = 0; i < n; i++) {
			a[i] = nextInt();
		}
		return a;
	}

	public String nextLine() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isEndOfLine(c));
		return res.toString();
	}

	public boolean isSpaceChar(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	private boolean isEndOfLine(int c) {
		return c == '\n' || c == '\r' || c == -1;
	}
}

 

 

11779번: 최소비용 구하기 2

첫째 줄에 도시의 개수 n(1≤n≤1,000)이 주어지고 둘째 줄에는 버스의 개수 m(1≤m≤100,000)이 주어진다. 그리고 셋째 줄부터 m+2줄까지 다음과 같은 버스의 정보가 주어진다. 먼저 처음에는 그 버스

www.acmicpc.net

 

 

 

 


 

 

 

  • 풀이

 

주어진 연결된 노드 중 start에서 end까지 가는 최소비용을 구하면 되는 알고리즘 입니다.

 

우선순위큐를 사용하지 않은 다익스트라 알고리즘을 사용하는 경우 O(V^2)시간이 걸리기 때문에 100000*100000으로 1초가 넘어가게 되어 시간초과가 나게됩니다. 이 문제의 핵심은 우선순위큐를 사용한 다익스트라 알고리즘을 사용하여 O(ElogV)의 시간으로 풀어내야 하는 문제입니다. 

 

현재까지 누적된 distance값으로 우선순위큐를 매겨줍니다. 이렇게되면 가장 빨리 end에 도착한 값이 최소 비용으로 도착한 값이기 때문에 반복문을 종료하여도 됩니다. 

 

추가적으로 추적은 부모노드를 설정함으로써 역추적하여 구해주었습니다.

 

  • 코드

 

 

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class Main {
	static StringBuilder sb;
	static int N;
	static int[] parent, distance;
	static ArrayList<Node>[] array;

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(sb);
	}

	// 데이터
	private static void SetData() throws Exception {
		InputReader in = new InputReader(System.in);

		sb = new StringBuilder();
		N = in.nextInt();
		array = new ArrayList[N+1];
		for(int i = 1; i <= N; i++)
			array[i] = new ArrayList<>();
		
		int count = in.nextInt();
		
		for(int i = 0; i < count ; i++) {
			int a = in.nextInt();
			int b = in.nextInt();
			int c = in.nextInt();
			array[a].add(new Node(b,c));
		}
		
		int start = in.nextInt();
		int end = in.nextInt();
		
		dijkstra(start, end);
		sb.append(distance[end]).append("\n");
		
		Stack<Integer> stack = new Stack<>();
        while(end != 0) {
        	stack.add(end);
            end = parent[end];
        }
		sb.append(stack.size()).append("\n");
		
		while(!stack.isEmpty())
			sb.append(stack.pop() + " ");
	}

	private static void dijkstra(int start, int end) {
		PriorityQueue<Node> pq = new PriorityQueue<>();
        pq.offer(new Node(start, 0));
		
        parent = new int[N+1];
        distance = new int[N+1];
        Arrays.fill(distance, 100000000);
        distance[start] = 0;
        
        while(!pq.isEmpty()){
            Node now = pq.poll();
            if(now.x == end) break;

            for(Node node : array[now.x]) {
            	if(distance[node.x] > distance[now.x] + node.distance){
            		distance[node.x] = distance[now.x] + node.distance;
                    pq.add(new Node(node.x, distance[node.x]));
                    parent[node.x] = now.x;
                }
            }
        }
	}
}

class Node implements Comparable<Node>{
	int x;
	int distance;
	
	public Node(int x, int distance) {
		this.x = x;
		this.distance = distance;
	}

	@Override
	public int compareTo(Node o) {
		// TODO Auto-generated method stub
		return this.distance - o.distance;
	}
}

class InputReader {
	private final InputStream stream;
	private final byte[] buf = new byte[8192];
	private int curChar, snumChars;

	public InputReader(InputStream st) {
		this.stream = st;
	}

	public int read() {
		if (snumChars == -1)
			throw new InputMismatchException();
		if (curChar >= snumChars) {
			curChar = 0;
			try {
				snumChars = stream.read(buf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (snumChars <= 0)
				return -1;
		}
		return buf[curChar++];
	}

	public int nextInt() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		int res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public long nextLong() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		long res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public int[] nextIntArray(int n) {
		int a[] = new int[n];
		for (int i = 0; i < n; i++) {
			a[i] = nextInt();
		}
		return a;
	}

	public String nextLine() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isEndOfLine(c));
		return res.toString();
	}

	public boolean isSpaceChar(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	private boolean isEndOfLine(int c) {
		return c == '\n' || c == '\r' || c == -1;
	}
}

네트워크에 공부한 뒤 공부한 내용을 복습할겸 겸사겸사 스프링 공부도 해보고 싶어서 Spring boot로 채팅 프로그램을 만들어 보려고 합니다. 일반적인 http통신을 하는 서버들과 달리 채팅 서버는 socket통신을 하는 서버가 필요합니다.

 

http통신

  • client의 요청이 있을 때만 서버가 응답하고 연결을 종료하는 단방햔 통신 이다.
  • 따라서 client가 server에 접속해 콘텐츠를 요청하고 결과를 받아 소비하는 구조의 서비스에서 많이 사용된다.

socket통신

  • server와 client가 특정 port를 통해 지속적으로 연결유지 하여 실시간으로 양방향 통신을 하는 방식
  • 주로 채팅 같은 실시간성을 요구하는 서비스에서 많이 사용된다.

Websocket

  • Websocket은 기존의 단방향 HTTP프로토콜과 호환되어 양방향 통신을 제공하기 위해 개발된 프로토콜
  • 일반 Socket통신과 달리 HTTP 80 port를 이용하므로 방화벽에 제약이 없다
  • 접속까지는 HTTP 프로토콜을 이용하고 그 이후의 통신은 자체적인 Websocket 프로토콜로 통신하게 된다.

프로젝트 생성

start.spring.io에서 선택한 버전과 dependencies 정보

  • 프로젝트 생성은 start.spring.io에서 만들었습니다.

 

 

기본 메인 메소드

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class TestApplication {

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

}

프로젝트를 생성할 때 기본 메소드 그대로 사용하면 됩니다.

 

 

 

Websocket Handler 작성

import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.logging.Logger;

@Component
public class WebSocketChatHandler extends TextWebSocketHandler {

    private final static Logger LOG = Logger.getGlobal();

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String input = message.getPayload();
        LOG.info(input); // 채팅 log
        TextMessage textMessage = new TextMessage("Hello, 영진일지입니다. \n 웹소켓 테스트입니다.");
        session.sendMessage(textMessage);
    }
}

websocket 통신은 서버와 클라이언트가 1:N 으로 관계를 맺습니다. 따라서 한 서버에 여러 클라이언트가 접속 할 수 있으며, 서버에는 여러 클라이언트가 발송한 메시지를 받아 처리해줄 Handler의 작성이 필요합니다. 다음과 같이 TextWebSocketHandler 를 상속받아 Handler를 작성했습니다. Client로부터 받은 메시지를 콘솔에 출력하고 Client로 환영 메시지를 보내는 역할을 합니다.

 

 

 

Websocket Config 작성

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    private final WebSocketHandler webSocketHandler;

    public WebSocketConfig(WebSocketHandler webSocketHandler) {
        this.webSocketHandler = webSocketHandler;
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(webSocketHandler, "/ws/chat").setAllowedOrigins("*");
    }
}

방금전 만든 handler 를 이용하여 Websocket을 활성화 하기 위한 Config 파일을 작성했습니다.

@EnableWebSocket을 선언하여 Websocket을 활성화합니다.

Websocket에 접속하기 위한 endpoint는 /ws/chat으로 설정하고 도메인이 다른 서버에서도 접속 가능하도록 CORS 설정을 추가해줍니다. (여기서 endpoint 접근 url입니다. url:port번호 후 뒤에 붙는 문자열을 의미합니다.)

 

 

Websocket 테스트

 

테스트를 위한 클라이언트 대신 chrome 웹스토어에 있는 Simple Websocket Client를 설치하고 실행합니다.

Spring Boot 서버를 구동 후 설치한 확장프로그램 Simple WebSocket Client 를 실행하고 ws://localhost:8080/ws/chat 를 입력후 Open 을 누릅니다.

 

Websocket의 경우 별개의 프로토콜이므로 http 가 아닌 ws로 시작하는 주소체계를 갖습니다.

위는 Message Log창에 서버와 연결이 되어 서버로 부터 작성한 메세지가 오는 모습입니다.

 

또한 위의 사진은 스프링 서버에 전송온 Simple WebSocket Client에서 작성한 Request 메세지가 잘 전달된 모습입니다.

 

위와 같이 TCP/IP를 이용하여 클라이언트 대용인 Simple WebSocket Client와 서버인 Spring과의 3-way-handshake를 통한 연결 후 데이터를 전송하는 모습입니다.

'spring' 카테고리의 다른 글

[Spring] 빌드 툴(Ant, Maven, Gradle)  (0) 2021.10.28

빌드 툴이란?

  • 소스 코드의 빌드 과정을 자동으로 처리해주는 프로그램
  • 외부 소스코드(외부 라이브러리) 자동 추가 및 관리

 

빌드 툴이 왜 필요한가?

  • 대규모 프로젝트에선 빌드프로세스를 수동으로 호출이 실용적이지 않습니다.
  • 무엇을 빌드할지, 어떤 순서를 가지고 빌드할지, 어떤 의존성이 있는지 모두 추적하기 쉽지 않기때문입니다.
  • 빌드 툴을 사용하면 이를 일관되게 할 수 있습니다.

 

JAVA에서의 빌드 툴 종류

  • Ant
  • Maven
  • Gradle

 

Ant

  • 설정을 위해 xml을 사용합니다.
  • 간단하고 사용하기 쉽다고 합니다.
  • 단점
    • 복잡한 처리를 하려하면 빌드 스크립트가 장황해져 관리가 어렵습니다.
    • 외부 라이브러리를 관리하는 구조가 없다.

 

 

Maven

 

// xml의 예시 입니다.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>

   <groupId>com.example</groupId>
   <artifactId>demo-maven</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>demo-maven</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.5.4.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>


</project>
  • Ant가 가지고있는 단점을 보완하여 만들어진 빌드 툴입니다.
  • 설정을 위해 xml을 사용합니다.
  • 외부 라이브러리를 관리할 수 있습니다.
  • 장황한 빌드 스크립트 문제를 해결했습니다.
  • 단점
    • 특정 경우에 xml이 복잡해집니다.
    • xml 자체에 한계가 있습니다. (설정 내용이 길어지고 가독성 떨어짐)

 

 

Gradle

 

// gradle 예시

buildscript {
    ext {
        springBootVersion = '2.1.7.RELEASE'
    }
    repositories {
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group 'com.jojoldu.book'
version '1.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}
  • Maven이 가지고있는 단점을 보완하여 만들어진 빌드 툴입니다.
  • 설정할 때 xml대신에 groovy 언어를 사용합니다. (xml이 가지는 한계를 갖지 않습니다.)
  • 에시만봐도 Maven보다 가독성 면에서 뛰어나다는 장점이 있습니다.
  • 외부 라이브러리를 관리할 수 있습니다.
  • 유연하게 빌드 스크립트를 작성할 수 있습니다.
  • 캐싱이 잘되어 성능이 뛰어납니다. (실제로 Gradle이 Maven보다 최대 100배 빠르다고 합니다.)

'spring' 카테고리의 다른 글

[Spring] 간단한 웹소켓 프로그램 만들기  (0) 2021.10.28

소켓이란?

  • socket은 IP주소와 Port넘버가 합쳐진 네트워크 상에서 서버 프로그램과 클라이언트 프로그램이 통신할 수록 도와주는 소프트웨어 장치입니다.
  • TCP/IP를 이용하는 API로 소프트웨어로 작성된 통신의 접속점입니다.
  • 네트워크 상에서 서버와 클라이언트 프로그램이 특정포트를 통해 양방향 통신이 가능하도록 만들어주는 소프트웨어 장치입니다.
  • 멀리 떨어져있는 두 호스트를 연결해주는 매개체 역할

 

 

 

 

spring 으로 socket programming 한 뒤 정리하자.

'Network' 카테고리의 다른 글

[Network] OAuth  (0) 2021.10.27
[Network] 메세지 전송방식(유니캐스트, 멀티캐스트, 브로드캐스트)  (0) 2021.10.27
[Network] DNS 동작원리  (0) 2021.10.25
[Network] REST와 RESTful  (0) 2021.10.22
[Network] 쿠키와 세션  (0) 2021.10.21

 

4485번: 녹색 옷 입은 애가 젤다지?

젤다의 전설 게임에서 화폐의 단위는 루피(rupee)다. 그런데 간혹 '도둑루피'라 불리는 검정색 루피도 존재하는데, 이걸 획득하면 오히려 소지한 루피가 감소하게 된다! 젤다의 전설 시리즈의 주

www.acmicpc.net

 

 

 


 

 

 

  • 풀이

 

(0,0) 부터 (N-1,N-1)까지 상,하,좌,우로 1칸씩 이동하면서 가장 적은 도둑루피의 수를 만나면서 가는 합 중 가장 적은 합을 출력하면 되는 문제입니다.

 

문제를 읽으면서 가장 먼저 생각난 알고리즘은 가장 적은 수로만 (N-1, N-1)로 가기 위한 다익스트라였고, 다익스트라를 사용하여 알고리즘을 풀어냈습니다.

 

풀이 과정은 다음과 같습니다.

배열의 탐색은 가는 길을 가장 적은 수로만 가기 위해 distance 배열을 통해 현재 지나온 값보다 적은 값만 지나갈 수 있도록 하였습니다. 처음 초기화는 N의 가장 큰 값인 125와 도둑루피의 수중 최대값인 9를 곱한 125*125*9인 140625보다 큰 150000으로 초기화 하였습니다.

 

그래프 탐색이 종료되면 (N-1,N-1)에는 가장 적은 루피의 수를 만나고온 합이 저장되어있습니다.

 

 

  • 코드

 

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class Main {
	static StringBuilder sb;
	static int N;
	static int[][] array;
	static int[] dx = {0,0,-1,1};
	static int[] dy = {-1,1,0,0};

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(sb);
	}

	// 데이터
	private static void SetData() throws Exception {
		InputReader in = new InputReader(System.in);

		sb = new StringBuilder();
		int index = 1;
		while(true) {
			N = in.nextInt();
			if(N == 0) break;
			
			array = new int[N][N];
			for(int i = 0; i < N; i++) {
				for(int j = 0; j < N; j++) {
					array[i][j] = in.nextInt();
				}
			}
			
			sb.append("Problem "+(index++)+ ": "+ dijkstra()).append("\n");
		}
	}

	private static int dijkstra() {
		Queue<Node> queue = new LinkedList<>();
        queue.offer(new Node(0, 0));
		
        int[][] distance = new int[N][N];
        
        for(int i = 0; i < N; i++)
        	Arrays.fill(distance[i], 150000);
       
        distance[0][0] = array[0][0];
        
        while (!queue.isEmpty()) {
            Node nowNode = queue.poll();
 
            for(int direction = 0; direction < 4; direction++) {
            	int r = nowNode.x + dx[direction];
            	int c = nowNode.y + dy[direction];
            	
            	if(r < 0 || c < 0 || r >= N || c >= N) continue;
            	if(distance[r][c] <= distance[nowNode.x][nowNode.y] + array[r][c]) continue;
            	
            	distance[r][c] = distance[nowNode.x][nowNode.y] + array[r][c];
            	queue.add(new Node(r, c));
            }
        }
		return distance[N-1][N-1];
		
	}
}

class Node {
	int x;
	int y;
	
	public Node(int x, int y) {
		this.x = x;
		this.y = y;
	}
}

class InputReader {
	private final InputStream stream;
	private final byte[] buf = new byte[8192];
	private int curChar, snumChars;

	public InputReader(InputStream st) {
		this.stream = st;
	}

	public int read() {
		if (snumChars == -1)
			throw new InputMismatchException();
		if (curChar >= snumChars) {
			curChar = 0;
			try {
				snumChars = stream.read(buf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (snumChars <= 0)
				return -1;
		}
		return buf[curChar++];
	}

	public int nextInt() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		int res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public long nextLong() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		long res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public int[] nextIntArray(int n) {
		int a[] = new int[n];
		for (int i = 0; i < n; i++) {
			a[i] = nextInt();
		}
		return a;
	}

	public String nextLine() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isEndOfLine(c));
		return res.toString();
	}

	public boolean isSpaceChar(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	private boolean isEndOfLine(int c) {
		return c == '\n' || c == '\r' || c == -1;
	}
}

사용자가 마주하게 되는 곳

SSG.COM 로그인 화면

  • 현재 사용자는 쇼핑몰 사이트나 처음 들어가는 사이트에서 로그인할 때 위의 사진과 같은 네모박스로 로그인할 수 있습니다.
  • 이것을 가능하게 해준 것이 바로 OAuth입니다.

 

 

OAuth란?

  • OAuth는 Open Authorization, Open Authentication 뜻하는 것으로 Service Provider 애플리케이션(네이버, 카카오, 구글)의 유저 비밀번호를 Third party 앱에 제공 없이 인증, 인가를 할 수 있는 오픈 스탠다드 프로토콜입니다.
  • OAuth 인증을 통해 애플리케이션 API를 유저대신에 접근할 수 있는 권한을 얻을 수 있습니다.
  • OAuth가 사용되기 전에는 외부 사이트와 인증기반의 데이터를 연동할 때 인증방식의 표준이 없었기 때문에 기존의 기본인증인 아이디와 비밀번호를 사용하였는데, 유저의 비밀번호가 노출될 가망성이 커서 보안상 취약한 구조였습니다.
  • 그렇기 때문에 이 문제를 보안하기 위해 OAuth의 인증은 API를 제공하는 서버에서 진행하고, 유저가 인증되었다는 Access Token을 발급했습니다.
  • 그 발급된 Access token으로 Third party(Consumer) 애플리케이션에서는 Service Provider의 API를 안전하고 쉽게 사용할 수 있게 되었습니다.

 

 

OAuth 동작 원리

  • (A) (애플리케이션 → 사용자) 사용자 데이터에 접근하기 위한 권한을 요청합니다. 개념상 애플리케이션이 사용자에게 요청하지만, 실제 구현은 애플리케이션과 사용자 사이에 권한 제공기관이 중개 역할을 하는 경우가 일반적입니다.
  • (B) (사용자 → 애플리케이션) 접근에 동의함을 증명하는 권한 부여 동의서(Authorization Grant)를 발급합니다. RFC 6749에서는 4가지 유형의 권한 부여 동의서를 정의하고 있습니다. 애플리케이션과의 유형 및 권한 제공기관의 지원 여부에 따라 사용할 권한 부여 동의서의 유형이 결정됩니다.
  • (C) (애플리케이션 → 권한 제공기관) 권한 부여 동의서를 제출하여 접근 토큰을 요청합니다. 접근 토큰은 사용자 데이터에 접근할 수 있는 키입니다.
  • (D) (권한 제공기관 → 애플리케이션) 권한 부여 동의서를 확인하여 사용자가 동의한 데이터 항목, 범위 및 기간 등에 대한 정보가 담긴 접근 토큰을 제공합니다.
  • (E) (애플리케이션 → 데이터 제공기관) 접근 토큰을 제출하여 사용자 데이터를 요청합니다.
  • (F) (데이터 제공기관 → 애플리케이션) 사용자 데이터를 제공합니다. 이때 애플리케이션과이 제출한 접근 토큰이 유효함을 확인하고, 접근 토큰의 정보를 확인하여 제공할 데이터 항목, 범위 및 유효기간이 정해집니다.

 

 

유니캐스트, 멀티캐스트, 브로드캐스트란?

  • 네트워크에서 통신하는 방법을 구분짓는 방법입니다.

 

 

유니캐스트란?

  • 1:1 전송 방식입니다.
  • 데이터를 받고자하는 MAC Address를 프레임에 포함시켜 보내는 방식입니다.
  • 그래서 MAC Address를 찾아 통신하게되고 네트워크에 있는 노드들 중 자신의 MAC Address인 경우에만 패킷이 CPU에 전송됩니다.
  • 해당 안되는 다른 노드들에겐 CPU에 영향을 미치지않고 원하는 노드랑 통신하는 방법입니다.

 

 

브로드캐스트란?

  • TCP/IP의 IPv4에서 같은 대역의 네트워크 주소를 가진 모든 호스트들에게 패킷을 전송하는 방식으로 하나의 네트워크와 전체의 통신 방법입니다.
  • 같은 네트워크에 포함되는 장비들에게 거부권은 없고 무조건 수신하는 통신방법입니다.
  • 유니캐스트와 다르게 무조건 받아들여야하기 때문에 CPU까지 패킷이 올라오게되고 컴퓨터 자체에 부담이 증가하게됩니다.
  • 실질적인 통신은 IP Address가 아닌 MAC Address로 이루어지는데 IP 주소는 알고있지만 MAC Address를 모를 때 사용하는 방법입니다.
  • 대표적인 예로 ARP(자신과 데이터 통신을 하기 위한 다른 노드의 MAC Address를 알아내기위한 프로토콜)

 

 

멀티캐스트란?

    • 1:N 전송 방식입니다.
    • 자신의 데이터를 받기 원하는 특정 호스트들에게 보내는 것이 가능하지만, 스위치나 라우터가 이 기능을 지원해 주어야 합니다.
    • 유니캐스트로 일일이 보내거나 브로드캐스팅하기에 부담되는 경우 사용
    • 전송을 위한 그룹 주소는 D Class IP 주소 (224.0.0.0 ~ 239.255.255.255)로 전세계 개개인의 인터넷 호스트를 나타내는 A, B, C Class IP 주소와는 달리 실제의 호스트를 나타내는 주소가 아니며, 그룹 주소를 갖는 멀티캐스트 패킷을 전송받은 수신자는 자신이 패킷의 그룹에 속해있는가를 판단해 패킷의 수용여부를 결정하게 됩니다
    • 현재 인터넷상의 라우터들은 대부분 유니캐스트만을 지원하기 때문에 멀티캐스트 패킷을 전송하기 위해서 멀티캐스트 라우터 사이에 터널링이라는 개념을 사용하여 캡슐화된 패킷을 전송합니다.
    • 즉 멀티캐스트 주소를 가진 데이터 패킷 헤더 앞에 멀티캐스트를 지원하지 않는 일반 라우터들을 거칠 경우, 기존의 유니캐스트 패킷과 같은 방법으로 라우팅되어 최종적으로 터널의 종착지 노드로 전송될 수 있게 하는 것 입니다.

 

 

 

'Network' 카테고리의 다른 글

[Network] 소켓 및 Spring Socket Programming  (0) 2021.10.28
[Network] OAuth  (0) 2021.10.27
[Network] DNS 동작원리  (0) 2021.10.25
[Network] REST와 RESTful  (0) 2021.10.22
[Network] 쿠키와 세션  (0) 2021.10.21

+ Recent posts