• 初识linux socket编程


    csapp.h的配置

    在编译链接hex2dd.c时,报错 undefined reference to 'unix_error' collect2: error: ld returned 1 exit status
    于是我擅自把unix_error的内容拿出来写进hex2dd.c。而在dd2hex.c中,apt_error和unix_error两个函数都报错。
    我决定解决这个错误。通过生成动态库的方法:
    首先依次执行

    // 当前路径下有csapp.h和csapp.c
    gcc -shared -fpic -o libcsapp.so csapp.c -lpthread
    sudo mv libcsapp.so /usr/local/lib
    

    然后执行gcc dd2hex.c -o dd2hex -lcsapp并运行程序

    发现编译没有报错,而运行时报错了。这是由于运行时链接没有找到动态库。
    尝试来到/etc/ld.so.conf.d/下新建一个文件添加/usr/local/lib为寻找动态库的地址,发现已经有一个文件内含有这个地址

    执行sudo ldconfig更新ld.so.cache,然后即可成功运行。

    改变IP地址的表示形式

    十六进制转为点分十进制

    /*hex2dd.c*/
    #include"csapp.h"
    int main(int argc, char **argv)
    {
        struct in_addr inaddr;  // 网络字节序
        uint32_t addr;   // 主机字节序
        char buf[MAXBUF];   // 点分十进制
    
        if (argc != 2)
        {
            fprintf(stderr, "usage: %s <hex number>
    ", argv[0]);
            exit(0);
        }
        sscanf(argv[1], "%x", &addr);
        inaddr.s_addr = htonl(addr);
    
        if (!inet_ntop(AF_INET, &inaddr, buf, MAXBUF))
                fprintf(stderr, "%s: %s
    ", "inet_ntop", strerror(errno));
        printf("%s
    ", buf);
    
        exit(0);
    }
    

    编译命令:gcc hex2dd.c -o hex2dd(需要把csapp.h和csapp.c放在当前路径)
    运行效果:

    IP地址结构定义如下:

    /* Internet address.  */
    typedef uint32_t in_addr_t;
    struct in_addr
      {
        in_addr_t s_addr;
      };
    

    一个IP地址就是一个32位无符号整数,所以上述程序也可以改写成如下:

    /*hex2dd_1.c*/
    #include"csapp.h"
    int main(int argc, char **argv)
    {
        uint32_t inaddr;  // 网络字节序
        uint32_t addr;   // 主机字节序
        char buf[MAXBUF];   // 点分十进制
    
        if (argc != 2)
        {
            fprintf(stderr, "usage: %s <hex number>
    ", argv[0]);
            exit(0);
        }
        sscanf(argv[1], "%x", &addr);
        inaddr = htonl(addr);
    
        if (!inet_ntop(AF_INET, &inaddr, buf, MAXBUF))
                fprintf(stderr, "%s: %s
    ", "inet_ntop", strerror(errno));
        printf("%s
    ", buf);
    
        exit(0);
    }
    

    sscanf函数指定了输入源为argv[1],以16进制格式输入;

    #include<arpa/inet.b>
    uint32_t htonl(uint32_t hostlong);
    const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
    

    htonl函数把主机字节顺序转换为网络字节顺序;
    inet_ntop函数将十六进制转换为点分十进制。

    点分十进制转为十六进制

    /*dd2hex.c*/
    #include"csapp.h"
    int main(int argc, char **argv)
    {
        struct in_addr inaddr;
        int rc;
        uint32_t addr;
    
        if (argc != 2)
        {
            fprintf(stderr, "usage: %s <dotted-decimal>
    ", argv[0]);
            exit(0);
        }
    
        rc = inet_pton(AF_INET, argv[1], &inaddr);
        if (rc == 0)
            app_error("inet_pton error: invalid dotted-decimal address");
        else if (rc < 0)
            unix_error("inet_pton error");
        
        printf("0x%x
    ", ntohl(inaddr.s_addr));
        exit(0);
    }
    

    编译命令:gcc dd2hex.c -o dd2hex -lcsapp(提前配置好动态库)
    运行效果:

    #include <arpa/inet.h>
    uint32_t ntohl(uint32_t netlong);
    int inet_pton(int af, const char*src, void *dst);
    

    ntohl函数把网络字节序转换为主机字节序;
    inet_pton函数把点分十进制转换为十六进制。

    将域名转换为IP地址

    /*hostinfo.c*/
    #include "csapp.h"
     
    int main(int argc, char **argv)
    {
        struct addrinfo *p, *listp, hints;
        char buf[MAXLINE];
        int rc, flags;
    
        if (argc != 2)
        {
            fprintf(stderr, "usage: %s <domain name>
    ", argv[0]);
            exit(0);
        }
    
        memset(&hints, 0, sizeof(struct addrinfo));
        hints.ai_family = AF_INET;  // 查找32的IP地址
        hints.ai_socktype = SOCK_STREAM;    // 用作连接的端点
        if ((rc = getaddrinfo(argv[1], NULL, &hints, &listp)) != 0) // service设为NULL
        {
            fprintf(stderr, "getaddrinfo error: %s
    ", gai_strerror(rc));
            exit(1);
        }
    
        flags = NI_NUMERICHOST;
        for (p = listp; p; p = p->ai_next)
        {
            getnameinfo(p->ai_addr, p->ai_addrlen, buf, MAXLINE, NULL, 0, flags);
            printf("%s
    ", buf);
        }
    
        freeaddrinfo(listp);
    
        exit(0);
    }
    

    运行效果:

    /* Structure to contain information about address of a service provider.  */
    struct addrinfo
    {
      int ai_flags;			/* Input flags.  */
      int ai_family;		/* Protocol family for socket.  */
      int ai_socktype;		/* Socket type.  */
      int ai_protocol;		/* Protocol for socket.  */
      socklen_t ai_addrlen;		/* Length of socket address.  */
      struct sockaddr *ai_addr;	/* Socket address for socket.  */
      char *ai_canonname;		/* Canonical name for service location.  */
      struct addrinfo *ai_next;	/* Pointer to next in list.  */
    };
    
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<netdb.h>
    int getaddrinfo(const char *host, const char *service, const struct addrinfo *hints,
                    struct addrinfo **res);
    void freeaddrinfo(struct addrinfo *res);
    const char *gai_strerror(int errcode);
    

    getaddrinfo的host参数可以是域名也可以是数字地址,service参数可以是服务名也可以是十进制端口号。必须指定两者中至少一个。通过hints参数设置个别字段,ai_family设置为AF_INET会将列表限制为IPv4地址,设置为AF_INET6则限制为IPv6地址;ai_socketype设置为SOCK_STREAM将列表限制为对每个地址最多一个addrinfo结构;返回result,result是一个指向addrinfo结构的链表,其中每个结构指向一个对应于host和service的套接字地址结构。

    参考

    深入理解计算机系统(原书第3版)
    csapp.h头文件的使用 ---- 3种方法运行《深入理解计算机系统》中的代码
    Linux动态库的查找路径

  • 相关阅读:
    如何掌握所有的程序语言
    程序与证明
    卫星通信地面系统构成
    SCIP 环境搭建
    Homebrew install.sh
    macOS 内核之从 I/O Kit 电量管理开始
    matlab练习程序(空间椭圆拟合)
    多进程抢票加锁
    进程间数据传递
    队列用法
  • 原文地址:https://www.cnblogs.com/hardcoreYutian/p/14128487.html
Copyright © 2020-2023  润新知