프로그램들은 Ubuntu 20.04 LTS 버전에서 POSIX API에서 제공하는 함수들을 기반으로 C 코드로 작성하였다.
소켓 생성 단계 (socket(), bind())
서버는 클라이언트가 연결할 수 있도록 서버 소켓을 만들어 주어야 한다. 서버 소켓을 만들기 위해서는 서버가 열릴 IP 주소 (자기 자신의 IP 주소)와 포트 번호, IP 주소 종류 (IPv4 혹은 IPv6. IPv4를 보편적으로 사용한다.)가 필요하다. 클라이언트 소켓에서는 연결하려는 서버의 IP 주소, 포트 번호, IP 주소 종류가 필요하다.
socket() 함수는 연결 및 데이터 송수신을 위한 매개체인 소켓을 생성하는 함수이다. 클라이언트는 이 함수만 호출하고 다음 단계로 넘어가지만, 서버는 이에 추가적으로 bind() 함수를 호출해 주어야 한다.
bind() 함수는 서버 측 소켓에 서버에 대한 정보 3가지 (IP 주소, 포트 번호, IP 주소 종류)를 주입하는 함수다. bind() 함수를 호출함으로써 서버를 열 수 있고, 클라이언트는 서버 소켓에 주입된 정보를 통해 연결할 수 있다.
연결 시도 단계 (listen(), connect())
서버 측: listen() 함수는 서버 측에서 호출하는 함수로, bind() 함수로 소켓에 정보를 주입하면 소켓이 클라이언트와의 연결 대기하는 상태가 된다. 클라이언트가 서버에 연결하면 서버 측에서는 connect() 함수가 호출된다. connect() 함수가 호출되면 서버 내에서는 연결된 클라이언트와 데이터를 주고받기 위한 새로운 소켓이 생성된다. 이를 connect 소켓이라고 한다. listen() 단계까지 쓰였던 서버 측 소켓은 listen 소켓이라는 별개의 소켓이며, listen 소켓의 역할은 단순히 클라이언트와의 연결을 대기하기 위한 소켓인 것이다. 연결 이후 데이터 송수신을 담당하는 소켓은 connect() 함수에서 생성된 connect 소켓이다.
클라이언트 측: 서버 측과 달리, 클라이언트 측은 connect 소켓 하나만 존재한다. 클라이언트에서는 socket() 함수를 호출하여, connect 소켓을 생성한다. 이후 connect() 함수를 서버 측 정보 (IP 주소, 포트 번호, IP 주소 종류)를 인자로 하여 호출함으로써 서버와의 연결을 시도한다. 서버 측에서 listen 소켓을 통해 클라이언트가 연결 시도 중임을 확인하면, connect() 함수를 통해 연결을 승인하고, 연결된 클라이언트와의 데이터 송수신을 담당하는 connect 소켓을 생성한다.
데이터 송수신 단계 (read() (=receive()), write (=send()))
read 함수와 write 함수는 항상 짝지어져 있어야 한다.
즉, 어느 한 쪽이 read 또는 write 함수라면, 반드시 반대 쪽은 write 또는 read 함수여야 한다는 것이다.
read() 함수와 write() 함수는 서버 및 클라이언트 각각의 buffer 변수에 저장된 데이터를 통해 보내거나 받는다. buffer는 주로 동적 할당을 통한 char * 자료형이 쓰인다.
read() 함수와 write() 함수는 짝지어져 있다. 즉, read() 함수 또는 write() 함수 중 어느 한 쪽이 먼저 호출되면, 다른 한 쪽에서 이와 짝지어진 함수를 호출할 때까지 계속해서 대기 상태 (blocking)에 놓이게 된다는 것이다. 대기 상태에 놓인 프로그램은 어떤 작업도 하지 않는 유휴 상태가 된다. 따라서, TCP/IP 소켓 프로그래밍을 할때에 가장 조심해야 할 부분이 이러한 부분이다. read() 함수와 write() 함수는 같이 따라가야지 프로그램이 제대로 동작하기 때문이다.
연결 종료 단계 (close())
프로그램 소개
실행 방법
실행 결과
프로그램 소개
실행 방법
실행 결과
프로그램 소개
실행 방법
실행 결과
클라이언트
서버
- 소스 코드 (다운로드 가능)
https://github.com/deblur99/Network-Programming-Practice