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
반응형

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
반응형

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
반응형
728x90
반응형

Internet인터넷과 프로토콜

: 인터넷은 전 세계에 걸쳐 파일 전송 등의 데이터 통신 서비스를 받을 수 있는 컴퓨터 네트워크 시스템을 의미한다. 그래서 만약 우리가 ‘인터넷을 사용한다’ 라고 말하는 것은 사업자가 만들어 놓은 네트워크 인프라를 사용하는 것이다. (여기서 사업자는 SK,KT 회사들을 의미한다.)

인터넷 망을 통해 데이터를 디지털 신호로 바꾸어 전달하고, 받은 디지털 신호를 데이터로 다시 바꾸면서 네트워크 통신을 하는 것이다. 이 때, 네트워크 통신을 위한 규칙, 즉 공통된 메뉴얼을 프로토콜이라고 한다.

network edge

network edge는 hosts들로 구성된다. hosts들은 사용자 또는 서버를 포함하고 기본적으로 단말들을 의미한다. server는 data center이다. 우리가 브라우저에 접속한다고 생각하면 서버에 데이터를 요청해서 데이터를 받아온다. 이렇게 끝단에 있는 것들을 network edge들이라고 생각하면 된다. 이 사이사이를 link들이 이어주는데, 이제 어떻게 보낼것인지 어디로 보낼것인지 이런것들을 처리해주는 부분이 network core부분이다.

network core

data를 보낼 때, data자체는 크기가 크니까 잘게 쪼개서 보낸다. 이 때 잘게 쪼갠 조각 하나하나를 패킷(packet)이라고 한다. 이 패킷들을 어떻게 전달할 것인지가 문제이다. network core들은 ISP쪽을 의미하고 core에 edge들이 달려있는것이다. ISP도 서로서로 연결이 되어있다. 즉, network core들은 router들의 interconnection이다.

network core의 2가지 key function은 무엇일까?

  1. Forwarding(switching) : local action이다. 라우터에서 패킷을 받았는데, 패킷에는 목적지 주소가 써져 있다. 이 목적지로 가는 패킷은 몇 번 링크로 forwarding을 해야 하는지 forwarding table을 가지고 있다. 그래서 궁극적으로 패킷이 목적지에 도달할 수 있도록 하는 것이 forwarding이다.
  2. Routing : routing은 global action이다. source에서 destination까지 어떤 경로를 취해야 하는지 패킷이 어떤 경로를 따라가야 하는지 체크하는 것이 라우팅이 된다. (라우팅 알고리즘도 여러 가지가 있다.)

packet-switching의 개념이 중요한데, 패킷 하나가 보내지면 store and forward라는 방식을 사용한다. 이 방식은 전체가 받아질때까지 버퍼에 store하고 다 받아진 다음에야 보낸다. 중요한 성능 측정중 하나가 packet transmission delay이다. host가 data packet을 보내는 경우를 생각해보자. packet의 길이가 Lbits라고 한고, 전송속도를 R이라고 가정하자. 그럼 packet transmission delay, 즉 L bit packet을 link로 보내는데 걸리는 시간은 L/R이 된다.

그런데 packet switching은 queueing이 발생할 수 밖에 없다. 왜냐하면 link를 공유하게 되는데 전송되어 빼내는 속도보다 들어오는 속도가 빠르면 congestion, 즉 queueing delay가 생긴다.

그럼 잃어버리는 data도 생길것이다. arrival rate > transmission rate일 때, 패킷이 버퍼에 쌓이는데 메모리 용량은 한계가 있다. 그럼 packet drop이 생긴다.

여기서 packet switching과 반대되는 개념인 circuit switching도 있다. end - end resource가 예약이 되는 개념이다. 그러니까 이 link를 독점적으로 사용하는 것이다. traffic이 없다고 해도 항상 비워져 있어야한다. 그래서 telephone network에서 많이 쓴다. 전화하는 중간에 전화해도 통화중이라고 알려주지 같이 통화할 수 있는건 아닌것처럼 말이다.

그럼 packet switching과 circuit switcing을 비교해보자. 만약에 link로 1Gb/s통과하고 각각의 사용자는 사용하면 100 Mb/s를 사용하고 10%확률로 사용한다고 가정하자. 그럼 circuit switching은 1Gb에서 100Mb를 나눈값이 10명밖에 사용을 못한다. 그런데 packet switching은 35명이 사용한다고 가정할 때 35명이 동시에 사용할 확률이 0.004밖에 안된다. 그래서 여러명이서도 사용할 수 있는 것이다.

 

그럼 packet switching이 무조건 우세일까? 그건 아니다. 성능을 보장해야 하는 경우는 circuit switching을 사용하게 된다.

pacekt switcing은 data loss가 있으므로 reliabel data transfer이나 congestion control이 필요하다.

 

Performance : loss, delay, throughput

인터넷은 기본적으로 packet switching이다. packet switching은 모든 resource를 공유하는 것이라고 위에서 설명하였다.

delay에는 4개의 요소가 있는데, 4가지 요소는 transmission delay, nodal processing delay, queueing delay, propagation delay이다.

nodal processing delay는 packet이 도착했을 때, packet에 bit error가 있는지 없는지 확인하고 output link를 결정하는 과정이다. nodal processing delay는 보통 microsec로 굉장히 짧다. 그래서 보통 하드웨어에서 구현이 되어 있다.

queuing delay : transmission 받으려고 기다리는 delay이다. router의 congestion level에 따라서 변화가 굉장히 심하게 있을 수 있다. 어떤 경우에는 queueing delay가 0이었다가 어떤 경우에는 굉장히 컸다가 굉장히 dynamic한 상황이다.( nodal processing delay같은 경우는 거의 변화가 없다. ) Queueing delay는 변화가 있기 때문에 여러가지 요소가 있다.

transmission delay : packet을 링크에 밀어넣는 속도이고, packet length가 Lbits이고, transmission rate이 R bps다 라고 하면 L/R초가 걸리게 되는 것이다.

propagation delay : bit는 전기신호인데 001 이런식으로 보내는데 전자기파, 빛의 속도 20만킬로미터 퍼 second가 되는데 physical link가 d미터였다고 하면 d/s가 걸리는 것이다. link가 아주 길지 아니면 굉장히 delay가 짧다.

이것들이 다 합쳐서 Packet delay가 된다.

 

packet arrival rate이 a라고 해보자. packet per second. packet length는 bits이다. a packet per second인데 하나의 packet이 Lbits니까 arrival rate이 aL bps가 된다. R은 transmission rate이다.

 

La/R → traffic intensity

그럼 여기서 의문이 생긴다. traffic intensity가 1보다 작다는 것은 queueing delay가 발생안한다는 뜻이 아닐까?

아니다. 여기서 arrival rate는 평균을 의미하기 때문에 이 경우에도 queueing delay가 발생할 수 있다.

 

Packet loss

congestion이 발생할때 버퍼링이 될 수 있는데 버퍼가 꽉찬 상태에서 추가로 들어오면은 loss가 발생한다. loss packet이 발생하면 재전송 mechanism이 있다. 그리고 throughput은 얼마나 통과했느냐 얼마나 data들이 통과했는냐를 나타내는것이 throughput이 된다. sender에서 receiver까지 bit가 전송되는 속도. instantaneous는 어떤 시점에서의 속도를 나타내는 것이다.

average는 긴 시간 간격이고 그 시간안에 전송된것.

Rs가 Rc보다 작은 상황이라고 해보자. Rs속도가 안나오면 Rc가 아무리 높아도 사용안된다.

bottleneck problem. → 그럼 end to end 는 최대 Rs가 된다. (병목현상이라고 부른다.)

즉, 여러 곳에서 들어올 때 최소값이 end-end throughput이 되는 것이다.

 

TCP / IP 계층

Application Layer : 특정 서비스를 제공하기 위해 애플리케이션끼리 정보를 주고받을 수 있게 해준다. ( FTP, HTTP, SSH, Telnet, DNS, SMTP)

—> ex> 브라우저와 웹서버가 HTTP요청, 응답을 통해 통신하는 것

Transport Layer : 송신된 데이터를 수신측 애플리케이션에 확실하게 전달해 준다. 네트워크 통신을 하는 애플리케이션은 포트 번호를 사용하게 된다. Transport Layer는 port 번호를 사용해서 애플리케이션을 찾아주는 역할을 한다. TCP, UDP와 같은 프로토콜이 사용된다.

Internet Layer : 수신측까지 데이터를 전달하기 위해 사용된다. 송신측, 수신측 모두 IP 주소를 가지고 있다. IP주소를 바탕으로 정확한 목적지를 찾아갈 수 있게 해준다. IP, ARP같은 프로토콜이 사용된다.

Network Access Layer : 네트워크에 직접 연결된 기기 간의 데이터 전송을 도와준다. 여기서는 물리적 주소인 MAC주소를 사용한다. Ethernet, PPP, Token Ring과 같은 프로토콜을 사용한다.

 

그럼 우리가 www.google.com을 웹브라우저에 입력하면 무슨 일이 일어날까?

먼저 www.google.com을을 입력하면 google서버의 80포트로 HTTP Request를 보내는 것을 의미한다. 해당 요청을 인터넷을 통해 구글서버로 전달하기 위해 우리는 패킷을 만들어야 한다. 패킷에는 각 계층에 필요한 정보들이 담겨야 한다.

( 계층별로 HTTP, TCP, IP, Ethernet 프로토콜을 사용한다고 생각하자.)

 

Application Layer에는 Http Request가 들어간다.

Transport Layer에는 SP, DP. SP는 시작포트, DP는 도착포트. 시작포트번호는 내 컴퓨터에서 만든 소켓의 포트 번호라서 당연히 컴퓨터는 알고 있을 것이다. 목적지 포트 번호 또한 80으로 알고 있다.

(80은 웹서버의 well known 포트 번호이다)

 

IP header에는 SA와 DA. 시작 IP주소, 도착 IP주소. 시작 IP주소는 알고 있겠지만,(내pc니까) 목적지 ip주소는 모른다. www.google.com이라는 도메인 주소만 알고 있기때문에 DNS 프로토콜을 사용해서 IP주소를 알 수 있다.

브라우저는 OS에게 도메인에 대한 IP주소를 알고 싶다고 요청한다. 그럼 OS에서 DNS서버로 요청을 보내게 된다. 그럼 OS가 DNS 서버를 어떻게 알고 있을까? DNS서버 주소는 이미 컴퓨터에 등록이 되어 있다. 

 

DNS또한 HTTP와 같은 애플리케이션 계층 프로토콜이다. 53번 포트를 사용한다. DNS도 HTTP Request와 비슷하게 도메인이 담긴 쿼리를 도메인 서버로 보낸다. 그럼 도메인 서버가 IP주소를 응답 해준다.

DNS는 Transport Layer에서 UDP라는 프로토콜을 사용한다. UDP는 TCP와는 다르게 헤더가 간단하다. 포트번호말고 다른게 없다. 그 이유는 UDP가 비연결지향형 프로토콜이기 때문이다.

 

Ethernet 프로토콜에 대한 헤더를 알아야하는데 아직 MAC주소를 모른다. MAC주소는 어떻게 알아와야할까? 이전까지는 목표인 구글 서버에 대한 정보가 필요했다. 그럼 MAC주소도 우리의 목적지인 구글 웹서버의 MAC주소가 필요할까? 아니다. 여기서필요한  MAC주소는 구글의 MAC주소 대신 물리적으로 연결된 우리집 공유기의 MAC주소가 필요하다. 이 공유기를 통해 다른 네트워크와 연결이 가능하니까 게이트웨이라고 부르기도 한다. 게이트웨이의 IP는 이미 알고 있다. ( netstat -rn 명령어를 통해 알 수 있음)

 

그럼 어떻게 IP주소로 MAC주소를 알 수 있을까? IP주소로 MAC주소를 알아내기 위해서 ARP 프로토콜을 사용한다. ARP 프로토콜을 IP주소를 MAC주소로 바꾸어주는 주소해석 프로토콜이다.

 

TCP 프로토콜은 데이터를 송신하기 전에 송신측과 수신측이 서로 연결되는 작업이 필요하다. 이러한 작업을 3 Way Handshaking이라고 부른다.

3way handshaking을 수행하기 위해서는 TCP header에 표시한 플래그들이 사용된다. 이러한 플래그들을 컨트롤 비트라고 부른다. SYN과 ACK 플래그가 사용된다.

클라이언트는 서버에게 접속을 요청하는 SYN 패킷을 보낸다. 서버는 SYN 요청을 받고, 클라이언트에게 요청을 수락한다는 ACK와 SYN플래그가 설정된 패킷을 보낸다.

클라이언트는 서버에게 다시 ACK를 보낸다. 이제부터 연결이 이루어지고 데이터가 오가게 된다. 이런 3가지 과정을 3way handshaking이라고 한다. 

 

내가 사용하는 컴퓨터는 Private IP를 사용하고 있다. Private IP는 외부의 네트워크 환경에서 IP주소를 찾지 못한다. 그래서 공유기를 통해 나갈 때 public IP로 주소를 변환하여 나가는 작업이 필요하다.

이러한 작업을 NAT (Network Address Translation)이라고 한다.

우리집 공유기를 거치고 나서 구글 서버에 도착하기 위해서는 여러 라우터를 거쳐야 한다. 라우터는 네트워크와 네트워크를 연결해주는 역할을 한다. 라우터가 목적이 경로를 찾아 나가는 과정을 라우팅이라고 한다. 라우팅을 거쳐 구글 서버가 연결된 라우터까지 데이터가 도착을 하면, 패킷의 IP헤더에 기록된 구글 서버 IP주소를 통해 MAC주소를 얻어와야 한다. 이때 이전에 설명했던 ARP프로토콜을 사용한다.

이때 ARP는 라우터가 연결된 네트워크에 브로드캐스팅된다. 목적지 구글서버가 자신의 IP로 온 ARP 요청을 받고 MAC주소를 응답해준다. 이제 목적지 구글서버의 MAC주소를 알았으니 데이터가 물리적으로 전달될 수 있다. ARP로 IP주소를 통해 MAC주소를 얻고, 드디어 목적지 구글 서버에 데이터가 도착한다.

그럼 구글 서버에서 HTTP Request를 받고 응답을 돌려보낸다. '/'에 매핑된 GET요청을 처리해서 적절한 HTML을 응답해준다. 그리고, HTTP 요청과 응답과정이 끝나면 연결을 종료해야 한다. 여기서도 TCP 컨트롤 비트가 사용된다. 이 단계에서는 ACK, FIN플래그가 사용된다.

클라이언트가 서버로 연결을 종료하겠다는 FIN 플래그를 전송한다. 서버는 클라이언트에게 ACK 메시지를 보내고 자신의 통신이 끝날 때까지 기다린다. 서버가 통신이 끝나면 클라이언트로 FIN을 보낸다. 클라이언트는 확인했다는 의미로 서버에게 ACK를 보낸다. 그럼 연결종료가 완료된다. 총 4단계이고 이걸 4way handshaking이라고 한다.

여기서 서버가 FIN을 보내는 과정에서 한가지 문제가 발생할 수 있다. 서버가 FIN을 보내기 전에 보냈던 데이터가 FIN 보다 늦게 도착할 경우이다. 서버로부터 FIN을 수신했다고 클라이언트가 바로 연결된 소켓을 닫아버리면 FIN을 보내기 전에 보낸 패킷은 영영 클라이언트가 받을 수 없게 된다. 그래서 클라이언트는 서버로부터 FIN요청을 받더라도 일정시간동안 소켓을 닫지 않고, 혹시나 아직 도착하지 않은 잉여 패킷을 기다린다. 이렇게 4way handshaking이 완료되어도, 소켓을 닫지않고 잉여패킷을 기다리는 상태를 TIME_WAIT이라고 한다.

 

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
Socket Programming(1) - socket이란?  (0) 2022.11.13
URL and URI's key  (2) 2022.10.15

+ Recent posts