UDP 네트워크 프로그래밍 - 1

2019. 7. 21. 13:55드론

https://os.mbed.com/handbook/Socket

 

UDP 프로토콜은 데이터 전송 시 신뢰성은 없지만 속도가 빠르기 때문에 일반적인 근거리 LAN 환경에서 많이 사용된다. BSD 소켓 함수에서 socket 함수의 인자로 SOCK_DGRAM 옵션을 통해 설정할 수 있다. 일반적으로 UDP 서버와 클라이언트는 sendto() 함수를 통해 메세지를 전달하고, recvfrom() 함수를 통해 수신하게 된다. 그리고 사용이 끝나면 close로 닫아주게 된다. UDP 서버와 클라이언트 구조는 위와 같이 비슷하지만, 서버는 특정 포트를 바인딩해야 하는 특징이 있다

 

참고로 클라이언트는 일반적으로 포트를 바인딩하지 않는다. 바인딩은 특정 포트로 데이터가 들어오면 해당 어플리케이션에게 데이터를 전달할 수 있도록 운영체제에게 알리는 것이다. 클라이언트가 서버와의 통신을 시도할 때 자동으로 포트 번호를 지정하며, 이 번호는 서버와 통신하는 동안만 유효한 임시 번호다. 반면, 서버는 항상 클라이언트의 요청에 응답해야 하므로 커널에 포트 번호를 등록해서, 실행되는 동안 고정된 포트 번호를 갖는다

 

bind() 함수는 쉽게 말해서 클라이언트가 서비스에 잘 찾아올 수 있도록 소켓에 addr을 부여하는 것이다. 클라이언트로부터 들어오는 서비스를 현재의 애플리케이션이 사용할 수 있도록 운영체제에게 알려주는 것이다. bind 함수는 UDP뿐만 아니라 TCP 서버에서도 사용된다

 

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

 

bind 함수는 다음과 같이 구성되어 있다. socket 함수를 통해 반환된 파일 디스크립터 값을 넣어주며, const struct sockaddr은 IP 주소와 포트번호에 대한 값을 설정한다. struct sockaddr은 여러 종류가 있는데 그 중 인터넷 주소를 위한 소켓 구조체인 struct sockaddr_in을 살펴보면 다음과 같다. 만일 IPC를 위해서라면 struct socketaddr_un을 사용하게 되는데 이때 컴파일 오류를 방지하기 위해 반드시 (struct sockaddr *)로 casting을 해야만 한다

 

 

서버의 주소같은 경우에는 서버의 주소를 기입하면 되는데, 자주 IP가 변경되는 환경에서는 INADDR_ANY를 사용하면 자동으로 서버의 주소를 채워준다. 포트 번호의 경우 TELNET이나 웹과 같은 기본 서비스를 제공하는 서버를 만들지 않는다면, 잘 알려진 포트 번호를 피한다. 일반적으로 5000번 이후의 포트 번호를 많이 사용하게 된다

 

그리고 이전에 유닉스에서 인터넷 통신을 하기 위해서는 먼저 소켓을 생성해야 하는데, socket 함수를 사용한다. 호출에 성공하면 파일 디스크립터를 반환한다

 

http://man7.org/linux/man-pages/man2/socket.2.html

 

첫 번째 인자는 domain으로 통신 방식을 넣어주게 된다. 인터넷으로 통신할 것인지, 내부적인 파일 시스템을 이용해서인지 결정하게 된다

 

 

많은 도메인 방식이 명시되어 있는데, 처음에는 빨간색 박스를 유의해서 보면 좋을 것 같다. AF_UNIX는 IPC를 socket 함수를 통해서 하는 방식이고, AF_INET은 IPv4 인터넷 프로토콜을 사용하는 통신 방식을 의미하게 된다

 

 

그 다음은 전송 계층을 정의하는 type 부분이다. 일반적으로 SOCK_STREAM 혹은 SOCK_DGRAM을 많이 사용한다. 이들은 각각 전송 계층에서 TCP와 UDP를 의미하게 된다. SOCK_RAW는 IP를 직접 이용하거나, 직접 프로토콜을 만들 때 사용할 수 있는 소켓이다

 

마지막 인자인 protocol은 네트워크 프로토콜을 의미하는데, 보통 0의 값을 사용한다. 예전에는 다양한 프로토콜들이 사용됐는데 최근에는 TCP/IP로 주로 통합되어서 사용되기 때문에 더 이상 큰 의미가 없다