티스토리 뷰

안녕하세요.

신랑 각시의 신랑 입니다.


이번에는 IPv6 관련한 Socket Client 를 작성해 보겠습니다.

이번 목적은 주어진 IP 가 IPv4 표현이든, IPv6 표현이든 모두 수용 가능한 Client 만드는 것이 목적입니다.


socket 을 만들 때, getaddrinfo() 함수를 호출하여 적절한 struct addrinfo 값을 얻어오고, 해당 구조체를 가지고 connect() 을 한다. 라고 요약할 수 있겠습니다.


이전 포스팅으로 적어 둔 echo server 와 통신할 client 입니다.


#include 
#include 
#include 
#include 

#include 
#include 
#include 

std::string GetPeerInfo(struct sockaddr * _addr, socklen_t _addrlen) {

    char hostname[256];
    char svcname[64];

    if(getnameinfo(_addr,
                    _addrlen,
                    hostname,
                    sizeof(hostname),
                    svcname,
                    sizeof(svcname),
                    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
        char buf[128];
        std::cout << "getnameinfo() - fail " << errno << ":" <<  strerror_r(errno, buf, sizeof(buf));
        std::cout << std::endl;
        return "";

    }
    return std::string(hostname) + ":" + svcname;
}

void doClient(int _sock) {
    char buf[32];
    sprintf(buf, "I am Happy !");

    if(send(_sock, buf, strlen(buf), 0) < 0) {
        std::cout << "[CLIENT] send() fail : " << strerror(errno) << std::endl;
        close(_sock);
        return ;
    }
    std::cout << "[CLIENT] send : " << buf << std::endl;

    if(recv(_sock, buf, strlen(buf), 0) <= 0) {
        std::cout << "[CLIENT] recv() fail : " << strerror(errno) << std::endl;
        close(_sock);
        return ;
    }
    std::cout << "[CLIENT] recv : " << buf << std::endl;

    close(_sock);
    std::cout << "[CLIENT] Bye" << std::endl;
}

void clientDual(char * _ip, char * _port) {
    std::cout << "[CLIENT] IPv4-IPv6 Dual Mode" << std::endl;

    struct addrinfo   hints;
    memset(&hints, 0, sizeof(hints));

    hints.ai_flags = AI_NUMERICSERV;
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;

    struct addrinfo * res;

    int ret = getaddrinfo(_ip, _port, &hints, &res);
    if(ret != 0) {
        std::cout << "getaddrinfo: " << gai_strerror(ret) << std::endl;
        return ;
    }

    int sfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if(sfd < 0) {
        std::cout << "socket() fail :" << strerror(errno) << std::endl;
        freeaddrinfo(res);

        return ;
    }

    if(connect(sfd, res->ai_addr, res->ai_addrlen) < 0) {
        std::cout << "connect() fail :" << strerror(errno) << std::endl;
        close(sfd);
        freeaddrinfo(res);

        return ;
    }

    std::cout << "[CLIENT] SERVER INFO : "
              << GetPeerInfo(res->ai_addr, res->ai_addrlen) << std::endl;
    freeaddrinfo(res);
    doClient(sfd);
}

int main(int argc, char * argv[]) {

    if(argc != 3) {

        std::cout << "invalid argument" << std::endl;
        std::cout << "ex) clientDual [ip] [port]" << std::endl;
        return 0;
    }
    clientDual(argv[1], argv[2]);
    return 0;
}


아래는 컴파일을 위한 명령 입니다.


g++ -o cdual clientDual.cpp -std=c++11

댓글