메시지 | 설명 |
---|---|
SYN(synchronize) | 동기화 메시지. 연결을 초기화하고 수립한다. 이 메시지는 장비 간의 순서 번호를 동기화 시킨다. |
ACK(acknowledgement) | 승인 메시지. 이 메시지는 SYN나 FIN의 메시지에 대해 잘 받았다는 응답을 처리한다. |
상태 | 설명 |
---|---|
CLOSED | 연결 수립을 시작하기 전의 기본 상태(연결 없음) |
LISTEN | 클라이언트의 SYN(연결 초기화 요청) 메시지를 기다리는 상태 |
SYN-SENT | 자신의 SYN 메시지를 보내고 상대방의 응답 SYN을 기다리는 상태 |
SYN-RECEIVED | 상대방의 SYN 메시지를 전달받고 자신의 SYN 메시지를 보내고 ACK를 기다리는 상태 |
순서번호 동기화 예제
- 클라이언트의 ISN은 100이고, 서버의 ISN은 2080이다.
- ESTABLISHED 상태에서 데이터를 주고 받을 때마다 ISN으로 지정된 순서번호가 증가해서 데이터가 얼마나 전송 되었는지 확인하며, 승인번호를 기준으로 상대방이 데이터를 받았는지 확인한다.
메시지 | 설명 |
---|---|
FIN(finish) | 종료 메시지. TCP 세그먼트의 FIN비트가 설정된 메시지. 장비의 종료 요청을 알린다. |
ACK(acknowledgement) | 승인 메시지. 이 메시지는 SYN나 FIN의 메세지에 대해 잘 받았다는 응답을 처리한다. |
상태 | 설명 |
---|---|
CLOSED | 연결 수립을 시작하기 전의 기본 상태(연결 없음) |
ESTABLISHED | 연결의 수립이 완료된 상태. 서로 데이터를 교환할 수 있다. |
CLOSE-WAIT | 상대방의 FIN(종료 요청)을 받은 상태. 상대방 FIN에 대한 ACK를 보내고 어플리케이션에 종료를 알린다. |
LAST-ACK | CLOSE-WAIT 상태를 처리 후, 자신의 FIN 요청을 보낸 후 FN에 대한 ACK를 기다리는 상태 |
FIN-WAIT-1 | 자신이 보낸 FIN에 대한 ACK를 기다리거나 상대방의 FIN을 기다린다. |
FIN-WAIT-2 | 자신이 보낸 FIN에 대한 ACK를 받았고 상대방의 FIN을 기다린다. |
CLOSING | 상대방의 FIN에 ACK를 보냈지만 자신의 FIN에 대한 ACK를 못 받은 상태 |
TIME-WAIT | 모든 FIN에 대한 ACK를 받고 연결 종료가 완료된 상태. 새 연결과 겹치지 않도록 일정 시간 동안 기다린 후 CLOSED로 전이한다. |
TIME-WAIT 상태
- 위의 예제를 보면 클라이언트의 경우, 연결이 종료된 후에 바로 CLOSED 상태로 전환하지 않고 TIME-WAIT 상태로 전환된 후 일정 시간(최대 세그먼트 수명 2배)을 기다린 후에 CLOSED 상태로 전환되는데 그 이유는,
- 상대 장비가 ACK 메시지를 받았다는 것을 가정하기 위해 일정 시간을 둔다.
- 한 연결의 종료와 다음 연결 간에 일정 시간을 둔다. 이런 시간을 둠으로써 다른 연결에서 온 패킷과 자신의 패킷이 뒤섞이는 것을 방지한다.
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char* string, struct in_addr* inp);
설명 inet_addr()의 업그레이드 버전
매개변수1 const char* string
주소 문자열
매개변수2 struct in_addr* inp
구조체 멤버변수 중 주소값이 들어가는 멤버변수의 주소값
return
1. 성공 int
0이 아닌 값
2. 실패 0
struct sockaddr_in addr;
inet_aton("192.168.1.102", &addr); //6601a8c0
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
in_addr_t inet_addr(const char *string);
설명 문자열로 표현한 IPv4 주소를, 네트워크 바이트 정렬 방식의 4바이트 정수로 변환
(이 함수는 255.255.255.255 주소에 대한 리턴값이 INADDR_NONE(-1)과 동일하여 구분할 수 없는 문제가 있다. 따라서 최대한 inet_aton()을 사용해야 한다.)
매개변수 const char* string
주소 문자열
return
1. 성공 int_addr_t
빅엔디안 32비트값/unsigned long형의 값/uint32_t
2. 실패 INADDR_NONE(-1)
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
char* inet_ntoa(struct in_addr in);
설명 네트워크 바이트 정렬 방식의 4바이트 정수의 IPv4 주소를, 문자열 주소로 표현
매개변수 struct in_addr in
구조체의 멤버변수 중 주소 문자열이 있는 멤버변수
return
1. 성공 char*
변환된 해당 문자열의 포인터
2. 실패 -1
//in_addr 구조체는 netinet/in.h에 정의되어 있다.
struct in_addr
{
unsigned long int s_addr;
}
#include <arpa/inet.h>
int inet_pton(int af, const char* src, void* dst);
설명 문자열을 프로토콜(IP4, IP6 등)에 해당하는 네트워크 데이터(빅엔디언 방식의 이진데이터)로 변경
매개변수1 int af
address family를 지정
- AF_INET
32비트의 IPv4 네트워크 주소(예시:"198.02.031.203")로 변환된다. src는 struct in_addr 구조체를 가리킴. dst의 크기는 최소한 INET-ADDRSTRLEN의 바이트 크기여야 한다.
- AF_INET6
128비트의 IPv6 네트워크 주소(예시:"2001:0db8:85a3:08d3:1319:8a2e:0370:7334")로 변환된다. src는 struct in6_addr 구조체를 가리킴. dst의 크기는 최소한 INET6_ADDRSTRLEN의 바이트 크기여야 한다.
매개변수2 const char *src
문자열 형태의 주소
매개변수3 void* dst
src를 binary형태로 변환 후 복사된 메모리의 포인터. Network byte order로 작성된다.
return
1. 성공 1
성공적으로 변환된 네트워크 주소가 dst에 저장됨
2. 실패 0
src의 문자열이 나타내는 네트워크 주소가 af에 명시된 address family의 유효한 값이 아닌 경우
3. 실패 -1 errno
af가 적절한 address family값이 아닌 경우 EAFNOSUPPORT
char *ip = "192.168.0,1"
in_addr addr;
inet_pton(AF_INET, ip, &addr.s_addr);
sockadrr_in in_addr;
inet_pton(AF_INET, ip, &in_addr.sin_addr);
#include <arpa/inet.h>
const char* inet_ntop(int af, const void* src, char* dst, socklen_t size);
설명 네트워크 주소 구조체인 src를 문자열 dst로 변환해주는 함수
dst가 IPv4일 는 sin_addr.sin_addr의 포인터이고, IPv6일 때는 sin_addr.sin6_addr의 포인터이다.
매개변수1 int af
address family (위에 있음)
- AF_INET
- AF_INET6
매개변수2 const char *src
네트워크 주소 구조체 (IPv4/IPv6)
매개변수3 char* dst
문자열
매개변수4 socklen_t size
dst 버퍼의 크기
return
1. 성공 const char*
dst를 가리키는 포인터
2. 실패 NULL errno
#include <arpa/inet.h>
u_short htons(u_short hostshort);
매개변수 u_short hostshort
short형 호스트 바이트 순서의 데이터
return
1. 성공 u_short
short형 네트워크 바이트 순서로 변경한 데이터
2. 실패 -1
#include <arpa/inet.h>
u_long htonl(u_long hostlong);
매개변수 u_long hostlong
long형 호스트 바이트 순서의 데이터
return
1. 성공 u_long
long형 네트워크 바이트 순서로 변경한 데이터
2. 실패 -1
#include <arpa/inet.h>
u_short ntohs(u_short netshort);
매개변수 u_short netshort
short형 네트워크 바이트 순서의 데이터
return
1. 성공 u_short
short형 호스트 바이트 순서로 변경한 데이터
2. 실패 -1
#include <arpa/inet.h>
u_long ntohl(u_long netlong);
매개변수 u_long netlong
long형 네트워크 바이트 순서의 데이터
return
1. 성공 u_long
long형 호스트 바이트 순서로 변경한 데이터
2. 실패 -1
TCP/IP 통신 함수 사용 순서
서버 프로그램
클라이언트 프로그램
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
설명 호스트가 통신하기 위해 필요한 리소스를 할당한다.
매개변수1 int domain
[프로토콜 체계] 생성할 소켓이 통신을 하기 위해 사용할 프로토콜 체계를 설정
- PF_INET
AF_INET
IPv4 인터넷 프로토콜
- PF_INET6
IPv6 인터넷 프로토콜
- PF_LOCAL
AF_UNIX
같은 시스템 내에서 프로세스끼리 통신함 (Local 통신을 위한 UNIX 프로토콜)
- PF_PACKET
Low level socket을 위한 인터페이스
- PF_IPX
IPX 노벨 프로토콜
매개변수2 int type
[소켓 타입] 소켓이 데이터를 전송하는데 있어서, 사용하게 되는 전송 타입을 설정
- SOCK_STREAM
TCP/IP 프로토콜 이용
- SOCK_DGRAM
UDP/IP 프로토콜 이용
매개변수3 int protocol
[프로토콜 선택] 두 호스트 간에 통신을 하는데 있어서 특정 프로토콜을 지정하기 위해 사용 (보통 0값을 사용함)
- 하나의 프로토콜 체계 안에서 데이터 전송 타입까지 같지만 최종적으로 통신하는 형태가 다른, 즉 전송타입은 같지만 그 안에서도 프로토콜이 또 다시 나뉘는 상황에서 이 인자는 유용한 인자가 된다. (프로토콜 구체화)
- 프로토콜 체계가 PF_INET인 경우, IPPROTO_TCP
TCP를 기반으로 하는 소켓 생성(연결 지향형 소켓) / IPPROTO_UDP
UDP를 기반으로 하는 소켓 생성(비연결 지향형 소켓)과 같은 값을 설정할 수 있다.
return
1. 성공 int
소켓 파일 디스크립터
2. 실패 -1
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
설명 클라이언트의 주소 할당은 connect() 함수를 호출할 때, 커널이 자동으로 해준다. (bind 과정 필요없음)
매개변수1 int sockfd
클라이언트 소켓의 파일 디스크립터
매개변수2 const struct sockaddr* addr
소켓에 설정할 주소 정보에 대한 struct
struct sockaddr는 socket을 지원하는 프로토콜의 기본 골격에 대한 struct이며,
AF_* (Address Family)에 따라서 struct를 다르게 정의하여 사용한다.
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
로 safamily에 AF값을 설정하고 AF_값에 따라서 sadata의 구조가 다르다.
따라서 AF값에 따라서 구조체를 재정의하며 사용하며, Address Family에 따라서 char sa_data[14];
즉, 14바이트보다 큰 경우가 있으므로 사실상 struct sockaddr은 의미가 없는 구조체이다.
매개변수3 socklen_t addrlen
addr 구조체의 크기를 저장한 변수 (AF_* 상수에 따라 크기가 다름)
return
1. 성공 -1이 아님
연결 요청이 서버에 의해 수락
2. 실패 -1
오류가 발생해 연결 요청 중단
만약 연결 요청이 바로 이루어지지 않고 서버의 대기 큐에서 대기하고 있는 상태라면, connect() 함수는 리턴되지 않고, 블로킹 상태에 있는다.
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
매개변수1 int sockfd
주소를 할당하고자 하는 소켓의 파일 디스크립터
매개변수2 const struct sockaddr* addr
할당하고자 하는 주소 정보를 지니고 있는 sockaddr 구조체 변수의 인자값
//sockaddr 구조체
struct sockaddr {
sa_family_t sa_family; //소켓의 주소체계
char sa_data[14]; //해당 주소체계에서 사용하는 주소 정보
}
//sockaddr_in 구조체 (IPv4 주소체계에서 사용됨)
struct sockaddr_in {
sin_family_t sin_family; //IPv4 주소체계에서 사용하므로 항상 AF_INET으로 설정
unist16_t sin_port; //포트 번호
struct in_addr sin_addr; //IP주소를 나타내는 32비트 정수 타입 구조체
char sin_zero[8]; //sockaddr와 같은 크기를 유지하기 위해 필요한 패딩 공간. 항상 0
}
매개변수3 socklen_t addrlen
인자로 전달된 주소 정보 구조체의 길이
return
1. 성공 0
sockfd가 가리키는 소켓에 addr이 가리키는 주소 정보가 할당된다.
2. 실패 -1
#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd, int backlog);
설명 클라이언트로부터의 연결 요청을 처리할 수 있는 상태
매개변수1 int sockfd
클라이언트로부터 연결 요청을 받아들이기 위한 소켓 파일 디스크립터(== 서버 소켓)
매개변수2 int backlog
연결 요청 대기 큐의 크기에 대한 설정
return
1. 성공 0
함수 호출 성공하면, 여러 클라이언트들이 연결 요청 해올 것이고, 모든 연결 요청은 서버가 미리 만들어놓은 대기실로 들어가 순서대로 연결 요청이 수락될 때까지 기다려야 한다.
- 서버 소켓 상태는 CLOSE에서 LISTEN 상태로 변경되고, 연결을 요청한 클라이언트 소켓은 SYN_RCVD 상태에서 3-way handshaking을 완료하고 ESTABLISHED 상태가 된다.
2. 실패 -1
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
설명 클라이언트로부터의 연결 요청을 수락하여 데이터를 주고 받을 수 있는 상태로 설정한다.
'연결 요청 대기큐'에서 대기 중에 있는 클라이언트의 데이터 입,출력을 하기 위해 사용될 소켓을 새로 생성하고, 그 소켓의 파일 디스크립터를 리턴하기 때문에 소켓 생성을 따로 하지 않아도 된다.
매개변수1 int sockfd
서버 소켓의 파일 디스크립터
매개변수2 struct sockaddr* addr
연결 요청을 수락할 클라이언트의 주소 정보
매개변수3 socklent_t* addrlen
addr이 가리키는 구조체의 크기
return
1. 성공 int
새로 생긴 파일 디스크립터
2. 실패 -1
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void* buf, size_t len, int flags);
설명 address를 지정할 수 없기 때문에 연결지향 방식인 TCP 통신에서 사용된다.
소켓이 connected 상태에 있을 때 사용된다.
매개변수1 int sockfd
목적지의 주소 정보를 갖는 파일 디스크립터
- connect(), accept()로 연결된 소켓 디스크립터
매개변수2 const void* buf
전송할 데이터를 저장할 버퍼
매개변수3 size_t len
전송할 데이터의 길이
매개변수4 int flags
전송할 데이터 또는 읽는 방법에 대한 옵션. 0 또는 bit or 연산으로 설정 가능함
- MSG_DONTROUTE
gateway를 통하지 않고 직접 상대시스템으로 전송
- MSG_DONTWAIT
non blocking에서 사용하는 옵션으로 전송이 block되면 EAGAIN, EWOULDBLOCK 오류로 바로 리턴함
- MSG_MORE
더 전송할 데이터가 있음을 설정함
- MSG_OOB
out of band(긴급데이터) 데이터를 읽는다. 주로 X.25에서 접속이 끊겼을 때 전송되는 데이터
- MSG_NOSIGNAL
, MSG_EOR
, MSG_CONFIRM
- 0
일반 데이터. write(sockfd, buf, len)을 호출한 것과 같음
return
1. 성공 ssize_t
실제로 전송된 데이터량
2. 실패 -1
errno
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void* buf, size_t len, int flags);
설명 connect(), accept() 등으로 연결된 소켓으로부터 데이터를 수신한다.
address를 지정할 수 없기 때문에 연결지향 방식인 TCP 통신에서 사용된다.
매개변수1 int sockfd
접속된 소켓의 파일 디스크립터
매개변수2 void* buf
수신 데이터를 저장할 버퍼
매개변수3 size_t len
읽을 데이터 길이
매개변수4 int flags
읽을 데이터 유형 또는 읽는 방법에 대한 옵션
- MSG_OOB
out of band(긴급데이터) 데이터를 읽는다. 주로 X.25에서 접속이 끊겼을 때 전송되는 데이터
- MSG_PEEK
receive queue의 데이터를 queue에서 제거하지 않고 확인하기 위한 목적으로 설정함
- MSG_WAITALL
읽으려는 데이터가 buffer에 찰 때까지 대기함
- 0
일반 데이터. read(sockfd, buf, len)을 호출한 것과 같음
return
1. 성공 ssize_t
수신한 데이터 바이트 수
2. 실패 -1
errno
#include <sys/socket.h>
int shutdown(int sockfd, int how);
설명 소켓을 close하지는 않고 recv/send 기능을 못하도록 일부 기능을 제한하며 다시 그 기능을 살릴 수 없다.
매개변수1 int sockfd
socket(), accept() 등으로 생성한 소켓 디스크립터
매개변수2 int how
어떤 기능을 제한할 것인지 설정값
- SHUT_RD
읽기(수신) 기능
- SHUT_WR
쓰기(전송) 기능
- SHUT_RDWR
읽기/쓰기 모두
return
1. 성공 0
2. 실패 -1
errno
#include <unistd.h>
int close(int sockfd);
설명 현재 전송 중인 데이터를 소멸시킨다.
인자로 전달된 socketfd의 참조 카운터를 하나 감소시키며, 참조 카운터가 0이 된다면 socketfd를 종료시킨다.
매개변수 int socket_fd
소켓 디스크립터
return
1. 성공 0
2. 실패 -1
errno
UDP/IP 통신 함수 사용 순서
수신이 필요한 쪽
송신만 하는 쪽
#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd, void* buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen);
설명 address를 지정할 수 있기 때문에 비연결지향 방식인 UDP 통신에서 사용된다.
send(sockfd, buf, len, flags) == sendto(sockfd, buf, len, flags, NULL, 0)
매개변수1 int sockfd
소켓의 파일 디스크립터
매개변수2 const void* buf
전송할 데이터
매개변수3 size_t len
전송할 데이터의 길이
매개변수4 int flags
전송을 위한 옵션
- MSG_OOB
SOCK_STREAM에서만 사용되며 out-of-band 데이터로 전송될 수 있음
- MSG_DONTROUTE
데이터는 라우팅 될 수 없음
- MSG_DONTWAIT
NONE BLOCKING 통신이 가능하도록 함
- MSG_NOSIGNAL
상대방과 연결이 끊겼을 때, SIGPIPE 시그널을 받지 않도록 함
- MSG_CONFIRM
MSG_EOR
매개변수5 const struct sockaddr* dest_addr
목적지 주소 정보
매개변수6 socklent_t addrlen
목적지 주소 정보의 크기
return
1. 성공 ssize_t
실제 전송한 바이트 수
2. 실패 -1
#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendmsg(int sockfd, const struct msghdr* msg, int flags);
매개변수1 int sockfd
소켓의 파일 디스크립터
매개변수2 const struct msghdr* msg
struct msghdr {
void *msg_name; /* 접속할 주소 */
socklen_t msg_namelen; /* 접속할 주소 크기 */
struct iovec *msg_iov; /* IO 버퍼 */
size_t msg_iovlen; /* IO 버퍼 갯수 */
void *msg_control; /* 제어 정보 버퍼 */
size_t msg_controllen; /* 제어 정보 버퍼 크기 */
int msg_flags; /* 플래그 (사용하지 않음) */
};
매개변수3 int flags
전송할 데이터 또는 읽는 방법에 대한 옵션. 0 또는 bit or 연산으로 설정 가능함
- MSG_DONTROUTE
gateway를 통하지 않고 직접 상대시스템으로 전송
- MSG_DONTWAIT
non blocking에서 사용하는 옵션으로 전송이 block되면 EAGAIN, EWOULDBLOCK 오류로 바로 리턴함
- MSG_MORE
더 전송할 데이터가 있음을 설정함
- MSG_OOB
out of band(긴급데이터) 데이터를 읽는다. 주로 X.25에서 접속이 끊겼을 때 전송되는 데이터
- MSG_NOSIGNAL
, MSG_EOR
, MSG_CONFIRM
- 0
일반 데이터. write(sockfd, buf, len)을 호출한 것과 같음
return
1. 성공 ssize_t
실제 전송한 바이트 수
2. 실패 -1
errno
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void* buf, size_t len, int flags, struct sockaddr* src_addr, socklen_t* addrlen);
설명 address를 지정할 수 있기 때문에 비연결지향 방식인 UDP 통신에서 사용된다.
매개변수1 int sockfd
바인드된 소켓의 파일 디스크립터
매개변수2 void* buf
수신 데이터를 저장할 버퍼
매개변수3 size_t len
읽을 데이터 길이
매개변수4 int flags
읽을 데이터 유형 또는 읽는 방법에 대한 옵션
- MSG_DONTWAIT
- MSG_ERRQUEUE
- MSG_OOB
- MSG_PEEK
- MSG_TRUNC
- MSG_WAITALL
매개변수5 struct sockaddr* src_addr
수신받은 데이터를 송신한 단말의 주소
매개변수6 socklen_t* addrlen
주소 정보 구조체의 길이
return
1. 성공 ssize_t
수신한 데이터 바이트 수
2. 실패 -1
errno
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags);
매개변수1 int sockfd
소켓의 파일 디스크립터
매개변수2 struct msghdr* msg
struct msghdr {
void *msg_name; /* 접속할 주소 */
socklen_t msg_namelen; /* 접속할 주소 크기 */
struct iovec *msg_iov; /* IO 버퍼 */
size_t msg_iovlen; /* IO 버퍼 갯수 */
void *msg_control; /* 제어 정보 버퍼 */
size_t msg_controllen; /* 제어 정보 버퍼 크기 */
int msg_flags; /* 플래그 (사용하지 않음) */
};
매개변수3 int flags
옵션
- MSG_CMSG_CLOEXEC
- MSG_DONTWAIT
- MSG_ERRQUEUE
- MSG_OOB
- MSG_PEEK
- MSG_TRUNC
- MSG_WAITALL
return
1. 성공 ssize_t
수신한 데이터 바이트 수
2. 실패 -1
errno