Computer Science/Network

application layer

Prower 2022. 12. 22. 17:53
728x90
반응형

1. application layer

  • 실제 컴퓨터에서 작동하는 프로세스가 속한 계층
  • 네트워크는 다른 컴퓨터의 프로세스간 통신
  • 클라이언트 - 서버의 프로세스간 통신
    • socket: 통신을 위한 interface. 프로세스가 OS에 네트워크 통신을 요청할 때 사용하는 interface
    • IP: 네트워크상 host 연결을 위한 주소. host를 식별하는데 사용
    • port: 프로세스의 socket 연결을 위한 주소. host의 프로세스를 식별하는데 사용

socket

  • 프로세스는 소켓을 통해 통신한다.
  • application layer에서 transport layer에서 제공하는 소켓에 의존한다.
  • 소켓은 process에서 전달하는, process로 전달되는 데이터 제어

transport layer에 대한 요구

application layer는 transport layer에서 제공하는 기능, 서비스를 사용함
제공하는 기능에 대한 요구는 다음과 같을 수 있으나 실제로 application layer는 데이터 안정성만 제공한다.

  • 데이터 안정성: 데이터가 유실되지 않고 목적지에 도달함 -> TCP가 제공
  • 시간 제약 -> 제공 X
  • 스루풋 -> 제공 X
  • 보안 -> 제공 X

2. client - server 구조

server

  • 고정된 IP와 port를 가진다.
    • 고정된 포트를 사용 이유(e.g http는 80번 사용)
      • 일종의 약속이나, 일정한 IP를 유지하는 이유와 같음
      • 서버 프로세스의 포트가 변경되면 클라이언트가 서버의 프로세스를 찾아갈 수 없다.
  • host의 요청을 기다림

client

  • 서버와 통신
  • 변경이 가능한 IP, port를 사용

3. HyperText Transfer Protocol

  • hypertext를 전달하는 프로토콜
  • 클라이언트가 요청하고자 하는 url로 리소스를 요청
  • 웹 서비스가 http 위에서 동작하는 구조
  • client: send HTTP request
  • server: send HTTP response

transport layer

  • TCP를 사용하기 때문에 request, response 이전에 TCP connection 필요

연결 단계

  1. 서버가 TCP 소켓 개방
  2. 클라이언트가 TCP 연결 요청
  3. 서버가 클라이언트의 TCP 연결 요청 accept
  4. HTTP 메세지 전송
  5. TCP 연결 close

stateless

  • 서버에서 client의 상태를 기록하지 않음

persistent vs non-persistent

  • HTTP 통신은 한번의 TCP 연결에 하나의 object(hypertext, jpg...)를 전송
  • 여러 object를 받기 위해서 여러번의 TCP 연결이 필요하며 이는 비효율적
  • persistent: 한번의 TCP 연결로 여러 객체를 전달하는 방식
  • non-persistent: 한번의 TCP 연결 마다 하나의 object 전송
    • 동작 방식
      1. try TCP connection
      2. http request, response
      3. close TCP connection
      4. client parses hypertext
      5. need more hypertext
      6. start from 1. ...
    • 그러나 이는 비효율적이므로 HTTP/1.1 에서는 pipelining 방식을 통해 response를 기다리지 않고 여러개의 request를 보내고 many response를 받는 방식으로 작동한다.

response time

  • RTT: 클라이언트에서 전송된 패킷이 서버에 도달하여 다시 돌아오기 까지의 시간

non-persistent 연결 구조

(non-) persistent 모두 요청을 위한 RTT가 한 번 필요하고, 이후 object를 전달받는데 RTT + file transmission time이 소요된다.

  • non-persistent의 경우 n개의 object를 받는데: (2 * RTT + file transmission time) * object 수 가 소요된다.
  • persistent의 경우 한번의 n개의 object를 받는데: RTT + (RTT + file transmission time) * object 수 가 소요된다.

4. socket

  • 네트워크를 위해 OS에서 제공하는 interface
  • application layer는 transport layer에서 제공하는 interface 사용
  • 어플리케이션은 네트워크 통신을 위해
    • TCP, UDP에 맞는 소켓을 생성
    • 소켓을 통해 데이터를 전송하고 받는다
  • 종류: TCP(SOCK_STREAM), UDP(SOCK_DGRAM) 소켓

API

동작 구조

  • 연결 준비
    • server
      • socket(): 소켓 생성
        • domain(IP), type(TCP, UDP), protocol을 인자로 받음
        • 생성된 소켓 번호(file descriptor) 반환
      • bind(): 소켓을 특정 port에 바인딩
        • socket()에서 생성된 file descriptor, 서버의 IP/port, 주소 길이를 인자로 받음
      • listen(): 클라이언트의 요청을 대기
        • file descriptor, backlog(connection queue 길이)를 인자로 받음
      • accept(): 연결을 받을 준비 완료
        • file descriptor, 요청으로 들어온 클라이언트의 IP/port, 주소 길이를 인자로 받음
        • 클라이언트의 연결이 들어올 때 까지 blocking
    • client
      • connect(): 서버에 연결
        • 클라이언트의 소켓 번호, 서버의 IP/port, 주소 길이를 인자로 받음
  • 데이터 전달
    • read(), write(): 연결 이후 데이터를 주고 받기 위한 API
  • 연결 종료
    • close(): 연결이 끝난 뒤 소켓을 닫고, 점유했던 port를 반납한다.

예시 코드

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
void cleanExit(){exit(0);}
​
#define PORT 7777
#define BACKLOG 10
​
int main(void) {
    signal(SIGTERM, cleanExit);
    signal(SIGINT, cleanExit);
​
    int sockfd, new_fd;
    struct sockaddr_in source_ip;
    struct sockaddr_in dest_ip;
    int sin_size;
​
    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }
​
    source_ip.sin_family = AF_INET;
    source_ip.sin_port = htons(PORT);
    source_ip.sin_addr.s_addr = htonl(INADDR_ANY);
​
    if (bind(sockfd, (struct sockaddr *) &source_ip, sizeof(struct sockaddr)) == -1) {
        perror("bind");
        exit(1);
    }
​
    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }
​
    while(1) {
        sin_size = sizeof(struct sockaddr_in);
​
        if ((new_fd = accept(sockfd, (struct sockaddr*) &dest_ip, (socklen_t*)&sin_size)) == -1) {
            perror("accept");
            continue;
        }
​
        printf("server: got conection from %s\n", inet_ntoa(dest_ip.sin_addr));
​
        char result[] = "hello world\n";
        write(new_fd, result, sizeof(result));
        close(new_fd);
    }
}
​

해당 서버를 실행하고 netcat을 통해 localhost:9898(IP:port) 로 요청하면 리턴값을 받을 수 있다.

반환

> nc localhost 9898
> hello world
728x90
반응형