Post

소켓 프로그래밍 2

서버 - 클라이언트

소켓 프로그래밍 2

서버 클라이언트

소켓만을 활용해 채팅을 구현하기 위해서는 누군가는 서버의 역할을 누군가는 클라이언트의 역할을 수행해야한다. 소켓 함수의 관점에서 바라보면 accept()를 호출하고, 누군가의 connect 요청을 기다리는 쪽이 서버가 되는것이고, connect 요청을 하는쪽이 클라이언트가 된다.

서버

  • 클라이언트의 요청에 따라 다양한 서비스를 제공한다.
  • 항상 실행 상태에 있고 클라이언트의 서비스 요청을 기다린다.

클라이언트

  • 서버로 서비스 사용에 관한 요청을 보내고 응답을 받는다.

소켓 프로그래밍에서의 서버-클라이언트

서버

  • accept를 호출하고 클라이언트의 요청을 기다린다.
  • accept함수의 결과로 connect요청을 한 클라이언트를 위한 전용의 소켓 기술자(socket descriptor)가 생성된다. Server-Socket

클라이언트

  • connect 함수를 호출해 서버에게 연결을 요청한다.
  • 자신이 생성한 소켓 기술자를 통해 서버와 통신(메시지를 주고 받기)을 수행한다.

반복 서버와 동시 동작 서버

반복 서버

  • 접속 처리(accept)와 서비스 제공(send/recv)을 하나의 프로세스가 담당 - fork를 뜨지 않는 서버
  • 클라이언트를 순차적으로, 반복적으로 처리
  • 서버 프로세스가 직접 모든 클라이언트의 요청을 차례대로 처리(순차적으로 직접 처리)
  • 하나의 프로세스가 순차적으로 클라이언트를 처리함으로 응답 시간이 길어진다.

동시 동작 서버

  • 접속 처리(accept) 프로세스와 서비스 제공(send/recv)프로세스를 분리
  • 서비스를 제공하는 별도의 프로세스를 생성(fork)하여 클라이언트와 연결 수행
    • 부모 프로세스 : 클라이언트와의 접속을 처리
    • 자식 프로세스 : 클라이언트에게 서비스를 제공 (send/recv) - 클라이언트와의 통신을 담당
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      
      //server.c
      while((new_sd = accept(sd, (struct sockaddr *) & client, & client_len)) != -1){
        if(fork() == 0){
          // 자식 프로세스 : 별도의 프로세스를 생성하여 서비스 제공
          close(sd); // 접속을 처리하기 위한 소켓 기술자는 필요 x
          work(new_sd); // new_sd를 통해 클라이언트와 통신
          close(new_sd);
          exit(0);
        }
            
        // 부모 프로세스 : 클라이언트의 접속 처리
        close(new_sd);
      }
      
  • 병렬적으로 서비스를 제공함으로써 응답시간을 단축시킬 수 있다.
  • fork()로 인해(부모 프로세스의 메모리 구조를 그대로 복사) 리소스 사용량(메모리 사용량)이 늘어난다.
    • [검수必] 스레드를 활용하면 메모리 사용량을 줄일 수 있지만 race condition으로 인해 로직이 복잡해질 수 있다.
This post is licensed under CC BY 4.0 by the author.