《Unix环境高级编程》读书笔记之套接字(二)

  1. 获得网络名字和网络编号:读的数据库文件是 /etc/networks

    
    #include <netdb.h>
    
    struct netent * getnetent(void);
    • 功能:从网络数据库文件读下一个网络入口,并返回;

    • 网络号按网络字节序返回。地址类型为 AF_XX 的地址族常量。

    • 结构体:

      struct netent{
          char      *n_name;     /* 网络名 */
          char     **n_aliases;  /* 网络别名列表 */
          int        n_addrtype; /* 网络地址类型,通常是AF_INET */
          uint32_t   n_net;      /* 主机字节序的网络号 */
      };
    • 返回值:

      • 成功:返回结构体指针;

      • 失败或者到达文件尾: 返回空指针,并且设置errno。

        
        #include <netdb.h>
        
        struct netent * getnetbyname(const char* name);
    • 功能:从数据库文件读与网络名匹配一个结构体,并返回。

    • 网络号按网络字节序返回。地址类型为 AF_XX 的地址族常量。

    • 返回值:

      • 成功:返回结构体指针;

      • 失败或者到达文件尾: 返回空指针,并且设置errno。
        “`c

    include

    #include <neydb.h>
    void setservnet(int stayopen);
    void endservnet(void);
+ 功能:

    + `setservnet`打开与数据库的连接,并且设置下一个入口为第一个入口。如果`stayopen`是非0的话,在调用`getnet*`函数之前,与数据库的连接不会关闭。

    + `endservnet`关闭与数据库的连接。
  1. 将主机名(IP地址)和服务名(端口)映射到一个struct sockaddr地址结构

    
    #include <sys/types.h>
    
    
    #include <sys/socket.h>
    
    
    #include <netdb.h>
    
    int getaddrinfo(const char *node, const char *service,const struct addrinfo *hints, struct addrinfo **res);
    • 功能:给定主机名(IP地址)、服务名(端口号),返回一个或者多个struct addrinfo结构体,到res中。主要是得到一个struct sockaddr的地址。

      • 主机名可以是主机名字或者点分格式的主机地址。可以同时提供主机名和服务名,或者只提供其中一者,那么另外一个就是空指针。

      • 如果是服务端,可以只指定端口号,不指定IP地址,但是ai_flags要设置成AI_PASSIVE,此时服务端地址是0.0.0.0;

      • +
    • addrinfo结构体:链表结构

      struct addrinfo{
          int              ai_flags;   /* 表示如何处理地址和名字,多个可以相或 */
          int              ai_family;  /* 地址类型(域),0表示任意类型都可以 */
          int              ai_socktype;/* 套接字类型,0表示任意类型都可以 */
          int              ai_protocol;/* 协议(号),0表示任意协议都可以 */
          socklen_t        ai_addrlen; /* 地址长度 */
          struct sockaddr *ai_addr;    /* 套接字地址 */
          char            *ai_canonname;/* 主机规范名 */
          struct addrinfo *ai_next;    /* 链表下一个指针 */
      };
      • ai_flags

        • AI_ADDRCONFIG :查询配置的地址类型(IPv4或IPv6)。

        • AI_ALL :查找IPv4和IPv6地址,仅用于 AI_V4MAPPED 。

        • AI_CANONNAME :需要一个规范名而不是别名。

        • AI_NUMERICHOST :以数字格式返回主机地址。

        • AI_NUMERICSERV :以端口号返回服务。

        • AI_PASSIVE :套接字地址用于监听绑定。

        • AI_V4MAPPED :如果没找到IPv6地址,返回映射到IPv6格式的IPv4地址。

    • 参数:

      • node:主机名,可以是一个名字,也可以是点格式的字符串地址。当使用名字的时候,这个名字必须在/etc/hosts文件里面有对应的地址,如下面hosts的内容,使用127.0.1.1 和使用Ubuntu14是一样的。实际上就是制定地址。

        127.0.0.1 localhost
        127.0.1.1 Ubuntu14
        
        # The following lines are desirable for IPv6 capable hosts
        
        ::1     ip6-localhost ip6-loopback
        fe00::0 ip6-localnet
        ff00::0 ip6-mcastprefix
        ff02::1 ip6-allnodes
        ff02::2 ip6-allrouters
        ff02::3 ip6-allhosts
      • service:指定的服务,实际上就是端口。在文件/etc/services里面记录了服务名,端口号以及其协议的对应关系。

        • 如果要指定服务名,则可以在services文件里面添加需要的服务名,端口号,协议。

        • 也可以直接写字符串的端口号。

      • hints:用来筛选符合特定条件的地址,hints是一个用来过滤的模板,除了ai_family, ai_flags, ai_protocol, ai_socktype可以设定之外其他的都设置为0或者空指针。

    • 返回值:

      • 成功返回0

      • 失败返回非0错误码。

        
        #include <sys/types.h>
        
        
        #include <sys/socket.h>
        
        
        #include <netdb.h>   
        
        void freeaddrinfo(struct addrinfo *res);
        const char *gai_strerror(int error); 
    • freeaddrinfo:释放addrinfo结构;

    • gai_strerror:将getaddrinfo的错误码转换成为错误消息。

      
      #include <sys/socket.h>
      
      
      #include <netdb.h>
      
      int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char* serv, size_t servlen, int flags);
    • 功能:将套接字地址转换成为一个主机名和一个服务名。

    • 参数:

      • flags指定一些转换的方式:

        • NI_DGRAM :服务基于数据报(UDP)而非基于流(TCP)。

        • NI_NAMEREQD :如果找不到主机名,将其视作错误。

        • NI_NOFQDN :对于本地主机,仅返回完全限定域名的节点名部分。

        • NI_NUMERICHOST :以数字形式返回主机地址。

        • NI_NUMERICSERV :以端口号返回服务地址。

    • 返回值:

      • 成功返回0

      • 失败返回非0错误码。

  2. 套接字与地址关联(绑定地址):

    
    #include <sys/socket.h>
    
    int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
    • 功能:给本地没有分配套接字地址的套接字分配一个本地套接字地址。

    • 参数:

      • sockfd:套接字描述符,由socket()创建,仅仅确定了域和套接字类型,以及协议。

      • addr:套接字地址指针,指向结构体struct sockaddr,长度个格式取决于所使用的address family。对于地址,要求:

        • 地址必须有效,不能指定其他机器的地址。

        • 地址必须和套接字的地址族所支持的格式匹配。

        • 如果不是超级用户,端口号不能小于1024。

        • 一般只一个套接字端点能够和一个地址绑定,也有协议允许多重绑定。

      • len:地址长度

    • 返回值:

      • 成功: 返回0;

      • 失败: 返回-1,设置errno;

    • 对于因特网域,如果指定IP地址为 INADDR_ANY(<netinnet/in.h>) ,套接字端点可以被绑定到所有的系统网络接口,这样它可以收到这个系统的所有网卡的数据包。

      
      #include <sys/socket.h>
      
      int getsockname(int socket, struct socksddr *restrict address, socklen_t *restrict address_len);
    • 功能:通过套接字描述符得到与套接字绑定的地址;

    • 参数:

      • socket:如果该套接字没有绑定地址,结果是未定义的。

      • address:存储套接字地址的指针;

      • sddress_len:用户指定的套接字地址结构体大小,如果指定大小比实际的地址长度小,则会发生截断,但是不会报错。

    • 返回值:

      • 成功: 返回0;

      • 失败: 返回-1,设置errno;

        
        #include <sys/socket.h>
        
        int getpeername(int socket, struct socksddr *restrict address, socklen_t *restrict address_len);
    • 功能:通过与本进程连接的套接字描述符(对等方套接字描述符)得到与套接字绑定的地址;

    • 参数:

      • socket:如果该套接字没有绑定地址,结果是未定义的。

      • address:存储套接字地址的指针;

      • sddress_len:用户指定的套接字地址结构体大小,如果指定大小比实际的地址长度小,则会发生截断,但是不会报错。

    • 返回值:

      • 成功: 返回0;

      • 失败: 返回-1,设置errno;

  3. 建立连接:主要针对面向连接的传输协议,如(SOCK_STREAM和SOCK_SEQPACKET)

    • 面向连接的传输协议,在交换数据之前需要建立连接(如TCP);

      
      #include <sys/socket.h>
      
      int connect(int socket, const struct sockaddr *address, socklen_t address_len);
    • 功能:有客户端发起连接请求,并尝试把本地套接字与服务器的地址建立连接。

    • 参数:

      • socket:客户端套接字;

        • 如果套接字没有和一个地址绑定,connect会给绑定一个本地未用的地址

        • 如果套接字是面向连接的,connect会尝试建立一个连接。如果连接不能立即建立:

          • socket没有设置了O_NONBLOCKconnect会阻塞一个不确定的时长,直到连接建立。如果超过了这个时间,连接失败,并且连接会被中断,不在连接。如果阻塞的时候连接被一个信号中断,连接失败,设置错误为EINTR,但是连接不会被中断,连接会异步的被建立。

          • socket设置了O_NONBLOCK,但是连接没有立即建立,则connect返回失败,错误为EINPROGRESS,但是连接不会被终止,连接会异步建立,直到建立成功之前,没有建立成功返回错误类型为EALREADY。可以使用selectpoll来判断何时可写,可写,则连接成功。

        • 如果套接字不是面向连接的,connect会设置对方的地址为address,仅能接收该地址的报文,并且不建立连接。

      • address:服务器套接字地址;

      • address_len:服务器套接字地址长度;

    • 返回值:

      • 成功: 返回0;

      • 失败: 返回-1,设置errno;

        
        #include <sys/socket.h>
        
        int listen(int socket, int backlog);
    • 功能:用来标记面向连接的套接字,表示套接字可以接受backlog个连接请求;

    • 参数:

      • backlog:用来限制套接字接收连接请求的队列大小。

        • 最大值在文件sys/socket.h中定义为SOMAXCONN

        • 若果设置的值超过最大值,则设置成最大值;

        • 如果设置成0,则设置成为具体unix实现设置的最小值。

        • 如果比0小,则与设置为0一样;

    • 返回值:

      • 成功: 返回0;

      • 失败: 返回-1,设置errno;

        
        #include <sys/socket.h>
        
        int accept(int socket, struct soxkaddr *restrict address, socklen_t *restrict sddress_len);
    • 功能:接受客户端的连接请求,并且把地址返回到sddress所指的空间(如果没有设置为NULL的话)。

      • 在还可以接受连接请求的时候,如果套接字设置为阻塞(没有设置O_NONBLOCK),那么没有连接之前会一直阻塞。

      • 在还可以接受连接请求的时候,如果套接字设置为非阻塞(设置O_NONBLOCK),那么accept会失败,并且设置错误为EAGAIN或者EWOULDBLOCK

      • 如果协议允许连接没有绑定地址的连接,而且客户端套接字没有绑定地址,则结果没有定义。

    • 参数:

      • socket:服务器的套接字,必须已经绑定地址,而且已经成功调用listen

      • address:输出

        • 设置为空指针,表示对此参数不关心;

        • 一个指向套接字地址的指针,客户端地址会返回到指针所指的内存。

      • address_len

        • 空指针,不关心地址;

        • 标志地址长度的指针,如果设定的长度比实际地址长度小,则会发生截断

    • 返回值:

      • 成功: 返回客户端套接字描述符;

      • 失败: 返回-1,设置errno;

  4. 数据传输:

    
    #include <sys/socket.h>
    
    ssize_t send(int socket, const char *buffer, size_t length, int flags);
    • 功能:发送消息给客户端或者服务端。函数的成功调用并不代表消息已经成功发送给对方,而是代表数据已经成功发送到网络驱动程序上。失败也只表示本地的失败。

      • 发送消息的长度由length指定,但是超过了特定的协议下规定的长度的时候,send会失败,并且数据不会被发送。

      • 对于发送的套接字,没有足够的空间来存储发送的信息,且套接字是阻塞的(没有设置O_NONBLOCK),send会一直阻塞,知道有足够空间。

      • 对于发送的套接字,没有足够的空间来存储发送的信息,且套接字是非阻塞的(设置了O_NONBLOCK),send失败。

      • selectpoll可以用来确定什么时候可以发送数据。

    • 参数:

      • length:表示发送信息的字节长度;

      • flags:可以使用下面的多个或一个相 或

        • MSG_DONTROUTE :勿将数据路由出本地网络。

        • MSG_DONTWAIT :允许非阻塞操作,等价于用 O_NONBLOCK 。

        • MSG_EOR :如果协议支持,此为记录结束。

        • MSG_OOB :如果协议支持,发送带外数据。

    • 返回值:

      • 成功: 返回传输的字节数;

      • 失败: 返回-1,设置errno;

        
        #include <sys/socket.h>
        
        ssize_t recv(int socket, void *buffer, size_t length, int flags);
    • 功能:接受数据存在缓冲区。

      • 对于基于消息的套接字,如 SOCK_DGRAM, SOCK_SEQPACKET,消息会一次性读完。如果消息太长,超过了length指定的值,如果没有设定MSG_PEEK多余的会被丢弃。

      • 对于基于流的套接字,如SOCK_STREAM,消息的边界会被忽略,一旦数据可用就会被返回,没有数据会被丢弃

      • 对于发送的套接字,没有足够的空间来存储发送的信息,且套接字是阻塞的(没有设置O_NONBLOCK),recv会一直阻塞,知道有足够空间。

      • 对于发送的套接字,没有足够的空间来存储发送的信息,且套接字是非阻塞的(设置了O_NONBLOCK),recv失败。

    • 参数:

      • flags:可以使用下面的多个或一个相 或

        • MSG_PEEK:返回数据包内容但是不真正取走数据包;

        • MSG_DONTWAIT:recvmsg 处于非阻塞模式,相当于O_NONBLOCK

        • MSG_TRUNC:即使数据包被截断也返回数据包实际长度。

        • MSG_OOB :接收到带外数据;

        • MSG_WAITALL:对于流套接字(SOCK_STREAM),函数阻塞到所有数据都返回,

    • 返回值:

      • 成功: 返回传输的字节数;

      • 失败: 返回-1,设置errno;

        
        #include <sys/socket.h>
        
        ssize_t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
    • 功能:与send一样除了一下几点:

      • 对于面对链接的套接字,地址和地址长度被忽略,因为连接中隐含了目标地址。

      • sendto的参数里面有地址和地址长度,因此当套接字是不是面向连接的时候,将直接向地址发送数据报,这个地址必须由connect设置过。

      • 如果套接字协议支持广播,而且地址是一个广播地址,套接字也设置了O_BROADCAST则可以向广播地址广播。

        
        #include <sys/socket.h>
        
        ssize_t recvfrom(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
    • send对应,flagsrecv一样。

      
      #include <sys/socket.h>
      
      ssize_t sendmsg(int socket, const struct msghdr *message, int flags);
      ssize_t recvmsg(int socket, const struct msghdr *message, int flags);
    • 功能:如果是面向连接的套接字,结构体里面的地址将会被忽略,否则,会想结构体里面的地址发送消息。其余与以上的sendto一样。

    • 参数:

      • mseeage:结构体指针;

        struct msghdr{
            void *msg_name;          /* 地址,不是面向链接的套接字时用 */
            socklen_t msg_namelen;   /* 地址长度 */
            struct iovec *msg_iov;   /* I/O缓冲数组,高级I/O writev/readv */
            int msg_iovlen;          /* I/O缓冲数组长度 */
            void *msg_control;       /* 辅助数据 */
            socklen_t msg_controllen;/* 辅助数据的字节数 */
            int msg_flags;           /* 接受消息标志 */
        };
      • flags:同上;

  5. 获取主机名字:

        #include <unistd.h>
    int gethostname(char *name, size_t namelen);
    int sethostname(const char *name, size_t len);
    • 功能:获取当前机器的标准主机名

    • 返回值:

      • 成功: 返回0;

      • 失败: 返回-1,设置errno

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值