IV : TCP 서버-클라이언트
TCP/IP 윈도우 소켓 프로그래밍 을 읽고 정리한 문서입니다 ;)
TCP 서버-클라이언트 구조
TCP 서버-클라이언트의 예로, 웹 서버와 웹 클라이언트인 브라우저가 동작하는 모습이 있다.
- 서버는 먼저 실행되어 클라이언트가 접속하기를 기다린다 (listen)
- 클라이언트는 서버에 접속하여 데이터를 보낸다. (connect & send)
- 서버는 클라이언트 접속을 수용하고 클라이언트의 데이터를 받아 처리한다 (accept & recv)
- 서버는 처리한 데이터를 클라이언트로 보낸다 (send)
- 클라이언트는 서버가 보낸 데이터를 받아 처리한다 (recv)
- 데이터 주고받기가 끝나면 접속을 끊는다 (close)
받은 데이터를 그대로 다시 클라이언트로 되돌려 주는 서버를 에코 서버라고 한다.
netstat
명령은 TCP/IP 네트워크 연결과 통계 정보를 표시하는 유틸리티이다.
-a
옵션은 모든 연결과 연결 대기 포트를 출력하며, -n
옵션은 IP주소를 이름을 가져오지 않고 그대로 출력한다.
이를 통해 확인하면, 서버 프로세스는 기본으로 accept 를 위한 연결 + 클라이언트당 하나의 연결 소켓이 존재하며, 클라이언트 프로세스는 서버와 연결하는 하나의 소켓을 가지게 되는 것을 알 수 있다.
TCP 서버-클라이언트 분석
응용 프로그램이 소켓을 통해 통신하려면 다음 요소가 결정되어야 한다.
- 사용할 프로토콜
- 지역 IP 주소와 지역 포트 번호
- 원격 IP 주소와 원격 포트 번호
따라서 기본적으로 사용되는 대표 소켓 함수들은 지역 주소와 원격 주소를 결정하고, TCP 상태를 LISTENING
이나 ESTABLISHED
등으로 변경하기 위한 일련의 절차라고 할 수 있다.
서버에서의 TCP 소켓 함수 호출
socket()
함수로 소켓을 생성함으로서 사용할 프로토콜을 결정한다.bind()
함수로 지역 IP 주소와 지역 포트 번호를 결정한다.int bind( SOCKET s, // 접속을 수용할 목적으로 만든 소켓인 상태 const struct sockaddr *name, // 사용할 지역 IP 와 PORT로 초기화하여 전달한다 int namelen // SOCKADDR length );
listen()
함수로 TCP를LISTENING
상태로 변경한다.int listen( SOCKET s, // bind() 까지 수행된 상태의 소켓 int backlog // 연결 큐에 대기할 수 있는 최대 클라이언트 수 (SOMAXCONN가 최대) );
accept()
함수로 자신에게 접속한 클라이언트와의 소켓을 생성하고, 원격 IP 주소와 원격 포트 번호가 결정된다.이 함수는 접속한 클라이언트가 없을 경우 프로세스를 대기 상태 (wait, suspend)로 만든다.
SOCKET accept( SOCKET s, struct sockaddr *addr, // 연결이 수립된 클라이언트의 주소 정보 int *addrlen // SOCKADDR length );
send()
,recv()
등의 데이터 전송 함수로 클라이언트와 통신을 수행하고,closesocket()
으로 소켓을 닫는다.
클라이언트에서의 TCP 소켓 함수 호출
socket()
함수로 소켓을 생성함으로서 사용할 프로토콜을 결정한다.connect()
함수로 서버에 접속한다. 원격 IP와 원격 포트, 지역 IP 주소와 지역 포트 까지 결정된다.int connect( SOCKET s, // socket()으로 만들어진 소켓 const struct sockaddr *name, // 원격 IP 포트를 입력한 소켓 주소 구조체 int namelen // SOCKADDR length );
send()
,recv()
등을 통해 데이터를 전송하고,closesocket()
으로 소켓을 닫는다.
TCP 데이터 전송 함수
TCP/IP 프로토콜 스택에는 데이터를 전송하기 전 임시로 저장해두는 송신 버퍼가 존재하며, 받은 데이터를 응용 프로그램이 처리하기 전에 임시로 저장해두는 수신 버퍼가 존재한다. 이들을 합쳐 소켓 버퍼라고 부른다.
send()
함수는 프로토콜 스택으로 데이터 복사가 성공하면 곧바로 리턴한다. 따라서 send()
리턴 후 실제 프로토콜 스택과 네트워크 장비들을 통해 데이터가 전달되어야 상대방에게 데이터가 전달되는 것이다.
int send(
SOCKET s, // SOCKET
const char *buf, // 보낼 데이터를 담고 있는 응용프로그램 버퍼 주소
int len, // 보낼 데이터 길이
int flags // 대부분 0
);
send()
함수는 첫 번째 인자로 전달하는 SOCKET
의 특성에 따라 두 종류의 리턴을 할 수 있다.
- blocking socket : 송신 버퍼의 여유 공간이 보낼 데이터 길이보다 작은 경우, 해당 프로세스는
blocking
상태가 된다. 이후 송신 버퍼에 여유가 생겼을 때 일이 처리되고 리턴된다. - non-blocking socket : 송신 버퍼의 남은 공간만큼 데이터 복사를 수행한 뒤, 복사를 수행한 크기를 리턴해준다.
recv()
함수는 운영체제의 수신 버퍼에 도착한 데이터를 응용 프로그램 버퍼에 복사하는 동작이다.
int recv(
SOCKET s, // SOCKET
char *buf, // 응용프로그램 버퍼 주소
int len, // 읽어올 최대 데이터 크기
int flags // 대부분 0
);
recv()
함수는 다음 두 종류의 성공적인 리턴을 할 수 있다.
- 수신 버퍼에 데이터가 도달한 경우 : 데이터를 응용 프로그램의 버퍼에 복사한 후 실제 복사한 바이트 수를 리턴하기에, 최소 리턴 값은
1
, 최대 리턴 값은len
이다. - 접속이 정상 종료되었을 경우 : 이때는
0
을 리턴함으로서 정상 종료된 상태임을 알린다.
TCP는 데이터 경계를 구분하지 않기에, 자신이 받을 데이터의 크기를 미리 알고 있다면 그만큼 받을 때 까지 recv()
를 반복하여 호출해야 한다.
int recvn(SOCKET s, char *buf, int len, int flags) {
int received;
char *ptr = buf;
int left = len;
while(left > 0) {
received = recv(s, ptr, left, flags);
if (received == SOCKET_ERROR)
return SOCKET_ERROR;
else if (received == 0)
break;
left -= received;
ptr += received;
}
return len-left;
}
TCP 서버-클라이언트 IPv6
기존 IPv4 주소 체계 코드를 IPv6 코드로 변환하는 규칙은 다음과 같다.
ws2tcpip.h
헤더 파일을 포함한다.- 소켓 생성 시
AF_INET
대신AF_INET6
을 사용한다. - 소켓 주소 구조체로
SOCKADDR_IN
대신SOCKADDR_IN6
을 사용한다. - IPv4만을 지원하는 함수를 IPv4 및 IPv6 을 지원하는 함수로 변경한다.
요약
- TCP 응용 프로그램의 통신을 위한 다섯 가지 값
- 프로토콜, 지역 IP 및 포트 주소, 원격 IP 및 포트 주소
- TCP 서버 핵심 함수
bind()
: 소켓의 지역 IP와 포트 번호 결정listen()
: 소켓의 TCP 포트 상태를LISTENING
으로 변경accept()
: 서버로 접속하는 클라이언트의 주소가 입력된 새 소켓을 리턴받음
- TCP 클라이언트 핵심 함수
connect()
: 원격 IP 주소와 포트로 논리적 연결을 설정한다
- 소켓 버퍼
- 송신 버퍼 : 데이터를 보내기 전 임시로 저장해두는 영역
- 수신 버퍼 : 도착한 데이터를 응용프로그램이 가져가기 전 저장해두는 영역
- TCP 데이터 전송 함수
send()
: 운영체제 프로토콜 스택의 송신 버퍼에 복사함으로서 할일이 끝나고 리턴된다.recv()
: 프로토콜 스택의 수신 버퍼로부터 원하는 길이의 데이터를 읽어온다.
- IPv4 환경을 IPv6 환경으로 전환
ws2tcpip.h
헤더 파일을 포함AF_INET6
,SOCKADDR_IN6
구조체 사용- IPv6 대응 함수로 변경
'공부한 이야기 > 윈도우 소켓 프로그래밍' 카테고리의 다른 글
VI : 멀티스레드 (0) | 2023.04.29 |
---|---|
V : 데이터 전송하기 (0) | 2023.04.29 |
III : 소켓 주소 구조체 다루기 (0) | 2023.04.29 |
II : 윈도우 소켓 시작하기 (0) | 2023.04.29 |
I : 네트워크 소켓 프로그래밍 (0) | 2023.04.29 |