본문 바로가기
Computer Science/UNIX & Linux

[UNIX/Linux] ep11-4) UDP 소켓 프로그래밍

by 클레어몬트 2024. 12. 11.

https://claremont.tistory.com/entry/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-IPCInter-Process-Communication

[운영체제] IPC(Inter-Process Communication)

https://claremont.tistory.com/entry/ep2-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4process [운영체제] ep2) 프로세스(process)ㅁ프로세스(process): 실행 중인 프로그램 (실행/스케줄링의 단위 및 자료구조)보조기억장치에 저장

claremont.tistory.com

https://claremont.tistory.com/entry/UNIXLinux-ep11-1-%EC%86%8C%EC%BC%93-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%B4%88

[UNIX/Linux] ep11-1) 소켓 프로그래밍 기초

https://claremont.tistory.com/entry/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-IPCInter-Process-Communication [운영체제] IPC(Inter-Process Communication)https://claremont.tistory.com/entry/ep2-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4process [운영체제] ep2)

claremont.tistory.com

https://claremont.tistory.com/entry/UNIXLinux-ep11-2-%EC%86%8C%EC%BC%93-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%ED%95%A8%EC%88%98

[UNIX/Linux] ep11-2) 소켓 프로그래밍 함수

https://claremont.tistory.com/entry/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-IPCInter-Process-Communication [운영체제] IPC(Inter-Process Communication)https://claremont.tistory.com/entry/ep2-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4process [운영체제] ep2)

claremont.tistory.com

https://claremont.tistory.com/entry/UNIXLinux-ep11-3-TCP-%EC%86%8C%EC%BC%93-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D

[UNIX/Linux] ep11-3) TCP 소켓 프로그래밍

https://claremont.tistory.com/entry/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-IPCInter-Process-Communication [운영체제] IPC(Inter-Process Communication)https://claremont.tistory.com/entry/ep2-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4process [운영체제] ep2)

claremont.tistory.com

 
"UDP라고 다를 거 없다"
앞에서 배운 TCP 소켓 프로그래밍과 원리가 동일하다!
 
[TCP 소켓 프로그래밍]
 send( ) : 데이터 송신(SOCK_STREAM)
 recv( ) : 데이터 수신(SOCK_STREAM)
 
[UDP 소켓 프로그래밍]
 sendto( ) : 데이터 송신(SOCK_DGRAM)
 recvfrom( ) : 데이터 수신(SOCK_DGRAM)
 
※ UDP에서는 클라이언트 측에서 connect() 함수를 사용할 필요가 없다
UDP는 연결지향(connectionless) 프로토콜로, 데이터그램을 목적지로 바로 보내거나 받을 수 있다. 따라서 서버와의 "연결"을 설정할 필요가 없다. 대신, 데이터를 보내거나 받을 때마다 sendto()와 recvfrom() 함수에서 목적지 정보를 명시한다.
 
따라서 connect()는 TCP에서 연결을 설정하는 데 필수이지만, UDP에서는 선택적이다.
(UDP에서도 connect()를 호출할 수 있지만, 호출해도 물리적인 연결이 생성되지 않고 소켓에 기본 송신/수신 대상이 설정될 뿐이다.)
 
 
(server1.c)

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PORTNUM 9005

int main() {
    char buf[256];
    struct sockaddr_in sin, cli;
    int sd, clientlen = sizeof(cli);
    
    // 인터넷 소켓을 사용하는 소켓을 생성
    // 통신 방식은 SOCK_ DGRAM 으로 지정해 UDP를 사용하도록 함
    if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }
    
    // 소켓 주소 구조체를 초기화하고 포트 번호와 서버의 주소를 설정
    memset((char*)&sin, '\0', sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORTNUM);
    sin.sin_addr.s_addr = inet_addr("192.168.147.129");
    
    // 위에서 생성한 소켓을 bind() 함수를 사용해 바로 위에서 설정한 IP 주소/포트 번호와 연결
    if (bind(sd, (struct sockaddr*)&sin, sizeof(sin))) {
        perror("bind");
        exit(1);
    }
    
    // recvfrom() 함수를 호출해 클라이언트에서 오는 메시지를 받음
    while (1) {
        // recvfrom() 함수는 메시지를 보낸 클라이언트의 주소도 함께 알려주므로
        // 이 주소를 사용해 클라이언트로 메시지를 보낼 수 있음
        if ((recvfrom(sd, buf, 255, 0, (struct sockaddr*)&cli, &clientlen)) == -1) {
            perror("recvfrom");
            exit(1);
        }
        printf("** From Client : %s\n", buf);
        
        // 클라이언트로 간단한 메시지를 전송, sendto() 함수에는 목적지 주소를 인자로 지정해야 함
        strcpy(buf, "Hello Client");
        if ((sendto(sd, buf, strlen(buf) + 1, 0, (struct sockaddr*)&cli, sizeof(cli))) == -1) {
            perror("sendto");
            exit(1);
        }
    }
    
    return 0;
}

 
(client1.c)

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PORTNUM 9005

int main() {
    int sd, n;
    char buf[256];
    struct sockaddr_in sin;
    
    // 소켓을 생성 (TCP 기반 프로그램과 달리 connect() 함수를 호출하지 않음)
    if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }
    
    // 서버의 포트 번호와 IP 주소를 소켓 주소 구조체에 설정
    memset((char*)&sin, '\0', sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORTNUM);
    sin.sin_addr.s_addr = inet_addr("192.168.147.129");
    
    // sendto() 함수를 호출해 메시지를 서버로 전송
    strcpy(buf, "I am a client.");
    if (sendto(sd, buf, strlen(buf) + 1, 0, (struct sockaddr*)&sin, sizeof(sin)) == -1) {
        perror("sendto");
        exit(1);
    }
    
    // 서버에서 전송한 응답 메시지를 recvfrom() 함수로 읽어 출력
    n = recvfrom(sd, buf, sizeof(buf), 0, NULL, NULL);
    buf[n] = '\0';
    printf("** From Server : %s\n", buf);
    
    return 0;
}
// 실행 결과: 서버와 클라이언트가 메시지를 주고받았음을 알 수 있음

 
 
 
 
 
 
참고 및 출처: 시스템 프로그래밍 리눅스&유닉스(이종원)