수업/Network Programming

[Network Programming] Network Socket Programming 개요/기초

hw-ani 2023. 5. 25. 23:22

 

이 과목에선 Socket을 통해 Application Layer의 프로그램을 개발하는 것을 중점으로 한다.

OS에서 제공해주는 네트워크 관련 API(Application Programming Interface)를 활용하는 것이 주된 목표이다. Client-Server model을 주로 다루며, kernel level이 아닌 user-level programming을 한다.

Socket을 생성해서 사용하면 Application 아래 Layer의 내용은 감춰진다. 즉, 응용 프로그래머는 이 Socket을 기반으로 Application 계층의 완성에 집중하게 된다.

 

 

Socket API 종류 예시. SOCK_RAW는 ping 같은 프로그램에서 사용한다.

 

 

 

Client-Server model 1 : Iterative Server (with UDP)

 

 

 

Client-Server model 2 : Concurrent Server (with TCP)

process 하나당 client 하나씩 맡아서 동시에 처리한다.

 

 


Network Programming(Socket Programming)이란?

Socket을 기반으로 Network로 연결된 둘 이상의 컴퓨터 사이에서의 데이터 송수신 프로그램을 작성하는 것을 말한다.

 

Socket이란?

OS가 제공하는 SW적 장치로 이를 이용해 데이터 송수신을 할 수 있다. Socket API를 활용하면 데이터 송수신에 대한 물리적, 소프트웨어적 세부사항을 신경쓰지 않고 프로그램을 작성할 수 있다. 그 아래 과정은 OS에서 처리해주므로..

 

Linux에선 Socket API 함수로 socket, bind, listen, accept, connect 등의 함수를 제공한다.(OS마다 함수 이름, 역할, 구현방식 등은 다르다.)

 

 

> Linux 기반 File I/O

Linux에선 socket을 file로 취급한다. 따라서 socket을 다루기 위해선 Linux의 저수준 file I/O API를 알아둘 필요가 있다.

이 함수들은 C standard 함수가 아니므로 Linux OS에서만 사용할 수 있다.

 

File Descriptor

: (특정 process에서 접근중인) file을 구분하기위해 OS가 각 file에 부여한 숫자이다. 예를들어 process가 생성되면 자동으로 standard input, standard output, standard error이 해당 process와 연결되고(열리고), 각각 file descriptor로 0, 1, 2가 할당된다.

저수준 file I/O 함수는 작업 대상을 구분하기위해 이 file descriptor를 argument로 요구한다. socket도 file로 취급되므로, 이 file descriptor 값을 가진다.

 

 

open

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char* path, int flag);

성공 시 file descriptor, 실패 시 -1 반환

 

flag 위치에 올 수 있는 macro variable은 다음과 같다.

 

 

 

close

#include <unistd.h>

int close(int fd);

성공 시 0, 실패 시 -1 반환

 

 

write

#include <unistd.h>

ssize_t write(int fd, const void * buf, size_t nbytes);

성공 시 전달한 bytes 수, 실패 시 -1 반환

 

 

read

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t nbytes);

성공 시 수신한 bytse 수(파일 끝을 만나면 0), 실패 시 -1 반환

 

 

Q. 왜 open과 close는 다른 header file에 선언돼있을까?
A. 아래 링크랑 GPT 등 참고해서 알아보니 open은 파일 제어 작업을 하는 함수로 보고 관련 기능이 모여있는 fcntl.h에 포함돼있었고, close는 그냥 일반적인 system call 함수로 보고 unistd.h에 포함돼있었는데, 이 관습이 그냥 쭉 이어져와서 그런 것 같다.

https://stackoverflow.com/questions/22359359/why-is-open-declared-in-fcntl-h-while-close-is-declared-in-unistd-h

 


마지막엔 과정이 머릿속에 있으면 된다. 전형적인 Concurrent Server의 Socket APIs 호출 순서이다.

 

 

 

 

 


< 의문/궁금 정리 >

 

Q1. Linux에서 Socket은 File로 취급된다고 하는데, 그럼 Socket 생성하면 File처럼 Disk에 저장되고 Linux File System에 의해 관리되는건가?

A1. "모든 것이 File이다. (Everything is a file)" 이라는 Unix-like OS의 철학때문에 Socket이 File로 취급되는 것이다. 이 의미가 꼭 Socket이 File과 같다는 뜻은 아니다. 이는 모두 File로 취급하여 File descriptor로 접근/조작할 수 있고, File 관련 system call을 모두에게 적용할 수 있다는 의미이다.(서로 다른 종류의 resource들에 대한 I/O 작업의 일관된 interface를 제공)

Socket은 Disk에 저장되지 않고, 따라서 File system에 의해 관리되지도 않는다. OS kernel에 의해 관리된다. 하지만 Unix-like system에서 모든 resource는 file로 취급되므로, Socket 또한 file descriptor로 접근하여 관련 system call을 사용할 수 있도록 OS에서 그렇게 처리해준 것 뿐이다.

 

Q2. 서로 다른 두 process에서 같은 socket을 사용할 수 있나? 소켓당 포트번호가 bind 돼있는데 말이 되나? 포트번호는 프로세스를 구분하기 위함인데, 같은 소켓을 여러 process가 사용해도 되나?

A1. 맞다. 보통 PORT number로 process를 구분한다. 하지만 여러 프로세스가 같은 소켓/포트번호 를 사용하는 것도 가능하다. 서버 아키텍쳐나 네트워크 기술이 발전하며 flexibility와 scalability가 필요하게 되었고, 요즘은 꽤 쓰기도 하나봄. 뭐 어쨌든 기술적으로 불가능한건 아니란 것만 알고, 나중에 그렇게 할 일이 있거나 더 궁금하면 더 찾아보자.

일단 관련 질문 글 링크(Can two applications listen to the same port?)