728x90
반응형

Channels and Buffers : 데이터는 항상 채널에서 버퍼로 읽히거나 버퍼에서 채널로 쓰여진다.

[Non-blocking IO]

하나의 Thread는 버퍼에 데이터를 읽도록 채널에 요청할 수 있다. 채널이 버퍼로 데이터를 읽는 동안 Thread는 다른 작업을 수행할 수 있다.

[Selectors]

selector는 여러 개의 채널에서 이벤트를 관리할 수 있는 객체이다.

[Channels]

channel에서 buffer로 읽거나 buffer를 채널로 쓰거나 할 수 있다.

( 이전에는 OutputStream과 InputStream을 사용하였어야 하는데 Channel만으로 할 수 있게 되었다)

channel에는 여러가지 type이 있다.

  • FileChannel : 파일에 데이터를 읽고 쓴다.
  • DatagramChannel : UDP를 이용해 네트워크를 통해 데이터를 읽고 쓴다.
  • SocketChannel : TCP를 이용해 네트워크를 통해 데이터를 읽고 쓴다.
  • ServerSocketChannel : 들어오는 TCP 연결을 수신할 수 있다. 들어오는 연결마다 SocketChannel이 만들어진다.

[Buffers ]

채널과 상호작용할 때 사용된다. 데이터는 채널에서 버퍼로 읽혀지거나, 버퍼에서 읽혀 채널로 쓰여진다.

  1. 버퍼에 데이터 쓰기
  2. buffer.flip() 호출 → 읽기모드
  3. 버퍼에서 데이터 읽기
  4. buffer.clear() 호출 → 쓰기 모드

Selectors : 셀렉터를 사용하면 하나의 쓰레드가 여러 채널을 처리할 수 있다.

Selector는 사용을 위해 하나 이상의 채널을 Selector에 등록하고 select() 메서드를 호출해 등록된 채널 중 이벤트 준비가 완료된 하나 이상의 채널이 생길 때까지 block된다.

Selector selector = Selector.open(); // Selector 생성

selector에 채널을 등록하기 위해서는 register() 메서드를 사용해야 한다. (채널을 selector에 등록)

channel.configureBlocking(false);
// selector에 채널을 등록하기 위해서는 반드시 해당 채널이 non-blocking 모드로 변환되어야 한다. 
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);

SelectionKey : register() 메서드를 이용해 채널을 Selector에 등록하면 SelectionKey 객체가 반환된다.

Channel channel = selectionKey.channel();
Selector selector = selectionKey.selector();

Selector에 하나 이상의 채널을 등록한 후에는 select() 메소드를 호출할 수 있다. select() 메소드는 accept, connect, read, write 이벤트에 대해 준비되어 있는 채널을 반환한다.

select()메서드를 사용하면 개수가 반환된다. select() 메서드를 통해 하나 이상의 준비된 채널이 발생하면, selectedKeys() 메서드를 사용해 준비된 채널의 집합을 반환 받는다.

Set<SelectionKey> selectedKeys = selector.selectedKeys();

[ServerSocketChannel] : ServerSocket과 마찬가지로 들어오는 TCP 연결을 수신 대기 할 수 있는 채널이다.

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9999));
while(true){
	SocketChannel socketChannel = serverSocketChannel.accept();
}

ServerSocketChannel은 Non-blocking 모드로 설정이 가능하다.

SocketChannel은 TCP 네트워크 소켓에 연결된 채널이다. Socket의 역할과 같다.

SocketChannel도 non-blocking 모드로 설정할 수 있다.

728x90
반응형

'백엔드 > Network Programming' 카테고리의 다른 글

Socket Programming(3) - Socket for Server  (0) 2022.11.21
Socket Programming(2) - Socket for Client  (0) 2022.11.13
Socket Programming(1) - socket이란?  (0) 2022.11.13
URL and URI's key  (2) 2022.10.15
Internet protocols and layers  (2) 2022.09.09
728x90
반응형

ServerSocket Class

  • 서버쪽에서 Socket을 생성할 때도 ,hostname 또는 IP주소와 port number가 필요하다.
  • 서버의 입장에서는 누가 connection을 요청할지 알 수 가 없어서 binding된 port를 계속해서 듣고 있어야 한다
  • 그래서 Socket Class를 사용하지 않고 ServerSocket Class를 따로 만들어야 한다. 
  • Constructors
    • public ServerSocket(int port) throws BindException, IOException
    • public ServerSocket(int port, int queueLength) throws BindException, IOException
      • 서버는 동시에 여러 Client로부터 request를 받을 수 있기 때문에 동시에 처리를 못하니까 queue에다가 request를 넣어서 처리한다. queueLength는 queue의 길이를 의미한다.
    • public ServerSocket(int port, int queueLength, InetAddress bindAddress) throws IOException
    • public ServerSocket() throws IOException  => binding 없이 socket 생성하고 binding 반드시 해주어야 함
      • public void bind(SocketAddress endpoint) throws IOException
      • public void bind(SocketAddress endpoint, int queueLength) throws IOException

예를 들어 위와 같은 코드를 입력하면 지금 현재 내 컴퓨터에서 사용되고 있는 port number들을 보여준다.

엄청 많은 port가 사용되고 있는데 한번 64032번에서는 어떤 프로그램이 실행되고 있는지 확인해보자.

17352 PID에서 사용되고 있는 것을 알 수 있다. 그럼 작업 관리자에서 어떤 프로그램인지 확인할 수 있다.

KOSinj.exe(?) 이런게 port 64032에서 사용되고 있다는 사실을 알 수 있다.

 

Server Program의 life Cycle

  1. ServerSocket() 생성자를 통하여 특정 port에 ServerSocket이 생성된다
  2. ServerSocket은 들어오는 connection을 accept() 메서드를 통해 듣는다.
    • accept()는 blocking 형태로 동작한다 -> accept()가 connection이 올때까지 기다리고 밑에 라인은 실행하지 않는다. 
    • client와 server가 연결되면 Socket object를 리턴한다. ( client와 Server를 연결하는 소켓이다)
  3. Socket의 getInputStream()과 getOutputStream() 메서드를 호출할 수 있다.
  4. Server와 Client는 약속된 protocol에 따라 interact한다.
  5. Server, Client close connection
  6. 서버는 다음 connection을 위해 Step2로 가고 다음 connection을 기다린다.

DaytimeServer -> DaytimeClient를 실행하여 localhost의 port 13번에서 서버가 실행되는 것을 확인한다.

 

위의 코드의 문제점은 무엇일까??

코드의 구조를 보면 connection request를 하나 받을 때까지 기다린다. 계속 기다리고 있다가 connection 들어오면 write를 해주고 다시 while문을 와서 다음 request를 기다린다.

만약에 client1번이 request를 보냈는데, 이 client가 굉장히 느린 client였다고 가정해보자. 그 다음 엄청나게 빠른 client2가 request를 보냈다고 가정해보자. 근데 아직도 client1이 아직도 request를 못받아서 client2는 계속 기다리고 있어야 한다. 

--> IO blocking 대문에 기다려야하는 시간이 길어진다. 

 

해결방법)

  • 각각의 connection마다 새로운 process를 만든다 (옛날의 UNIX에서는 이렇게 동작함)
  • 이렇게 하면 memory를 너무 많이 쓰기 때문에 각각의 connection마다 새로운 thread를 생성한다.

 

문제점  -> 앞의 방법의 문제점은??

  • 만약에 request가 굉장히 많이 들어오면 thread가 엄청나게 생긴다
  • thread로 인한 overhead로 인해서 performance가 slow down된다
  • DoS 공격에도 취약해진다. 

해결 방법)

  • Thread Pool을 사용한다
  • Thread Pool은 request들어올때마다 Thread를 생성하는 것이 아닌, Pool을 만들어서 이 thread를 이용해서 request를 해결한다.
  • Thread를 반납하고 다시 사용될 수 있도록 한다. 

이상적인 thread pool size는 프로그램이 I/O bound인지 CPU bound인지에 따라 다르다. 

Thread pool size가 너무 크면 memory가 높게 사용되기 때문에 본인의 상황에 맞게 사용하여야 한다.

그래서 보통은 다음과 같은 식에 따라 thread의 개수를 정한다.

 

isClosed and isBound

  • isClosed()
    • 만약 ServerSocket이 닫혔으면 true를 리턴한다
    • ServerSocket object가 ServerSocket()으로 생성되고, port와 아직 연결되어 있지 않으면 닫힌 것으로 생각하지 않는다 -> false를 리턴
  • isBound()
    • ServerSocket이 한번이라도 port와 binding되었으면 True를 리턴한다.

문제는 isClosed()가 true라고 해서 열려있는 것은 아니다. 그럼 ServerSocket이 open되어있다는 사실을 어떻게 알 수 있을까?

--> isBound() && !isClosed()

 

 

728x90
반응형

'백엔드 > Network Programming' 카테고리의 다른 글

Non-blocking I/O in Java  (0) 2022.12.12
Socket Programming(2) - Socket for Client  (0) 2022.11.13
Socket Programming(1) - socket이란?  (0) 2022.11.13
URL and URI's key  (2) 2022.10.15
Internet protocols and layers  (2) 2022.09.09
728x90
반응형

JVM은 다른 프로그램을 실행시키는 것이 목적이다. 두 가지 기능이 있다고 말할 수 있는데,

  1. 자바 프로그램이 어느 기기나 운영체제 상에서도 실행될 수 있도록 한다
    • 자바와 os 사이에서 중개자 역할을 수행하여 OS에 상관없이 재사용을 가능하게 해준다.
  2. 프로그램 메모리를 관리하고 최적화 한다

JVM은 코드를 실행하고, 해당 코드에 대해 런타임 환경을 제공하는 프로그램에 대한 사양이다.

JVM은 보통 어떤 기기상에서 실행되고 있는 프로세스, 특히 자바 앱에 대한 리소스를 대표하고 통제하는 서버를 지칭한다.

자바 애플리케이션을 클래스 로더를 통해 읽어들이고, 자바 API와 함께 실행하는 역할을 한다.

  1. 프로그램이 실행되면 JVM은 OS로부터 프로그램에 필요한 메모리를 할당받는다.
  2. javac(자바 컴파일러)가 자바 소스코드를 읽고, 자바 바이트코드(.class)로 변환한다.
  3. 변경된 class 파일들을 클래스 로더를 통해 JVM 메모리 영역으로 로딩한다.
  4. 로딩된 class 파일들은 Execution engine을 통해 해석된다.
  5. 해석된 바이트 코드는 메모리 영역에 배치되어 수행된다. 이 때 JVM은 쓰레드 동기화나 가비지 컬렉션 같은 메모리 관리 작업을 수행한다.

[클래스 로더] : JVM은 런타임 시에 처음으로 클래스를 참조할 때 해당 클래스를 로드하고 메모리 영역에 배치시키는데 이 동적 로드를 담당하는 부분이 바로 클래스 로더이다.

Runtime Data Access

: JVM이 운영체제 위에서 실행되면서 할당받는 메모리 영역이다.

PC 레지스터, JVM 스택, 네이티브 메서드 스택, 힙, 메서드 영역

  • PC 레지스터 : 스레드가 어떤 명령어로 실행되어야 할지 기록하는 부분 (JVM 명령의 주소를 가진다)
  • 스택 : 지역변수, 매개변수, 메서드 정보, 임시 데이터 등을 저장
  • 네이티브 메서드 스택 : 실제 실행할 수 있는 기계어로 작성된 프로그램을 실행시키는 영역
  • 힙 : 런타임에 동적으로 할당되는 데이터가 저장되는 영역. 객체나 배열 생성이 여기에 해당함. ( 힙에 할당된 데이터들이 가비지 컬렉터의 대상이 된다. JVM 성능에 영향을 미친다 )
  • 메서드 영역 : JVM이 시작될 때 생성되고, JVM이 읽은 각각의 클래스와 인터페이스에 대한 런타임 상수 풀, 필드 및 메서드 코드, 정적 변수, 메서드의 바이트 코드 등을 보관한다.

Garbage Collection

C나 C++은 개발자가 직접 메모리를 관리했지만 자바에서는 JVM이 프로그램 메모리를 관리한다. JVM은 Garbage Collection이라는 프로세스를 통해 메모리를 관리하는데 참조되지 않은 객체들을 탐색하여 삭제하고 삭제된 객체의 메모리를 반환하고 힙 메모리를 재사용하는 과정을 거친다.

 

 

https://gyoogle.dev/blog/computer-language/Java/Java 를 참조했습니다

728x90
반응형
728x90
반응형

Java에서의 Socket

Java에서는 socket class가 있어서 지원해준다.

  • java.net.Socket

    • client side의 TCP operation을 진행하는 기본적인 class
    • 밑에 함수들은 remote socket으로 connection을 open하는 함수이다
    • 기본 Constructor (생성자들) -> 여기서 host와 port는 remote(서버)의 주소와 portnumber이다. 
    public Socket(String host, int port) throws UnknownHostException,IOException
    public Socket(InetAddress host, int port) throws IOException
    
    try{
    	Socket toOReilly = new Socket("www.oreilly.com",80);
    } catch(UnknownHostException ex){
    	System.err.println(ex);
    } catch(IOException ex){
    	System.err.println(ex);
    }
  • remote와 local을 나누어서 local interface 어떤 것을 connect할지 정할 수도 있다.
public Socket(String host, int port, InetAddress interface, int localPort) throws UnknownHostException,IOException

그럼 위의 경우에는 remote만 적어주는데 local은 어떻게 되는 것일까?

→ OS에서 그냥 자동으로 선택해준다

 

또한, Socket을 만들고 바로 connect하는 것이 아니라, 만들고 나중에 connect할 수 도 있다.

public Socket()
public void connect(SocketAddress endpoint, int timeout) throws IOException

 

  • SocketAddress Class
    • connection endpoint ( remote host )를 나타내는 것을 도와주는 클래스
    • abstract class이고 생성자밖에 없다
    • socket connection정보(IP 주소, port number)를 제공하는 저장소 느낌이다
    • connect 함수를 사용할 수도 있다. 
    • Getter method
public SocketAddress getRemoteSocketAddress()
public SocketAddress getLocalSocketAddress()

  • InetSocketAddress Class
    • SocketAddress의 Subclass

 

Socket을 통해서 정보를 읽어보자

  • InputStream in = socket.getInputStream();

Socket을 통해서 서버에 써보자

  • OutputStream out = socket.getOutputStream();

 

예시 -> 사전

  • dict라는 TCP protocol에 port 2628로 "DEFINE eng-lat gold" 라고 request를 보내면 server는 gold의 의미를 English-to-latin 사전으로 definition을 보내준다.
package Socket;

import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;

public class DictClient3 {

    public static void main(String[] args){

        String host = "dict.org";
        try{
            Socket soc = new Socket(host,2628);
            OutputStream out = soc.getOutputStream();
            Writer writer = new OutputStreamWriter(out,"UTF-8");
            writer = new BufferedWriter(writer);
            InputStream in = soc.getInputStream();
            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(in,"UTF-8"));
            String request = "DEFINE fd-eng-lat gold";
            writer.write(request);
            writer.flush();
            soc.shutdownOutput();

            for(String line = reader.readLine();line!=null;line=reader.readLine()){
                System.out.println(line);
            }
            soc.close();
        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

 

 

Socket에 대한 정보 알아오기

Closed or Connected

  • isClosed() 함수는 socket이 닫혀있으면 true를 리턴하고, open되어 있으면 false를 리턴한다.
  • isConnected() 함수는 한번이라도 remote host와 연결되었다면 true를 리턴한다.
  • 만약 socket이 한번도 연결된 적이 없다면 isClosed() 함수는 open되어있지 않더라도 false를 return하게 된다. 
  • 따라서 socket connection이 제대로 open되어있는지 확인하려면 아래와 같이 확인해야 한다.
    • socket.isConnected() && !socket.isClosed()
728x90
반응형

'백엔드 > Network Programming' 카테고리의 다른 글

Non-blocking I/O in Java  (0) 2022.12.12
Socket Programming(3) - Socket for Server  (0) 2022.11.21
Socket Programming(1) - socket이란?  (0) 2022.11.13
URL and URI's key  (2) 2022.10.15
Internet protocols and layers  (2) 2022.09.09
728x90
반응형

 

Socket이란?

소켓을 들으면 일반적으로 전구의 소켓을 떠올릴 것이다. 그리고 컴퓨터에서 말하는 소켓은 전구의 소켓과 비슷하게 연결하는 통로라고 생각하면 된다. 사용자 즉, host가 2명이 있다고 생각해보자. Host가 서로 데이터를 주고 받는다고 생각해보자. 각각의 데이터는 단계별로 통과하여 데이터를 전달하게 되는데, 이 단계는 5가지가 있다. Application, Transport, Network, Link, Physical layer이다. 여기서 Application은 순수 software라고 생각하면 되고, Transport부터 Physical layer까지는 OS에 구현이 되어 있다. (Link layer와 Physical Layer는 NIC에도 있다.)

데이터 통신을 위해서는 먼저, 송신자의 Application에서 Socket이라는 문을 통하여 아래 layer들로 전달되고 수신자도 아래에서부터 데이터가 올라오고, Socket 문을 거쳐서 Application에 데이터가 도달하게 된다. 프로세스가 데이터를 보내거나 받기 위해서는 반드시 소켓을 열어 소켓에 데이터를 쓰거나 읽어야 한다. 

Multiplexing / demultiplexing

Multiplexing과 demultiplexing은 transport layer에서 일어난다. 서로 반대되는 개념인데, multiplexing이 여러 데이터를 한 통로에 넣어서 섞어버리는 것이라면 demultiplexing은 한 통로에서 온 것을 여러 갈래 중 해당하는 곳으로 보내는 것을 의미한다.
우리가 인터넷 호스트에서 demultiplexing이라고 한다면 packet들이 도착했을때, packet들이 어떤 process로 가야되는지 보내는 것을 demultiplexing이라고 한다. Sender에서 multiplexing은 여러 개의 socket에서 오는 data를 handling하는 것을 의미한다. 즉, process마다 socket이 하나 있다고 생각하면 된다. physical layer에서 link, network layer까지는 같이 오다가 transport layer에서 어떤 socket으로 가는지 결정해준다.

어떻게 demultiplexing이 작동할까

 Host는 IP layer(Network Layer)에서는 datagram을 전달받는다. 각각의 datagram은 source와 destination IP address를 가지고 있다. 각 datagram은 하나의 segment를 들고온다. 각 segment는 source와 destination의 port number를 가지고 있다. 그럼 host는 port number와 IP 주소를 이용해서 segment를 적절한 소켓에 데이터를 올려보내는 것이다.

TCP socket은 4가지 정보로 identify된다. Source의 IP주소, Soure의 port number, 목적지의 IP 주소, 목적지의 port number이다. 그럼 서버는 동시에 여러개의 TCP socket을 지원해야 된다. 각각의 socket은 각기 다른 socket으로 연결되는 것이다. socket은 port number에 binding되어야 하고, socket에 port number가 할당되어야만 socket의 기능을 할 수 있다. 위에서 볼 수 있듯이 16bit를 socket number로 사용할 수 있다. 이 중에서 0~1023은 잘 알려진 port로 임의로 사용할 수 없고(ex. 웹 서버:80포트) 임의로 사용할 수 있는 것은 49152~65535 번들이다. 

 

하나의 프로세스는 같은 프로토콜, 같은 IP 주소, 같은 port number를 가지는 소켓을 여러 개 만들 수 있기 때문에, 하나의 프로세스는 하나의 port만으로도 여러 호스트에 있는 프로세스의 요청을 처리할 수 있다. (게임 서버에서 동시 접속자 수가 엄청나게 많을 수 있는 이유도 동일하다) 그래서 서버의 경우는 보통 하나의 포트만 할당받고, 하나의 포트로 여러 개의 소켓을 열게된다. 

 

예시

 

 

위의 그림에서 모두 destination IP 주소는 B이고 port number는 80이다. 여기서 demultiplexing되어 다른 socket으로 들어간다.

 

Port number는 네트워크 상에서 통신하기 위해서 호스트 내부적으로 프로세스가 할당 받아야하는 고유한 숫자이다. 같은 Host 내에서 서로 다른 프로세스가 같은 Port number를 가질 수는 없다. 

728x90
반응형

'백엔드 > Network Programming' 카테고리의 다른 글

Non-blocking I/O in Java  (0) 2022.12.12
Socket Programming(3) - Socket for Server  (0) 2022.11.21
Socket Programming(2) - Socket for Client  (0) 2022.11.13
URL and URI's key  (2) 2022.10.15
Internet protocols and layers  (2) 2022.09.09
728x90
반응형

static이란 ‘고정된’이란 의미를 가지고 있다. Static 키워드를 사용해서 Static 변수와 Static 메소드를 만들 수 있는데 다른 말로 ‘정적 필드’와 ‘정적 메소드’ 라고도 하며, 합쳐서 정적 멤버라고 한다.

static field와 static method는 객체에 소속된 멤버가 아니라, 클래스에 고정된 멤버이다. 이 의미는 클래스 로더가 클래스를 로딩해서 메소드 메모리 영역에 적재할 때, 클래스 별로 관리된다. 따라서 클래스의 로딩이 끝나는 즉시 바로 사용할 수 있다.

Static member 선언

객체(인스턴스)로 생성할 것인지, static으로 생성할 것인지의 결정 기준은 공용으로 사용할 것이냐 아니냐로 결정하면 된다. 그냥 생성하면 java에서는 객체로 생성된다. static으로 생성하려면 static 키워드를 추가적으로 붙여서 공용으로 사용할 수 있다.

static field 사용 예시

먼저 Friend 클래스를 만들어 보았다. Friend에서는 static 변수인 numberOfFriends를 두었다. 이렇게 두면, Main에서 Friend의 static field를 어떻게 사용할 수 있는지 확인해보자.

package com.company;

public class Friend {

    String name;
    static int numberOfFriends;
    Friend(String name){
        this.name = name;
    }
}
package com.company;

public class Main {

    public static void main(String[] args) {

        System.out.println(Friend.numberOfFriends);
    }
}

Friend객체를 새로 생성하지 않고서 바로 numberOfFriends를 Friend 클래스에서 호출할 수 있다.

그럼 객체를 만들 때, 친구의 수를 한 명씩 늘리고, 이 변수를 공유할 수 있도록 해보자.

package com.company;

public class Friend {

    String name;
    static int numberOfFriends;
    Friend(String name){
        this.name = name;
        numberOfFriends++;
    }
}

////Main
package com.company;

public class Main {

    public static void main(String[] args) {
        Friend friend1 = new Friend("Jake");
        Friend friend2 = new Friend("Heon");
        System.out.println(Friend.numberOfFriends);
    }
}

이렇게 하면 Friend의 numberOfFriend는 2가 출력되는 것을 확인할 수 있다.

우리가 별 생각없이 쓰던 Math.round()같은 함수도 static 함수이기때문에 사용할 수 있었던 것이다.

(Math 객체를 따로 만들지 않고 바로 Math.round()와 썼었다)

static 멤버의 특성

Static 키워드를 통해 생성된 정적멤버들은 Heap 영역이 아닌 Static 영역에 할당된다. Static 영역에 할당된 메모리는 모든 객체가 공유하여 하나의 멤버를 어디서든지 참조할 수 있는 장점을 가지지만 Garbage Collectior의 관리 영역 밖에 존재하기 때문에 Static영역에 있는 멤버들은 프로그램의 종료될때까지 메모리가 할당된 채로 존재하게 된다. 즉, 너무 남발하게 되면 문제가 생긴다.

  1. 클래스를 설계할 때, 멤버변수 중 모든 인스턴스에 공통적으로 사용해야하는 것에 static을 사용한다. : 객체를 생성하면 각 객체들은 서로 독립적이라서 서로 다른 값을 유지하기 때문에 공통적인 값을 필요로 하는 경우에 static을 붙인다.
  2. static이 붙은 멤버변수는 인스턴스를 생성하지 않아도 사용할 수 있다. : static이 붙은 멤버 변수는 클래스가 메모리에 올라갈 때 이미 자동적으로 static 영역에 생성된다.
  3. static이 붙은 메서드에서는 인스턴스 변수를 사용할 수 없다. : 인스턴스 변수는 인스턴스를 생성해야만 존재하기 때문에 static이 붙은 메서드를 호출할 때 인스턴스가 생성되어있음을 보장할 수 없기 때문에 static이 붙은 메서드에서 인스턴스 변수의 사용을 허용하지 않는다. (반대로 인스턴스 변수나 인스턴스 메서드에서는 static이 붙은 메서드를 사용할 수 있다.)
  4. 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다. : 메서드의 작업내용중에서 인스턴스 변수를 필요로 한다면 static을 붙일 수 없다. 반대로 인스턴스 변수를 필요로 하지 않는다면 가능하면 static을 붙이는 것이 좋다. 메서드 호출시간도 짧아져서 효율이 높아진다. (static을 안붙인 메서드는 실행 시 호출되어야할 메서드를 찾는 과정이 추가적으로 필요하다.)
  5. 인스턴스 변수와 관계없거나, 클래스변수만을 사용하는 메서드들은 클래스메서드(static method)로 정의한다.
728x90
반응형
728x90
반응형

https://www.acmicpc.net/problem/7432

 

7432번: 디스크 트리

갑자기 맥북이 상근이의 손에서 떨어졌고, 화면이 켜지지 않았다. AS센터에 문의해보니 수리비가 97만원이 나왔고, 상근이는 큰 혼란에 빠졌다. 돈도 중요하지만, 상근이는 그 속에 들어있는 파

www.acmicpc.net

[풀이]

2가지 개념 : Trie와 DFS에 대한 개념에 대한 이해가 필요하다.

Trie 개념 : (link 첨부)

 

먼저 Node를 class로 만든다. Node는 key, data, children(자식)을 필드변수로 가지고 있다. 

Trie는 insert와 search함수를 가진다.

insert함수는 parameter로 path를 받는다. 이는 나중에 입력받은 값을 list형태로 넣어주기 위함이다. 

(예 : ['WINNT', 'SYSTEM32', 'CONFIG'] -> 이걸 path로 넣어준다)

여기서 path의 하나하나를 children에 넣어준다. 예를 들어 WINNT는 처음 넣는 것이니까 curr_node.children에 없으므로 curr_node.children['WINNT']에는 Node('WINNT')가 들어가게 된다. 그리고 현재 노드를 WINNT인 노드로 바꾸어 준다. 

 

위의 방법을 Trie의 원리로 구현한 것이다.

남은 것은 dfs를 이용해서 하나씩 출력만 하면 된다. 

사전 순으로 출력을 해야 하므로 sorted(trie.head.children)을 해준다. 이는 제일 첫번째 level 0의 children들이다.

dfe에서는 node.key를 level만큼 띄워서 출력해주고, node의 children을 재귀문을 통하여 출력해준다.

 

 

 

import sys
input = sys.stdin.readline

class Node:
    def __init__(self, key, data=None):
        self.key = key
        self.data = data
        self.children = {}

class Trie:
    def __init__(self):
        self.head = Node(None)

    def insert(self, path):
        curr_node = self.head
        for file in path:
            if file not in curr_node.children:
                curr_node.children[file] = Node(file)
            curr_node = curr_node.children[file]


def dfs_node(node, depth):
    print(' '*depth, node.key, sep='')
    for child in sorted(node.children):
        dfs_node(node.children[child], depth+1)

path_list = []
n = int(input())
trie = Trie()
for _ in range(n):
    trie.insert(input().rstrip().split('\\'))
# print(trie.head.children['WINNT'].children)

for node in sorted(trie.head.children):
    dfs_node(trie.head.children[node], 0)
728x90
반응형
728x90
반응형

URL Class

  • java.net.URL을 사용한다
  • Final Class이므로 상속이 되지 않는다
  • Immutable 하므로 fields는 생성된 이후에 바꿀 수 없다
  • fields에는 protocol, host, path 등이 있다.
  • 생성자가 존재한다. 생성자로 새로운 URL을 만든다
    • public URL(String url) throws MalformedURLException → 지원되지 않는 protocol이나 URL 문법에 맞지 않으면 MalformedURLException에 속한다
    • public URL(String protocol, String host, int port, String file) throws MalformedURLException
  • 생성자는 생성된 URL이 유효한지 안한지 체크하지 않는다. 그래서 URL이 존재하지 않거나 존재하더라도 접속되지 않을 수도 있다.
  • URL syntax가 만족해야 하는 것은 일단 ‘:’ 가 있어야 한다. 세미콜론을 통해 schem이나 protocol을 구분한다. 뒤에 오는 것은 어떤지는 신경쓰지 않는다.

URL로 데이터를 얻는 방법

  • data를 얻는 함수를 알아보겠다
  • public InputStream openStream() throws IOException
    • 제일 많이 사용되고 기본이 된다.
    • Client와 Server의 handshaking도 실행한다
    • 읽어들일 수 있는 data에서 InputStream을 반환한다.
    • InputStream으로 읽는 data는 raw content이다. 즉, ASCII 텍스트 파일은 ASCII로 읽히고, image file은 binary image data로 읽힌다.
    • HTTP header나 protocol 관련 정보는 포함하지 않는다.
    • 한계 : 너무 상위 레벨이라서 생기는 한계가 있다.
      • openStream()은 URL이 text를 가리키고 있다고 가정한다. 그러나 실제로 URL은 image나 sound, video같은 다른 타입도 가리킬 수 있다.
      • text이더라도 server에서의 encoding과 receiver에서의 encoding이 다를 수도 있다.
      • 다른 OS이면 해석이 다를 수도 있다.
      • HTTP header도 encoding 정보가 있을 수 있는데 여기서는 위에 말한대로 HTTP header를 읽을 수 없다.
      • 그래서 openConnection()이 필요하다.
    // 인수로 url 아무거나 넣어서 테스트하면 된다.
    public class SourceViewer {
    
        public static void main(String[] args){
            if(args.length > 0){
                InputStream in = null;
                try{
                    // Open the URL for reading
                    URL u = new URL(args[0]);
                    in = u.openStream();
                    // buffer the input to increase performance
                    in = new BufferedInputStream(in);
                    // chain the InputStream to a Reader
                    Reader r = new InputStreamReader(in);
                    int c;
                    while((c=r.read())!=-1){
                        System.out.print((char)c);
                    }
                }catch (MalformedURLException ex){
                    System.err.println(args[0] + " is not a parseable URL");
                }catch (IOException ex){
                    System.err.println(ex);
                }finally {
                    if(in!=null){
                        try{
                            in.close();
                        }catch (IOException e){}
                    }
                }
            }
        }
    }
    
  • public URLConnection openConnection() throws IOException
    • 반환 객체로부터 InputStream을 얻어야 할 수 있다
    • openStream보다 low level control이다.
    • openStream은 openConnection과 getContent()을 동시에 하는 것이다.
  • public Object getContent() throws IOException
    • 어떤 type으로 data retrieve 할것인지 결정할 수 있다.
      • URL은 ASCII나 HTML file을 의미할 수 있다.
      • URL은 GIF나 JPEG같은 image를 의미할 수 있다. → java.awt.ImageProducer가 return된다.
    • header of data에 있는 Content type field를 본다.
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.*;
    
    public class ContentGetter {
        public static void main(String[] args){
            try{
                URL u = new URL("<https://www.oreilly.com>");
                Object o = u.getContent();
                InputStream r = (InputStream) o;
                int c;
                while((c=r.read())!=-1) System.out.print((char) c);
                r.close();
                System.out.println("I got a "+o.getClass().getName());
            }catch (MalformedURLException ex){
                System.err.println(args[0] +" is not a parseable URL");
            }catch (IOException ex){
                System.err.println();
            }
        }
    }
    
  • public Object getContent(Class[] classes) throws IOException
    • Class에 제공한 순서대로 object를 가져오라는 뜻이다.
    • 만약 제공되지 않는 type이면 null을 return한다.

URL을 쪼개어 보자

  • URL의 요소들
  • Getter 함수들
    • public String getProtocol()
    • public String getHost()
    • public int getPort() → port가 명시되어 있지 않으면 -1을 리턴한다.
    • public int getDefaultPort()
    • public String getFile()
      • 첫번째 ‘/’에서 ‘#’까지를 string 형태로 return한다.
    • public String getPath()
      • query를 포함하지 않은 path만 리턴한다.
    • public String getRef()
      • fragment identifier part를 return한다. fragment identifier가 없으면 null을 리턴한다.
    • public String getQuery()
    • public String getUserInfo()
      • username+password를 리턴한다.
    • public String getAuthority()
      • userInfo + host + port를 리턴한다.

URL의 Equality와 Comparison

  • 언제 2개의 URL이 동일하다고 간주되냐면 같은 resource가 같은 host, port, path에 같은 fragment identifier와 query string이 같으면 동일하다고 한다.
  • equals() : 완전히 동일해야 한다
  • sameFile() : equals()와 같지만 fragment identifier는 고려하지 않는다.

URI Class

  • URI 문법
    • scheme : scheme-specific-part:fragment
  • URI Class 와 URL Class 의 비교
    • URI는 resource의 순수하고 identification이기 때문에 data를 얻을 함수는 없다.
    • RFC에 대해 조금 더 철저하게 다룬다
    • URI class는 protocol이 상관이 없다.
  • Methods
    • public String getScheme()
    • public String getSchemeSpecificPart()
    • public String getRawSchemeSpecificPart()
    • public String getFragment()
    • public String getRawFragment()
    raw하게 반환한다는 것은 I/O 같은 것을 I%20O 이런식으로 반환한다는 것이다.
    • public boolean isAbsolute() : URI가 scheme이 있으면 true
    • public boolean isOpaque() : URI가 hierarchical하면 false
    • public String toString() : encode되지 않은 string 형태 → I/O
    • public String toASCIIString() : encode된 URI 형태 → I%20O
    예를 들면 space는 %20이나 +로 대체된다.
    • URLEncoder.encode(String s, String encoding)
      • 이 함수는 non-ASCII character들을 모두 encode해버린다
      • 문제는 모든걸 encoding해버려서 문제가 생길 수 있다.
    • URLDecoder.decode(String s, String encoding)
      • 모든 plus sign을 space로 바꾸고 모든 percent escape를 해당하는 character로 바꾼다
    GET method로 통신하기
  • public class DMoz { public static void main(String[] args){ String target = ""; for(int i=0;i<args.length;i++){ target+="args[i]+"" ";="" }="" target="target.trim();" querystring="" query="new" querystring();="" query.add("q",target);="" try{="" url="" u="new" url("<<a="" href="https://search.yahoo.com/search?p=java&fr=yfp-t&fp=1&toggle=1&cop=mss&ei=UTF-8">https://search.yahoo.com/search?p=java&fr=yfp-t&fp=1&toggle=1&cop=mss&ei=UTF-8>"); try(InputStream in = new BufferedInputStream(u.openStream())){ InputStreamReader theHTML = new InputStreamReader(in); int c; while((c=theHTML.read())!=-1){ System.out.print((char)c); } } }catch (MalformedURLException ex){ System.err.println(ex); }catch (IOException ex){ System.err.println(ex); } } } </args.length;i++){>
  • encode form으로 반환한다는 뜻이다.

Password-Protected된 사이트에 접근하기

  • Authenticator Class
    • 추상 클래스이다.
    • methods
      • public static void setDefault(Authenticator a)
      • 만약 URL class가 username과 password를 필요로 한다면 MyAuthenticator를 물어본다.
      • getPasswordAuthentication() 함수를 override 해야한다.
        • password 인증이 필요하면 호출한다.
    • HTTP 인증 과정
      • client가 authentication info가 없는 request를 보낸다
      • server가 401을 보낸다
      • client가 authentication infor가 있는 request를 보낸다
      • server가 200을 보낸다

 

728x90
반응형

+ Recent posts