zoukankan      html  css  js  c++  java
  • linux IPC socket

    套接字是通讯端点的抽象

    创建一个套接字

    #include <sys/types.h>
    #include <sys/socket.h>
    
    int socket(int domain, int type, int protocol);
    返回值:成功文件(套接字)描述符,失败-1
    domain:即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。 协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。 type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等(socket的类型有哪些?)。 protocal:故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等 它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。

    套接字通信是双向的。可以禁止一个套接字的I/O

    #include <sys/socket.h>
    
    int shutdown(int sockfd, int how);
    返回值:成功0,出错-1
    sockfd:套接字的描述符
    how:三种SHUT_RD(0)关闭sockfd上的读功能
    SHUT_WR(1)关闭sockfd上的写功能
    SHUT_RDWR(2)关闭sockfd的读写功能

    用来在处理器字节序和网络字节序之间实施转换的函数

    #include <arpa/inet.h>
    
    uint32_t htonl(uint32_t hostlong);
    返回值:以网络字节序表示的32位整数 uint16_t htons(uint16_t hostshort);
    返回值:以网络字节序表示的16位整数
    uint32_t ntohl(uint32_t netlong);
    返回值:以主机字节序表示的32位整数
    uint16_t ntohs(uint16_t netshort);
    返回值:以主机字节序表示的16位整数

     h表示主机字节序,n表示网络字节序,l表示长整型,s表示短整型

    打印出能被人理解而不是计算机所理解的地址格式。同时支持IPv4和IPv6地址

    #include <arpa/inet.h>
    
    const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
    返回值:成功地址字符串指针,出错NULL
    af:地址簇,仅支持AF_INET和AF_INET6
    src:来源地址结构指针
    dst:接收转换后的字符串
    size:保存文本字符串的缓冲区大小
    
    int inet_pton(int af, const char *src, void *dst);
    返回值:成功1,格式无效0,出错-1
    af:地址簇,仅支持AF_INET和AF_INET6
    src:转换的地址字符串
    dst:转换后的地址结构指针

    这个很常用,所有使用socket都需要用这两个函数转换,p应该是protocol,n应该是net吧。

    例子

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <sys/types.h>
     4 #include <sys/ioctl.h>
     5 #include <stdlib.h>
     6 #include <netdb.h>
     7 #include <arpa/inet.h>
     8 #include <netinet/in.h>
     9 #include <string.h>
    10 
    11 int main(int argc, char *argv[])
    12 {
    13         char dst[100];
    14         int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    15 
    16         struct sockaddr_in serv;
    17         memset(&serv, 0 ,sizeof(struct sockaddr_in));
    18 
    19         serv.sin_family = AF_INET;
    20         serv.sin_port = htons(5555);
    21 
    22         if((inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr)) == 0)
    23                 printf("inet_pton error
    ");
    24         if((inet_ntop(AF_INET, &serv.sin_addr.s_addr, dst, sizeof(dst))) == NULL)
    25                         printf("inet_ntop error
    ");
    26         printf("dst=%s,sizeof(dst)=%d
    ", dst, sizeof(dst));
    27 
    28         bind(sockfd, (struct sockaddr *)&serv, sizeof(serv));
    29         listen(sockfd, 15);
    30         return 0;
    31 }
    inet_pton

      

    找到给定计算机系统的主机信息

    #include <netdb.h>
    
    struct hostent *gethostent(void);
    返回值:成功返回指针,出错NULL
    
    void sethostent(int stayopen);
    stayopen:true就是TCP,否则UDP
    void endhostent(void);

    能够采用一套相似的接口来获得网络名字和网络编号

    #include <netdb.h>
    
    struct netent *getnetbyaddr(uint32_t net, int type);
    struct netent *getnetbyname(const char *name);
    struct netent *getnetent(void);
    返回值:成功返回指针,出错NULL
    
    void setnetent(int stayopen);
    void endnetent(void);

    在协议名字和协议编号之间进行映射

    #include <netdb.h>
    
    struct protoent *getprottobyname(const char *name);
    struct protoent *getprotobynumber(int proto);
    struct protoent *getprotoent(void);
    返回值:成功返回指针,出错NULL
    
    void setprotoent(int stayopen);
    void endprotoent(void);

    服务是由地址的端口号部分表示的,每个服务由一个唯一的众所周知的端口号来支持。可以使用getservbyname将一个服务名映射到一个端口号,使用函数getservbyport将一个端口号映射到一个服务名,使用函数getservent顺序扫描服务数据库。

    #include <netdb.h>
    
    struct servent *getservbyname(const char *name, const char *proto);
    struct servent *getservbyport(int port, const char *proto);
    struct servent *getservent(void);
    返回值:成功返回指针,出错NULL
    
    void setservent(int stayopen);
    void endservent(void);

    将一个主机和一个服务名映射到一个地址

    #include <sys/socket.h>
    #include <netdb.h>
    
    int getaddrinfo(const char *node, const char *service,
                            const struct addrinfo *hints,
                            struct addrinfo **res);
    返回值:成功0,出错非0错误码
    node:向一个主机名(域名)或者地址串(IPv4的点分十进制串或者IPv6的16进制串)。
    service:指向一个服务名或者10进制端口号数串。
    hints:可以是一个空指针,也可以是一个指向某个addrinfo结构的指针
    res:指向的变量已被填入一个指针,它指向的是由其中的ai_next成员串联起来的addrinfo结构链表
    void freeaddrinfo(struct addrinfo *res);

    addrinfo结构体

    struct addrinfo
    { 
        int ai_flags; 
        int ai_family; //AF_INET,AF_INET6,UNIX etc
        int ai_socktype; //STREAM,DATAGRAM,RAW
        int ai_protocol; //IPPROTO_IP, IPPROTO_IPV4, IPPROTO_IPV6 etc
        size_t ai_addrlen;//length of ai_addr
        char* ai_canonname; //full hostname 
        struct sockaddr* ai_addr; //addr of host
        struct addrinfo* ai_next;
    }

    错误码需要调用函数来转换成错误消息

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netdb.h>
    
    const char *gai_strerror(int errcode);

    将一个地址转换成一个额主机名和一个服务名

    #include <sys/socke.h>
    #include <netdb.h>
    
    int getnameinfo(const struct sockaddr *sa, socklen_t salen,
                            char *host, socklen_t hostlen,
                            char *serv, socklen_t servlen, int flags);
    返回值:成功0,出错非0值
    sa:指向包含协议地址的套接口地址结构,它将会被转换成可读的字符串,
    salen:结构的长度,这个结构长度通常由accept、recvfrom、getsockname、getpeername
    host:主机字符串
    hostlen:长度
    serv:服务器字符串
    servlen:长度
    flags:标志位可以有多个用与或

     sockaddr结构体

    struct sockaddr
    {
      unsigned short sa_family;  /*addressfamily,AF_xxx*/
      char sa_data[14];       /*14bytesofprotocoladdress*/
    };

    16-9.c

      1 #include "apue.h"
      2 #if defined(SOLARIS)
      3 #include <netinet/in.h>
      4 #endif
      5 #include <netdb.h>
      6 #include <arpa/inet.h>
      7 #if defined(BSD)
      8 #include <sys/socket.h>
      9 #include <netinet/in.h>
     10 #endif
     11 
     12 void print_family(struct addrinfo *aip)
     13 {
     14     printf(" family ");
     15     switch(aip->ai_family) {
     16     case AF_INET:
     17         printf("inet");
     18         break;
     19     case AF_INET6:
     20         printf("inet6");
     21         break;
     22     case AF_UNIX:
     23         printf("unix");
     24         break;
     25     case AF_UNSPEC:
     26         printf("unspecified");
     27         break;
     28     default:
     29         printf("unknown");
     30     }
     31 }
     32 
     33 void print_type(struct addrinfo *aip)
     34 {
     35     printf(" type ");
     36     switch(aip->ai_socktype) {
     37     case SOCK_STREAM:
     38         printf("stream");
     39         break;
     40     case SOCK_DGRAM:
     41         printf("datagram");
     42         break;
     43     case SOCK_SEQPACKET:
     44         printf("seqpacket");
     45         break;
     46     case SOCK_RAW:
     47         printf("raw");
     48         break;
     49     default:
     50         printf("unknown (%d)", aip->ai_socktype);
     51     }
     52 }
     53 
     54 void print_protocol(struct addrinfo *aip)
     55 {
     56     printf(" protocol ");
     57     switch(aip->ai_protocol) {
     58     case 0:
     59         printf("default");
     60         break;
     61     case IPPROTO_TCP:
     62         printf("TCP");
     63         break;
     64     case IPPROTO_UDP:
     65         printf("UDP");
     66         break;
     67     case IPPROTO_RAW:
     68         printf("raw");
     69         break;
     70     default:
     71         printf("unknown (%d)", aip->ai_protocol);
     72     }
     73 }
     74 
     75 void print_flags(struct addrinfo *aip)
     76 {
     77     printf("flags");
     78     if(aip->ai_flags == 0) {
     79         printf(" 0");
     80     } else {
     81         if(aip->ai_flags & AI_PASSIVE)
     82             printf(" passive");
     83         if(aip->ai_flags & AI_CANONNAME)
     84             printf(" canon");
     85         if(aip->ai_flags & AI_NUMERICHOST)
     86             printf(" numhost");
     87         if(aip->ai_flags & AI_NUMERICSERV)
     88             printf(" numserv");
     89         if(aip->ai_flags & AI_V4MAPPED)
     90             printf(" v4mapped");
     91         if(aip->ai_flags & AI_ALL)
     92             printf(" all");
     93     }
     94 }
     95 
     96 int main(int argc, char *argv[])
     97 {
     98     struct addrinfo *ailist, *aip;
     99     struct addrinfo hint;
    100     struct sockaddr_in *sinp;
    101     const char *addr;
    102     int err;
    103     char abuf[INET_ADDRSTRLEN];
    104 
    105     if(argc != 3)
    106         err_quit("usage: %s nodename service", argv[0]);
    107     hint.ai_flags = AI_CANONNAME;
    108     hint.ai_family = 0;
    109     hint.ai_socktype = 0;
    110     hint.ai_protocol = 0;
    111     hint.ai_addrlen = 0;
    112     hint.ai_canonname = NULL;
    113     hint.ai_addr = NULL;
    114     hint.ai_next = NULL;
    115     if((err = getaddrinfo(argv[1], argv[2], &hint, &ailist)) != 0)
    116         err_quit("getaddrinfo error %s", gai_strerror(err));
    117     for(aip = ailist; aip != NULL; aip = aip->ai_next) {
    118         print_flags(aip);
    119         print_family(aip);
    120         print_type(aip);
    121         print_protocol(aip);
    122         printf("
    	host %s", aip->ai_canonname?aip->ai_canonname:"-");
    123         if(aip->ai_family == AF_INET) {
    124             sinp = (struct sockaddr_in *)aip->ai_addr;
    125             addr = inet_ntop(AF_INET, &sinp->sin_addr, abuf, INET_ADDRSTRLEN);
    126             printf(" address %s", addr?addr:"unknown");
    127             printf(" port %d", ntohs(sinp->sin_port));
    128         }
    129         printf("
    ");
    130     }
    131     exit(0);
    132 }
    getaddrinfo
    无欲速,无见小利。欲速,则不达;见小利,则大事不成。
  • 相关阅读:
    理解SynchronizationContext,如何在Winform里面跨线程访问UI控件
    ThreadPool.QueueUserWorkItem引发的血案,线程池异步非正确姿势导致程序闪退的问题
    实战经验分享之C#对象XML序列化
    C#wxpay和alipay
    C#调用windows api 实现打印机控制
    C#winform程序关闭计算机的正确姿势
    自动化控制之线程池的使用
    自动化控制之重码校验
    (转)C#中的那些全局异常捕获
    android studio 2.32躺坑记
  • 原文地址:https://www.cnblogs.com/ch122633/p/8074110.html
Copyright © 2011-2022 走看看