일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 백준
- n과 m
- 밑바닥부터 시작하는 딥러닝
- 재귀
- 경사하강법
- 1002
- 가상환경
- 파이썬
- Mac
- N-Queen
- 손실함수
- streamlit
- 그리디 알고리즘
- pyenv
- 백트래킹
- Python
- BOJ
- 설정
- 개발환경
- 신경망 학습
- 파이싼
- 1101
- 실버
- 기계학습
- end to end
- 15649
- 4948
- 9020
- Today
- Total
파이톨치
[socket programming] UDP socket program 본문
UDP
TCP와의 비교
UDP는 3-way 통신을 하는 TCP와 다르게, SEQ, ACK 와 같은 메시지 전달을 하지 않는다. 즉, flow contorl이 없다.
때문에 연결의 설정과 해제의 과정도 존재하지 않아서, listen, accept 함수가 필요하지 않는다.
데이터의 전송이 빠르지만, 데이터의 분실 및 손실의 위험이 존재한다.
또한, 1대1 통신이 아니기 때문에, 하나의 UDP 소켓만 존재하고, 연결 개념이 없어서 하나의 소켓으로 둘 이상의 소켓과 데이터 송수신이 가능하다.
UDP 기반의 데이터 입출력 함수
UDP 소켓은 데이터를 전송할 때마다 목적지에 대한 정보를 넣어주어야 한다. 아래 코드에서 전송지가 둘 이상일 수도 있다. 추가로, sendto 함수 호출 시 클라이언트의 IP와 PORT 번호가 자동으로 할당되기 때문에 주소 정보 할당 과정이 불필요하다.
ssize_t sendto(int sock, void *buff, size_t nbytes, int flags, struct sockaddr* to, socklen_t addrlen);
ssize_t recvfrom(int sock, void *buff, size_t nbytes, int flags, struct sockaddr* from, socklen_t addrlen);
UDP의 경우, socket -> bind -> recvfrom/sendto 순서로 동작한다.
serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
// 에코 서버의 서버 코드, 받는 메시지가 BUF_SIZE 보다 크다면 어떻게 해결 해야 하는가?
bind(serv_sock, (struct sockaddr*) &serv_adr, sizeof(serv_adr);
str_len = recvfrom(serv_sock, message, BUF_SIZE, 0, (struct sockaddr*) &clnt_adr, &clnt_adr_sz);
sendto(serv_sock, message, str_len, 0, (struct sockaddr *) &clnt_adr, &clnt_adr_sz);
// 에코 서버의 클라이언트, bind 필요 x
sendto(sock, message, strlen(message), 0, (struct sockaddr*)&serv_adr, sizeof(serv_adr));
adr_sz = sizeof(from_adr);
str_len = recvfrom(sock,message, BUF_SIZE, 0, (struct sockaddr *)&from_adr, &adr_sz);
message[str_len] = 0;
에코 서버에서 serv_adr만 할당해주면 된다. 나머지는 자동 할당이다.
recvfrom() 함수는 데이터를 수신할 때 상대방의 주소 정보를 함께 얻어올 수 있다. 함수 호출 시 마지막 인자로 전달한 주소 구조체 변수에 상대방의 주소 정보가 채워진다.
UDP의 데이터 경계 conected UDP
UDP의 경우, 송신 측에서 sendto() 함수 3번 호출 할 경우, 수신측에서도recvfrom() 함수 3번 호출하여 수신한다.
TCP의 경우, 송신 측에서 delay를 주더라도 수신 측에서 반드시 여러 번 recv()를 호출해야 하는 것은 아니다. 필요에 따라 적절한 크기로 recv()를 호출한다.
즉, TCP와의 차이점은 사용하는 함수가 다르고, 전달할 목적지 정보를 매 호출마다 지정한다는 점이다.
UDP도 connect를 해서 사용할 수 있다. 이 경우에, TCP와 같이 상대 소켓과의 연결을 하는 것이 아니라, 소켓에 목적지에 대한 정보를 등록하는 것이며, read, write를 사용할 수 있게 된다. connected UDP 소켓을 사용하면 한 번 목적지 주소를 지정해 두고 이후에는 마치 TCP처럼 데이터를 송수신한다. 하지만 중요한 점은, connected UDP 소켓이 TCP처럼 실제 연결을 의미하는 것은 아니라는 것이다.
추가로, connect 후 sendto 함수 호출 시, 1번과 3번 과정을 스킵할 수 있다.
1. UDP 소켓에 대한 목적지의 IP와 PORT 번호 등록
2. 데이터 전송
3. UDP 소켓에 등록된 목적지 정보 삭제
멀티 캐스트
UDP 사용시, 출발지 1개, 목적지 여러개인 멀티캐스트를 할 수 있게 된다. 혹은 subnet의 모든 host에 브로드 캐스트 할 수 도 있다.
멀티 캐스트 서버는 특정 멀티 캐스트 그룹을 대상으로 데이터를 딱 한번 전송한다. 특정 멀티 캐스트 그룹으로 전송되는 데이터를 수신하려면 해당 그룹에 가입하면 된다. 때문에, 수신을 위해서는 가입 절차를 거쳐야 한다.
멀티 캐스트 그룹의 가입은 소켓의 옵션 정보 변경을 통해 이루어진다.
그룹으로 가입하는 방법은 다음 코드를 사용한다.
join_adr.imr_multiaddr.s_addr = "멀티 캐스트 그룹의 주소 정보";
join_adr.imr_interface.s_addr = "그룹에 가입할 호스트의 주소 정보";
setsockopt(serv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&join_adr, sizeof(join_adr);
TTL은 패킷을 얼마나 멀리 보낼 것인가를 결정하는 요소이며 이를 옵션으로 넣어준다. 정수로 표현되며 라우터 1개를 거칠 때마다 1씩 감소한다. 0이되면 패킷은 소멸한다.
예) setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void *) &time_live, sizeof(time_live);
멀티 캐스트 Sender, 그룹을 향해서 메시지를 보낸다.
memset(&mul_adr, 0, sizeof(mul_adr));
setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void *) &time_live, sizeof(time_live);
sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr*) &mul_adr, sizeof(mul_adr);
멀티 캐스트 Recevier, receiver가 멀티 캐스트 크룹에 가입하는 수간부터 데이터를 수신하게 된다. 가입 전 데이터는 수신할 수 없다.
memset(&adr, 0, sizeof(adr));
bind(recv_sock, (struct sockaddr *)&adr, sizeof(adr));
setsockopt(serv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&join_adr, sizeof(join_adr);
str_len = recv_from(recv_sock, buf, BUF_SIZE-1, 0, NULL, 0);
브로드 캐스트
동일한 네트워크(subnet) 내에 존재하는 모든 호스트에게 데이터를 전송하는 방법이다. 데이터 전송의 대상이 호스트가 아닌 네트워크 자체이다.
IP에서 네트워크 주소를 제외한 호스트 주소를 모두 1로 전송하면 해당 네트워크로 데이터 전송 (Directed 브로드 캐스트)
IP 주소 255.255.255.255로 데이터 전송하면, 전송한 호스트가 속한 네트워크로 데이터가 전송 (Local 브로드 캐스트)
# sender
int bcast = 1;
memset(&broad_adr, 0, sizeof(broad_adr));
setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (void *)&bcast, sizeof(bcast));
sendto(send_sock, buf, sizeof(buf), 0, (struct sockaddr*) &broad_adr, sizeof(broad_adr));
# receiver
bind(recv_sock, (struct sockaddr*) &adr, sizeof(adr));
str_len = recvfrom(recv_sock, buf, BUF_SIZE-1, 0, NULL, 0);
buf[str_len] = '\0';
2024.04.19 - [대학수업/socket programming] - [socket programming] Socket Options
'대학수업 > socket programming' 카테고리의 다른 글
[socket programming] 멀티 쓰레드 기반의 서버 구현 (1) | 2024.04.20 |
---|---|
[socket programming] IO multiplexing (1) | 2024.04.20 |
[socket programming] 멀티 프로세스 기반 다중 서버 (0) | 2024.04.19 |
[socket programming] Socket Options (2) | 2024.04.19 |
[sock programming] Loopback "hello world" (2) | 2024.04.02 |