2014년 12월 9일 화요일

TCP/IP 소켓 프로그래밍 6강

이번 강은 UDP에 관한 설명이다.
TCP는 신뢰성을 위해 계속 서로 체크해가며 제대로 데이터가 잘 갔는지
혹시 실패하면 재전송하면서 데이터 전송의 신뢰성을 높였다.
그러다보니 아무래도 속도면에서 좀 떨어지게 되었다.
그래서 속도를 높이기 위해 이 체크하는 과정을 없앤 방식이 UDP 방식이다.
체크하는 과정을 우아하게(?) "흐름제어"라고 할꺼다

UDP 1줄 요약: TCP에서 흐름제어가 빠진 프로토콜

이러고 끝내면 욕먹겠지 ㅡㅡ;;

UDP가 어디에 주로 쓰일까?? 속도가 중요한 영상 스트리밍, 음악 스트리밍에 주로 쓰인다.
IPTV를 보는데 느려서 끊긴다면 무지 빡칠 것이다.
하지만 가끔씩 화면 일부분만 살짝 깨지는 정도면 걍 넘어갈 것이다(물론 빡빡한 소비자들은 바로 전화해서 쌍욕을....)

UDP의 특징
1. UDP는 서버와 클라이언트가 연결되어 있지 않다.
2. UDP는 서버건 클라이언트건 하나의 소켓만 있으면 된다
3. UDP는 흐름 제어를 하지 않는다.

연결이 안되어 있는데 어찌 보낸다는거지?? 와이파이인가?? 라고 생각을 했었다 -_-;
실상은 그것이 아니다. 아예 데이터 패킷에 보낼 주소와 포트를 박아 넣어서 보내는 것이다.

TCP는 "전화기", UDP는 "편지"라고 생각하면 편하다.

전화기는 받을 때까지 죽어라 콜해서 받아야 음성 데이터가 전송된다
편지는 상대방 주소만 알면 일단 보낼 수는 있다.
하지만 받고 안받고는 받는 사람 상황이니 소실 될 수도 있다.

근데 이리 설명 했다고 전화가 편지보다 빠르잖아 우기면 아오 확
방식이 그렇다는 것이다.

UDP는 이미 주소를 알고 보내는 것이기에 별도로 상대방의 상태 체크를 하고 수락하고 하는 과정이 없기에 빠른 것이다.

UDP 기반의 데이터 입출력 함수를 보자.

#include <sys/socket.h>
ssize_t sendto(int sock, void *buff, size_t nbytes, int flags, struct sockaddr *to, socklen_t addrlen);
-sock : 데이터 전송에 사용될 UDP소켓의 파일 디스크립터를 인자로 전달
-buff : 전송할 데이터를 저장하고 있는 버퍼의 주소 값 전달
-nbytes : 전송할 데이터 크기를 바이트 단위로 전달
-flags : 옵션 지정에 사용되는 매개변수, 지정할 옵션이 없다면 0 전달
-to  : 목적지 주소정보를 담고 있는 sockaddr 구조체 변수의 주소 값 전달
-addrlen : 매개변수 to로 전달된 주소 값의 구조체 변수 크기 전달

 #include <sys/socket.h>
ssize_t recvfrom(int sock, void *buff, size_t nbytes, int flags, struct sockaddr *from, socklen_t *addrlen);
-sock : 데이터 수신에 사용될 UDP 소켓의 파일의 디스크립터를 인자로 전달
-buff : 데이터 수신에 사용될 버퍼의 주소 값 전달
-nbytres : 수신할 최대 바이트 수 전달, 때문에 매개변수 buff가 가리키는 버퍼의 크기를 넘을 수 없다.
-flags : 옵션 지정에 사용되는 매개변수, 지정할 옵션이 없다면 0 전달
-from : 발신지 정보를 채워 넣을 sockaddr 구조체 변수의 주소 값 전달
-addrlen : 매개변수 from으로 전달 된 주소에 해당하는 구조체 변수의 크기정보를 담고 있는 변수의 주소 값 전달

소스를 보자 (서버측) - UDP는 서버 개념이 없으나 서비스를 보내는 쪽을 서버라고 하자
(main 부분만 따왔다)

int main(int argc, char *argv[])
{
int serv_sock;
char message[BUF_SIZE];
int str_len;
socklen_t clnt_adr_sz;

struct sockaddr_in serv_adr, clnt_adr;
if(argc!=2){
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
//소켓 생성을 하는데 UDP를 쓰기 위해 SOCK_DGRAM로 설정했다.
serv_sock=socket(PF_INET, SOCK_DGRAM, 0);
if(serv_sock==-1)
error_handling("UDP socket creation error");
//설정 초기화 
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_adr.sin_port=htons(atoi(argv[1]));
//주소 할당
if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)
error_handling("bind() error");

while(1)
{
clnt_adr_sz=sizeof(clnt_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);
}
        //원래는 서버측 소켓 종료지만 바로 위가 무한 루프라 실행되지 않는다.
close(serv_sock);
return 0;
}

역시 소스는 색으로 구분해야 잘 보인다. 이런 툴이 나오길 기대한다 -_-;
너무 알록 달록 할라나? ㅎㅎ
이번엔 클라이언트 측 소스를 보자 역시 main부분만 볼 것이다.

int main(int argc, char *argv[])
{
int sock;
char message[BUF_SIZE];
int str_len;
socklen_t adr_sz;
struct sockaddr_in serv_adr, from_adr;
if(argc!=3){
printf("Usage : %s <IP> <port>\n", argv[0]);
exit(1);
}
//udp 소켁 생성
sock=socket(PF_INET, SOCK_DGRAM, 0);   
if(sock==-1)
error_handling("socket() error");
//설정 초기화
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
serv_adr.sin_port=htons(atoi(argv[2]));
while(1)
{
fputs("Insert message(q to quit): ", stdout);
fgets(message, sizeof(message), stdin);     
//q나 Q를 누르면 무한루프에서 빠져나옴
               if(!strcmp(message,"q\n") || !strcmp(message,"Q\n"))
break;
//서버로 송신
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;
printf("Message from server: %s", message);
}
        //클라이언트 소켓 연결 종료
close(sock);
return 0;
}

위의 소스가 거의 같다. 단지 종료 조건이 있을 뿐이다 ;;

단계 별로 보자
1. udp 소켓에 목적지의 ip/port 등록
2. 데이터 전송
3. udp 소켓에 등록된 목적지 정보 삭제

역시 소스를 다운받아 해보자
소스 다운 받기

7강은 소켓의 우아한(?) 연결 종료다. 이것 역시 공부가 끝난 다음에 요약 할 것이다 ㅎㅎ;;
하루에 1강은 올리려고 노력할 것이다.
참고로 이 책은 22강 ㄷㄷ
올해 안에 TCP/IP 소켓 프로그래밍 책 다 보는 것이 목표다.
내년 초에는 떨어진 조직응용기사 실기 공부를 해야한다 ㅠㅠ
10점차로 떨어졌으니 아깝게 떨어진 것도 아니다...;;

댓글 없음:

댓글 쓰기