ddingz 2022. 1. 3. 16:47

mydaytime.c

유닉스 서버가 제공하는 daytime 서비스를 이용하는 클라이언트 프로그램이다.

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

#define MAXLINE 127

int main(int argc, char *argv[]) {
    int s, nbyte;
    struct sockaddr_in servaddr;
    char buf[MAXLINE + 1];

    if (argc != 2) {
        printf("Usage: %s ip_address\n", argv[0]);
        exit(0);
    }

    // 소켓 생성
    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket fail");
        exit(1);
    }

    // 서버의 소켓주소 구조체 servaddr을 '\0'으로 초기화
    bzero((char *)&servaddr, sizeof(servaddr));

    // servaddr의 주소 지정
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
    servaddr.sin_port = htons(13);

    // 연결요청
    if (connect(s, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
        perror("connect fail");
        exit(1);
    }

    // 서버가 보내오는 daytime 데이터의 수신 및 화면출력
    if ((nbyte = read(s, buf, MAXLINE)) < 0) {
        perror("read fail");
        exit(1);
    }
    buf[nbyte] = 0;
    printf("%s", buf);

    close(s);

    return 0;
}

mydaytime.c에서는 사용할 소켓을 아래와 같이 개설하는데, 프로토콜 체계로는 인터넷을, 서비스는 연결형(TCP)을 지정하고 있다.

s = socket(PF_INET, SOCK_STREAM, 0);

다음에는 연결할 서버의 소켓주소 구조체를 만들어야 하는데 주소 체계를 인터넷(AF_INET)으로 지정하고 서버의 IP 주소와 포트번호를 소켓주소 구조체 sever_addr에 기록하였다.

struct sockaddr_in servaddr; // 서버의 소켓주소 구조체
servaddr.sin_family = AF_INET; // 주소 체계 선택
inet_pton(AF_INET, argv[1], &servaddr.sin_addr); // 32비트 IP 주소로 변환
servaddr.sin_port = htons(13); // daytime 서비스 포트번호

위에서 inet_pton() 함수는 사용자가 명령 인자로 입력한 dotted decimal 형태의 IP 주소 문자열 argv[1]을 32비트 IP 주소로 변환하는 함수이다.
daytime 서비스를 받기 위하여 well-known 포트번호 13번을 지정하였다.
이상과 같이 서버의 주소 정보를 모두 servaddr 구조체에 기록한 다음에는 서버에 연결을 요청하기 위해 connect() 함수를 다음과 같이 호출한다.

connect(s, (struct sockaddr *)&servaddr, sizeof(servaddr));

서버와 연결된 후, 서버가 보내오는 문자열(날짜와 시간)을 수신하기 위해 클라이언트는 read()를 아래와 같이 호출하는데, 소켓을 통한 입출력도 파일 입출력과 유사하게 이루어지는 것을 알 수 있다.

n = read(s, buf, sizeof(buf)); // recv(s, buf, sizeof(buf), 0)도 같은 동작을 한다.

실행 결과

mydaytime.c을 실행시켰을 때 아래와 같은 에러 메시지가 출력되는 경우가 있다.

이것은 목적지 호스트에서 (주로 보안상의 이유로) daytime 서비스를 제공하지 않기 때문이다.
즉, 13번 포트가 비활성 상태이므로 연결이 거부된 것이다.
로컬 호스트에서 daytime 서비스를 하고 있다면 아래와 같이 출력될 것이다.

./mydaytime 127.0.0.1
Mon Jan 3 16:14:00 2022