ddingz 2022. 1. 5. 13:06

포트번호는 TCP 소켓인 경우는 connect() 호출이 성공한 후에, UDP 소켓의 경우는 첫 번째 메시지를 보내는 sendto() 함수가 성공한 후에 배정된다.
아래는 이것을 확인하는 예제 프로그램인데 TCP와 UDP 클라이언트에서 시스템이 배정한 포트번호를 getsockname()을 이용하여 얻은 후 화면에 출력하고 있다.
참고로 getsockname()은 자신의 호스트에 있는 소켓 정보를 알아내는 함수인데 TCP로 연결된 상대방의 소켓 정보를 얻으려면 getpeername()을 사용하면 된다.


port_number.c

port_number.c가 실행되기 위해서는 서버에서 TCP 및 UDP 에코 서비스가 동작하고 있어야 한다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

#define MSG "Test Message"

int main(void) {
    int sd1, sd2;
    int addrlen;
    struct sockaddr_in servaddr, cliaddr; // 소켓주소 구조체
    unsigned short port1, port2; // 포트번호

    // 소켓주소 구조체 초기화
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(7);

    sd1 = socket(PF_INET, SOCK_STREAM, 0);
    sd2 = socket(PF_INET, SOCK_DGRAM, 0);

    // TCP 소켓의 포트번호 얻기
    if (connect(sd1, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
        perror("connect fail");
        exit(1);
    }
    getsockname(sd1, (struct sockaddr *)&cliaddr, &addrlen);
    port1 = ntohs(cliaddr.sin_port);

    // UDP 소켓의 포트번호 얻기
    sendto(sd2, MSG, strlen(MSG), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
    getsockname(sd2, (struct sockaddr*)&cliaddr, &addrlen);
    port2 = ntohs(cliaddr.sin_port);

    printf("스트림 소켓 포트번호 = %d\n", port1);
    printf("데이터그램 소켓 포트번호 = %d\n", port2);

    close(sd1);
    close(sd2);

    return 0;
}

실행 결과

./port_number
스트림 소켓 포트번호 = 58895
데이터그램 소켓 포트번호 = 32771