zoukankan      html  css  js  c++  java
  • [第四版]用getaddrinfo设置tcp基本连接属性

    getaddrinfo

    getaddrinfo的一个重要功能, 很方便的构造struct sockaddr_in对象, 把繁琐的构造过程隐藏起来
    getaddrinfo兼有gethostbyname和getservbyname等四个函数的功能
    能传入ip/port, hostname/port, ip/service, hostname/service的组合
    如127.0.0.1/13, www.abc.com/80, 127.0.0.1/daytime

    #include <netdb.h>
    /* 成功返回0, 出错返回非0 */
    int getaddrinfo(const char *hostname,const char *service,
            const struct addrinfo *hints, struct addrinfo **result);
    
    struct addrinfo{
        int ai_flags; /* AI_PASSIVE(用于server的bind), AI_CANONNAME(返回主机名www.abc.com) */
        int ai_family; /* AF_INET, AF_INET6, AF_UNSPEC*/
        int ai_socktype; /* SOCK_STREAM, SOCK_DGRAM */
        int ai_protocol; /* IPPROTO_[IP/IPV4/IPV6/UDP/TCP] */
     
        socklen_t ai_addrlen;  /* 下面ai_addr结构的长度 */
        char *ai_canonname; /* ai_flags选项返回的主机名 */
        struct sockaddr *ai_addr; /* 返回地址结构, 可直接用于connect函数 */
        struct addrinfo *ai_next; /* 当查询的主机存在多个地址时通过ai_next来遍历 */
    }
    

    hostname和serice就是上面讲的组合
    hints是过滤条件, 这些过滤条件放在一个addrinfo的结构里, 通常用前四个成员作为过滤选项
    result是过滤的结果, 也是存储在addrinfo结构里, 如果存在多个匹配项, 可通过ai_next来遍历

    const char *gai_strerror(int error);
    

    效果同error, 传入错误号返回字符串错误信息
    不同的是gai_strerror传入的error是函数的返回值, 而不是全局变量errno

    void freeaddrinfo(struct addrinfo *ai);
    

    getaddrinfo的返回值是一个指针, 指向由系统malloc的内存区, 所以不用的时间需要freeaddrinfo

    client

    启动步骤:
    先服务端 ./server13 或者 ./server 0::0 13
    然后客户端 ./client 127.0.0.1 13 或者 ./client 0::0 13

    #include "unp.h"
    #include <netdb.h>
    int tcp_connect(const char *host,const char *serv){
        int sockfd,n;
        struct addrinfo hints,*res,*ressave;
        bzero(&hints,sizeof(struct addrinfo));
        hints.ai_family=AF_UNSPEC;
        hints.ai_socktype=SOCK_STREAM;
        if((n=getaddrinfo(host,serv,&hints,&res)) != 0)
            err_quit("tcp_connect error for %s, %s: %s",
                    host,serv,gai_strerror(n));
        ressave=res;
        do{
            sockfd=socket(res->ai_family,res->ai_socktype,res->ai_protocol);
            if(sockfd < 0)
                continue;
            if(connect(sockfd,res->ai_addr,res->ai_addrlen) == 0)
                break;
            Close(sockfd);
        }while((res=res->ai_next) != NULL);
        if(res == NULL)
            err_quit("tcp_connect error for %s, %s",host,serv);
        freeaddrinfo(ressave);
        return(sockfd);
    }
     
    int main(int argc, char *argv[]){
        int sockfd,n;
        char recvline[MAXLINE+1];  
        socklen_t len;
        struct sockaddr_in addr;
     
        if(argc != 3)
            err_quit("usage: %s <www/ip> <http/80>",argv[0]);
     
        sockfd=tcp_connect(argv[1],argv[2]);
     
        len=sizeof(addr);
        getpeername(sockfd,(struct sockaddr *)&addr,&len);
        printf("connected to %s
    ",sock_ntop((struct sockaddr *)&addr,len));
     
        while((n=Read(sockfd,recvline,MAXLINE)) >0){
            recvline[n]=0;
            Fputs(recvline,stdout);
        }
        return 0;
    }
    

    server

    #include "unp.h"
    #include <netdb.h>
    #include <time.h>
     
    int tcp_listen(const char *host,const char *service,socklen_t *addrlenp){
        int listenfd,n;
        const int on=1;
        struct addrinfo hints, *res,*ressave;
     
        bzero(&hints,sizeof(struct addrinfo));
        hints.ai_flags=AI_PASSIVE;
        hints.ai_family=AF_UNSPEC;
        hints.ai_socktype=SOCK_STREAM;
     
        if((n=getaddrinfo(host,service,&hints,&res)) != 0)
            err_quit("tcp_listen error for %s, %s: %s",host,service,gai_strerror(n));
        ressave=res;
     
        do{
            listenfd=socket(res->ai_family,res->ai_socktype,res->ai_protocol);
            if(listenfd < 0)
                continue;
     
            setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
            if(bind(listenfd,res->ai_addr,res->ai_addrlen) == 0)
                break;
     
            Close(listenfd);
        }while((res=res->ai_next) != NULL);
     
        if(res == NULL)
            err_quit("tcp_listen error for %s, %s",host,service);
     
        Listen(listenfd,10);
     
        if(addrlenp)
            *addrlenp=res->ai_addrlen;
     
        freeaddrinfo(ressave);
     
        return(listenfd);
    }
    int main(int argc, char *argv[]){
        int listenfd,connfd;
        socklen_t len;
        struct sockaddr_in cliaddr;
        char buff[MAXLINE];
        time_t ticks;
     
       if(argc == 2)
            listenfd=tcp_listen(NULL,argv[1],NULL);
        else if(argc == 3)
            listenfd=tcp_listen(argv[1],argv[2],NULL);
        else
            err_quit("usage: %s [<host>] <service/port>",argv[0]);
     
        for(;;){
            len=sizeof(cliaddr);
            connfd=Accept(listenfd,(struct sockaddr *)&cliaddr,&len);
            printf("connection from %s
    ",sock_ntop((struct sockaddr *)&cliaddr,len));
     
            ticks=time(NULL);
            snprintf(buff,sizeof(buff),"%.24s
    ",ctime(&ticks));
            Write(connfd,buff,strlen(buff));
     
            Close(connfd);
        }
    }
    
  • 相关阅读:
    JuiceSSH:安卓平台免费好用的 SSH 客户端
    git&github-本地库推送到远程库
    git&githib-给远程库取别名
    Git分支管理的本质
    MySQL学习笔记(一)--逻辑架构学习
    mysql-主从备份问题小结
    Docker--数据管理之Volumes
    初识OpenSSH--1
    一个最简单的Dockfile实践
    构词法2
  • 原文地址:https://www.cnblogs.com/cfans1993/p/6131888.html
Copyright © 2011-2022 走看看