개요
대부분의 네트워크는 클라이언트와 서버로 나눌 수 있다.
웹 클라이언트와 서버는 TCP 프로토콜을 이용하여 통신한다.
일반적으로 사용되는 분야는 실시간 통신, 메일, 컴퓨터 간 파일 전송, 원격 로그인이 있다.
기본적으로 알아야 할 용어와 개념은 다음과 같다.
소켓: 두 프로그램이 서로 데이터를 주고 받을 수 있는 양쪽에 생성되는 통신 단자
소켓 통신: 서버와 클라이언트 양방향 연결이 이루어지는 통신, 그림으로는 다음과 같다.
클라이언트는 서버에 request를 보내고 서버는 reply를 보낸다.
흐름
소켓 통신의 흐름은 다음과 같다.
1. 서버와 클라이언트가 있으면 서버부터 실행한다.
2. 클라이언트는 서버에 요청을 보낸다.
3. 서버는 이를 처리한 후 클라이언트에 답장을 보낸다.
4. 클라이언트는 서버에게 파일 끝 통보(end-of-file notification)를 보내서 연결의 한쪽 끝을 닫을 때까지 연결은 계속된다. 코드에서는 무한 반복문으로 표현된다.
5. 서버는 다른 쪽 끝을 닫고 종료하거나 새로운 클라이언트 연결을 기다린다.
위의 흐름을 흐름도로 보면 다음 사진과 같다.
socket(), bind()와 같은 것들은 소켓 함수이다.
소켓 함수
socket()함수
socket()함수는 원하는 통신 프로토콜형을 명시하는 함수이다.
통신 프로토콜에는 TCP, IPv6을 사용하는 UDP, 유닉스 영역 흐름 프로토콜 등이 있다.
parameter로 family, type, protocol을 가진다.
family는 프로토콜 군을 규정한다.
AF_INET | IPv4 |
AF_INET6 | IPv6 |
AF_LOCAL | Unix domain |
AF_ROUTE | Routing socket |
AF_KEY | Key socket |
AF는 Adress Family의 약자이다.
type은 소켓형을 지정한다.
SOCK_STREAM | stream socket |
SOCK_DGRAM | datagram socket |
SOCK_RAW | raw socket |
protocol은 생소켓을 제외하고는 0으로 설정한다.
socket()함수는 정상적으로 실행 시 음수가 아닌 작은 정수 값을 반환한다.
이를 소켓 지정 번호(sockfd)라고 한다.
fork()함수
부모 즉 자기 자신의 복사본을 만든다.
이 복사본들이 각기 다른 일을 처리하도록 한다.
부모 프로세스는 0이 아닌 값을 pid로 가진다. 0이 아닐 경우 close한다.
자식 프로세스는 요청/응답을 처리한다.(read write)
그림으로는 다음과 같다
부모 프로세스인 서버는 client로부터 연결 요청이 오면 fork 함수로 자식 프로세스를 생성한다.
생성된 자식 프로세스 서버는 client와 연결한다.
connect()함수
TCP클라이언트가 TCP서버와 연결을 설정하려 할때 사용하는 함수이다.
parameter은 sockfd, servaddr, addrlen이 있다.
sockfd는 socket()함수가 돌려주는 소켓 지정 번호이다.
servaddr는 소켓 주소 구조이다. 서버의 IP address와 포트번호가 반드시 있어야 한다.
addrlen은 소켓 주소 크기이다.
connect 함수는 오류 메세지에 따라 의미가 다르다.
SYN(synchronization:동기화) : 연결 요청 플래그
RST(reset) : 재 연결 종료
ETIMEOUT : SYN 세그먼트에 대한 응답을 받지 못할 경우 돌려주는 값. connect 호출 후에 SYN을 하나 보내고 6초 후에 하나, 24초 후에 하나, 이런 방식으로 SYN을 보낸다. 첫 SYN 이후 75초 동안 응답이 없으면 오류가 발생한 것이다.
ECONNRE-FUSED : 이 포트에서 연결을 기다리고 있는 프로세스가 없다.
connect()함수는 정상적으로 실행 시 0, 에러 발생시 -1을 return한다.
listen() 함수
listen함수는 첫번째 인수로 sockfd를 갖는데 이 소켓에 대한 연결 요청을 받아들인다.
즉 listen함수는 첫번째 인수로 받은 sockfd의 연결 요청을 받아들이는 역할을 하는 함수이다.
listen 호출은 소켓을 CLOSE 상태에서 LISTEN 상태로 옮긴다.
두 번째 인수로 backlog를 갖는다.
backlog는 연결용 대기열이다. 대기열 안에 들지 못한 클라이언트는 연결 요청이 만료되면 timeout된다.
listen 함수는 정상적으로 실행시 0, 에러 발생 시 -1을 return한다.
bind() 함수
소켓에 지역 프로토콜 주소를 부여한다.
bind()를 호출하려면 포트 번호 또는 IP 주소 또는 포트 번호, IP주소 둘 모두 또는 이 둘 모두가 아닌것으로 명시해야 한다.
포트번호를 0으로 명시하면 bind가 호출될 때 단명포트를 선택한다.
단명포트는 임시로 사용되는 포트를 의미한다.
bind() 함수는 정상적으로 실행시 0, 에러 발생 시 -1을 return한다.
accept() 함수
연결 대기열의 맨 앞에 있는 클라이언트와 연결하는 함수이다.
위의 connect 함수와 같은 parameter를 갖는다.
accept() 함수는 정상적으로 실행 시 음이 아닌 값을 return하고 에러 발생 시 -1을 return한다.
참고하면 좋은 Github
https://github.com/woorimlee/linux-network-programming
https://github.com/ryuever/unix-network-programming-v3
첫 번째 github는 본문의 내용을 쉽게 이해하는데에 도움이 될 것이고, 두 번째 github는 본문의 내용에 있는 함수들이 모두 사용되어 있을 것이다.
리눅스 환경에서 실행하는 것을 추천한다.