4-11 네트워크

do·2022년 6월 13일
1

API

목록 보기
38/42

TCP/UDP 기본 개념

TCP (Transmission Control Protocol, 전송 제어 프로토콜)

  • 인터넷 상에서 데이터를 메세지의 형태로 보내기 위해 IP와 함께 사용하는 프로토콜
  • 연속성보다는 신뢰성 있는 전송이 중요할 때에 사용하는 프로토콜
  • 연결형 서비스로 가상 회선 방식을 제공한다.
    • 발신지와 수신지를 연결하여 패킷을 전송하기 위한 논리적 경로를 배정한다는 말
  • 데이터의 흐름 제어 및 혼잡 제어의 기능이 있기 때문에 UDP보다 속도가 느리다.
    • 이러한 기능은 CPU를 사용하기 때문에 속도에 영향을 준다.
    • 패킷에 대한 응답을 해야하기 때문에 (시간 지연, CPU 소모) 성능이 낮다.
  • 높은 신뢰성을 보장한다.

TCP 연결 수립 절차 / 연결 해제 절차

  • TCP는 연결 수립 시 첫번째 통신에서 사용할 초기 순서번호(ISN; Initial Sequence Number)를 무작위로 지정하고 상대에게 알린다.
  • TPC handshake는 TCP/IP 프로토콜을 이용해 통신하는 응용 프로그램이 데이터를 전송하기 전에 먼저 정확한 전송을 보장하기 위해 상대방 컴퓨터와 사전에 세션을 수립하는 과정을 의미한다.

3-way handshake 접속 과정

TCP 연결 수립시 사용되는 메시지
메시지설명
SYN(synchronize)동기화 메시지. 연결을 초기화하고 수립한다. 이 메시지는 장비 간의 순서 번호를 동기화 시킨다.
ACK(acknowledgement)승인 메시지. 이 메시지는 SYN나 FIN의 메시지에 대해 잘 받았다는 응답을 처리한다.
TCP 연결 수립시 사용되는 TCP 소켓의 상태
상태설명
CLOSED연결 수립을 시작하기 전의 기본 상태(연결 없음)
LISTEN클라이언트의 SYN(연결 초기화 요청) 메시지를 기다리는 상태
SYN-SENT자신의 SYN 메시지를 보내고 상대방의 응답 SYN을 기다리는 상태
SYN-RECEIVED상대방의 SYN 메시지를 전달받고 자신의 SYN 메시지를 보내고 ACK를 기다리는 상태
  1. 클라이언트는 접속을 요청하는 SYN 패킷을 보낸다. 이때 클라이언트는 SYN 패킷을 보냄과 동시에 SYN/ACK 응답을 기다리기 위해 SYN_SENT 상태로 변하게 된다.
  2. 서버는 SYN 요청을 받고 클라이언트에게 요청을 수락하는 ACK 패킷과 SYN 패킷을 보내고 SYN-RECEIVED 상태로 변하여 클라이언트가 ACK 패킷을 보낼 때까지 기다린다.
  3. 클라이언트는 서버에 ACK 패킷을 보내고 이후 ESTABLISHED 상태가 되어 데이터 통신이 가능해진다.
  • ACK 패킷의 Acknowledgement Number는 신뢰적 데이터 전송을 위해 사용된다.
  • ISN(Initialized Sequence Number) 초기 시퀀스 번호는 SYN 패킷의 Sequence Number는 운영체제에 의해 랜덤으로 생성된다.
  • SYN 메시지에 새로 생성된 ISN을 TCP의 헤더의 순서번호 필드에 입력해서 보내고, 받은 쪽에서는 그 ISN에 +1을 한 값으로 ACK 메시지의 승인번호 필드에 입력해서 보내는 형식으로 동기화 작업을 진행한다.

순서번호 동기화 예제

  • 클라이언트의 ISN은 100이고, 서버의 ISN은 2080이다.
  • ESTABLISHED 상태에서 데이터를 주고 받을 때마다 ISN으로 지정된 순서번호가 증가해서 데이터가 얼마나 전송 되었는지 확인하며, 승인번호를 기준으로 상대방이 데이터를 받았는지 확인한다.

4-way handshake 종료 과정

TCP 연결 종료시 사용되는 메시지
메시지설명
FIN(finish)종료 메시지. TCP 세그먼트의 FIN비트가 설정된 메시지. 장비의 종료 요청을 알린다.
ACK(acknowledgement)승인 메시지. 이 메시지는 SYN나 FIN의 메세지에 대해 잘 받았다는 응답을 처리한다.
TCP 연결 종료시 사용되는 TCP 소켓의 상태
상태설명
CLOSED연결 수립을 시작하기 전의 기본 상태(연결 없음)
ESTABLISHED연결의 수립이 완료된 상태. 서로 데이터를 교환할 수 있다.
CLOSE-WAIT상대방의 FIN(종료 요청)을 받은 상태. 상대방 FIN에 대한 ACK를 보내고 어플리케이션에 종료를 알린다.
LAST-ACKCLOSE-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로 전이한다.
  1. 서버와 클라이언트가 TCP 연결이 되어있는 상태에서 클라이언트가 접속을 끊기 위해 close() 함수를 호출한다. TCP 헤더의 제어 비트 필드에 FIN 비트를 설정한 FIN 메시지를 서버에 보내고, 클라이언트는 FIN_WAIT1 상태로 변한다.
  2. FIN 메시지를 받은 서버 장비는 클라이언트가 close() 한다는 것을 알고 CLOSE_WAIT 상태로 바꾼 후 ACK를 전송한다. 클라이언트가 끊을 것이라는 신호를 받았다는 의미이고, CLOSE_WAIT을 통해 자신의 통신이 끝날 때까지 기다리는 상태가 된다.
  3. ACK를 받은 클라이언트는 FIN_WAIT2로 변환되고, 이때 서버는 close() 함수를 호출하고 FIN을 클라이언트에게 보낸다.
  4. 서버도 연결을 닫았다는 신호를 클라이언트가 수신하하면, 클라이언트는 ACK를 보낸 후 TIME_WAIT 상태로 전환된다.
    이후 모든 것이 끝나면 CLOSED 상태로 변환된다.

비정상 종료 상황

  • 어떠한 이유에서 FIN_WAIT1과 FIN_WAIT2 상태인 연결이 많이 남아있다면 문제가 발생한다.
  • 일정 시간이 지나 Time Out이 되면 연결이 자동으로 종료되긴 하지만, Time Out이 길어서 많은 수의 소켓이 늘어나기만 한다면, 메모리 부족으로 더 이상 소켓을 오픈하지 못하는 경우가 발생한다.
    • 이 경우는 네트워크/방화벽 또는 어플리케이션에서의 close() 처리에 대한 문제 등으로 발생할 수 있으며 원인을 찾기가 쉽지 않다.

TIME-WAIT 상태

  • 위의 예제를 보면 클라이언트의 경우, 연결이 종료된 후에 바로 CLOSED 상태로 전환하지 않고 TIME-WAIT 상태로 전환된 후 일정 시간(최대 세그먼트 수명 2배)을 기다린 후에 CLOSED 상태로 전환되는데 그 이유는,
    • 상대 장비가 ACK 메시지를 받았다는 것을 가정하기 위해 일정 시간을 둔다.
    • 한 연결의 종료와 다음 연결 간에 일정 시간을 둔다. 이런 시간을 둠으로써 다른 연결에서 온 패킷과 자신의 패킷이 뒤섞이는 것을 방지한다.

TCP 데이터 전송 절차

  • TCP의 데이터 전송은 양쪽 프로세스가 동시에 데이터를 전송할 수 있는 전이중 방식(full-duplex)을 지원한다.
    • 전이중 방식: 송신을 하면서 동시에 수신할 수 있는 방식
  • TCP는 부정 응답 기능인 NACK(Negative ACK)를 사용하지 않는다. 따라서 수신 프로세스에 도착한 데이터 세그먼트의 내용이 변형되어도 수신 프로세스가 응답을 하지 않아 데이터 분실과 동일하게 처리된다.
    • 데이터 변형과 분실 오류가 발생하면 수신 프로세스로부터 회신을 받을 수 없으므로 송신 프로세스의 Time Out 기능에 의해 오류가 복구된다.

UDP 데이터 전송 절차

  • UDP는 비연결형 서비스를 이용하여 데이터그램을 전송하며, 각 데이터그램은 전송 과정에서 독립적으로 중개된다.
    • 데이터그램: 패킷교환에서 각 패킷이 독립적으로 처리되어 목적지까지 도달하는 방식
    • 순서와 무관하게 전달됨
  • 흐름 제어 기능을 제공하지 않아 버퍼 오버플로우에 의한 데이터 분실 오류가 발생할 수 있다.
  • 데이터의 순서 번호 기능이 없다.
    • 분실 여부를 확인할 수 없다.
    • 도착 순서를 보장하지 않는다.
      • 따라서 응용 프로그램에서 데이터 분실을 감지하거나, 도착 순서 변경 오류를 해결하려면 순서 번호 기능을 응용 프로그램 내부에 구현해야 한다.

TCP와 UDP 비교 - 각각의 장단점

TCP

  • 장점
    • 신뢰성
      • 패킷 손실, 중복, 전송 순서바뀜 등이 없도록 보장
      • TCP 하위계층인 IP 계층의 신뢰성 없는 서비스에 대해 다방면으로 신뢰성을 제공
    • 연결지향적
      • 양단간 어플리케이션/프로세스는 TCP가 제공하는 연결성 회선을 통하여 서로 통신
      • 연결 관리를 위한 연결설정 및 연결해제 필요
  • 단점
    • 로직이 들어가서 조금 느림
  • 예시
    • HTTP 통신, 이메일, 파일전송

UDP

  • 장점
    • 속도가 빠름
      • 빠른 요청과 응답이 필요한 실시간 응용에 적합
    • 실시간 응용 및 멀티캐스팅 가능
      • 빠른 요청과 응답에 적합
    • 여러 다수 지점에 전송 가능 (1:N)
    • 비연결성이기에 논리적인 가상회선 연결이 필요없고 유연하며, 효율적 응용의 데이터 전송에 사용
    • 소켓 대신 IP를 기반으로 데이터를 전송한다. 패킷들이 각기 독립적으로 전송된다.
  • 단점
    • 신뢰성 보다는 연속성/성능이 중요한 서비스
      • 확인응답 없음 - 메시지가 제대로 도착했는지 확인하지 않음
      • 순서제어 없음 - 수신된 메시지의 순서를 맞추지 않음
      • 흐름제어 없음 - 흐름 제어를 위한 피드백을 제공하지 않음
      • 오류제어 거의 없음 - 검사합을 제외한 특별한 오류 검출 및 제어 없음
        • UDP를 사용하는 프로그램 쪽에서 오류제어 기능을 스스로 갖추어야 함
  • 예시
    • 실시간 스트리밍, VoIP, 온라인 게임, DNS

Byte Ordering

  • 데이터가 저장되는 순서
  • 데이터는 바이트 단위로 저장되지만, 저장되는 방식에 있어서 CPU마다 차이가 발생한다.
    • 4 바이트 크기의 int 자료를 저장한다고 했을 때, 어떤 CPU는 가장 낮은 바이트부터 저장하는가 하면, 어떤 CPU는 가장 높은 바이트부터 데이터를 저장한다.
  • 서로 다른 데이터 저장 방식을 사용하는 시스템끼리 통신하는 경우, 전혀 원하지 않은 값들을 주고 받을 수 있다.
    • 이런 문제를 해결하기 위해 데이터 통신을 할 때는 명시적으로 Network Byte order을 따르도록 데이터의 byte order를 변경한다. 네트워크 byte order는 Big Endian을 따른다.

Big Endian(빅 엔디언)

  • AMD 계열의 CPU
  • 네트워크에 최적화
  • 최상위 바이트부터 저장
  • 앞쪽에 0을 추가
  • 비교 연산에서 리틀 엔디언보다 속도가 빠름

Little Endian(리틀 엔디언)

  • Intel 계열의 CPU
  • 연산에 최적화
  • 최하위 바이트부터 저장
  • 뒤쪽에 0을 추가
  • 계산 연산에서 빅 엔디언보다 속도가 빠름

주소 변환 관련 함수

  • 주소를 표현하기 위해 사용하는 구조체 sockaddr_in 안에서 IP를 나타내기 위한 데이터 타입은 unsigned long형이다.
  • 따라서 IP 주소 정보를 할당하기 위해 문자열의 "192.186.10.10"을 unsigned long형으로 바꿔야 한다. ("192.186.10.10"의 표현 방식은 10진수 표현 방식이라 한다.)
  • 주소를 변환해주는 함수들은 단순히 변환만 시켜주는게 아니라 바이트 순서를 바꿔주는 일도 한다.

1. inet_aton() - 네트워크 주소 변환

#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

2. inet_addr() - 네트워크 주소 변환 (IPv4 전용)

#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)

3. inet_ntoa() - 네트워크 주소 변환

#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;
}

4. inet_pton() - (IPv4/IPv6 주소) readable text -> binary

#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);

5. inet_ntop() - (IPv4/IPv6 주소) binary -> readable text

#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

byte ording 관련 함수

1. htons() - 호스트 바이트 정렬 방식의 2바이트 데이터를 네트워크 바이트 정렬 방식으로 변환

#include <arpa/inet.h>
u_short htons(u_short hostshort);

매개변수 u_short hostshort short형 호스트 바이트 순서의 데이터
return
1. 성공 u_short short형 네트워크 바이트 순서로 변경한 데이터
2. 실패 -1

2. htonl() - 호스트 바이트 정렬 방식의 4바이트 데이터를 네트워크 바이트 정렬 방식으로 변환

#include <arpa/inet.h>
u_long htonl(u_long hostlong);

매개변수 u_long hostlong long형 호스트 바이트 순서의 데이터
return
1. 성공 u_long long형 네트워크 바이트 순서로 변경한 데이터
2. 실패 -1

3. ntohs() - 네트워크 바이트 정렬 방식의 2바이트 데이터를 호스트 바이트 정렬 방식으로 변환

#include <arpa/inet.h>
u_short ntohs(u_short netshort);

매개변수 u_short netshort short형 네트워크 바이트 순서의 데이터
return
1. 성공 u_short short형 호스트 바이트 순서로 변경한 데이터
2. 실패 -1

4. ntohl() - 네트워크 바이트 정렬 방식의 4바이트 데이터를 호스트 바이트 정렬 방식으로 변환

#include <arpa/inet.h>
u_long ntohl(u_long netlong);

매개변수 u_long netlong long형 네트워크 바이트 순서의 데이터
return
1. 성공 u_long long형 호스트 바이트 순서로 변경한 데이터
2. 실패 -1

TCP Client/Server 소켓 프로그래밍

TCP/IP 통신 함수 사용 순서

서버 프로그램

클라이언트 프로그램

1. socket() - 소켓 생성

#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

2. connect() - 연결 요청

#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() 함수는 리턴되지 않고, 블로킹 상태에 있는다.

3. bind() - 주소 정보 할당

#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

4. listen() - 연결 요청 대기

#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

5. accept() - 연결 요청 수락

#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

6. send() - TCP 데이터 송신(Stream 소켓)

#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

7. recv() - TCP 데이터 수신(Stream 소켓)

#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

8. shutdown - 소켓 기능 제한

#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

9. close() - 소켓 종료

#include <unistd.h>
int close(int sockfd);

설명 현재 전송 중인 데이터를 소멸시킨다.
인자로 전달된 socketfd의 참조 카운터를 하나 감소시키며, 참조 카운터가 0이 된다면 socketfd를 종료시킨다.
매개변수 int socket_fd 소켓 디스크립터
return
1. 성공 0
2. 실패 -1 errno

UDP Client/Server 소켓 프로그래밍

UDP/IP 통신 함수 사용 순서

수신이 필요한 쪽

송신만 하는 쪽

1. socket()

2. bind()

3. sendto() - UDP 데이터 송신(Datagram 소켓)

#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

4. sendmsg() - UDP 데이터 송신(Datagram 소켓)

#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

5. recvfrom() - UDP 데이터 수신(Datagram 소켓)

#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

6. recvmsg() - UDP 데이터 수신(Datagram 소켓)

#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

7. close()

0개의 댓글