欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

linux socket编程学习

程序员文章站 2022-07-07 21:32:56
...

    1. int socket(int domain, int type, int protocol);

    返回套接字描述符,错误的情况下返回-1。Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。你也可以对socket执行这些操作。

    参数1:domain-指定用于通信的协议族,常见的协议族有:AF_INET、AF_INET6、AF_LOCAL等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合,AF_UNIX决定了要用一个绝对路径名作为地址。

    参数2:type-常用的socket类型有:SOCK_STREAM、SOCK_DGRAM等。

    参数3:protocol-指定协议,常用的协议有:IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等。默认使用0,会根据type值的不同,有不同的默认值:type-SOCK_STREAM则默认为TCP协议,type-SOCK_DGRAM则默认UDP协议。

    参:http://www.cnblogs.com/skynet/archive/2010/12/12/1903949.html

    2. struct sockaddr_in

include <netinet/in.h>

// All pointers to socket address structures are often cast to pointers
// to this type before use in various functions and system calls:

struct sockaddr {
    unsigned short    sa_family;    // address family, AF_xxx
    char              sa_data[14];  // 14 bytes of protocol address
};

// IPv4 AF_INET sockets:

struct sockaddr_in {
    short            sin_family;   // e.g. AF_INET, AF_INET6
    unsigned short   sin_port;     // e.g. htons(3490)
    struct in_addr   sin_addr;     // see struct in_addr, below
    char             sin_zero[8];  // zero this if you want to
};

struct in_addr {
    unsigned long s_addr;          // load with inet_pton()
};

这几个结构体用于处理internet address信息。sockaddr和sockaddr_in都是16字节长,通常情况下他们是可以*转换的,在connect操作中有转换的操作。在sockaddr_in的sin_port和sin_addr存放网络字节序的数据。网络字节序和主机字节序的区别参见链接sin_addr 和 sin_port 需要转换为网络字节序,而sin_family 不需要。因为 sin_addr 和 sin_port 分别封装在包的 IP 和 UDP 层。因此,它们必须 要 是网络字节序。但是 sin_family 域只是被内核 (kernel) 使用来决定在数 据结构中包含什么类型的地址,所以它必须是主机字节序。

    3. 主机字节序(host byte order)和网络字节序(network byte order)的转换:

        (1) . int inet_aton(const char *cp, struct in_addr *inp);

        作用是把cp参数指定的字符串形式(IPV4 numbers-and-dots notation)的ip地址转换为整数形式(binary form)的且已经是网络字节序的数据。并把结果存入inp所指向的结构体。如果传入的地址合法,则返回非0整数,否则,返回0。不支持IPV6。

        cp参数可以是由dot隔开的数字组成的IPV4地址,这些数字可以是十进制、八进制(以0开头)或者十六进制(以0X开头)的,如192.168.52.250和0XC0.0XA8.0X34.0XFA,也可以是不同进制混合的,如0XC0.0250.52.0XFA。这几个地址都是同一个地址192.168.52.250。这些形式的地址都可被命名为IPV4 numbers-and-dots notation。而如果四个数字全部是10进制的话,可以称为IPV4 dotted-decimal notation或者IPv4 dotted-quad notation。其实指的都是IP地址的字符串表示法。以上叫法不知道用什么词翻译好,所以直接列出。

        源自:http://linux.die.net/man/3/inet_aton

        用法:

char* ip = "192.168.52.250"; 
struct in_addr addr;
inet_aton(ip, &addr);

        (2) . int inet_pton(int af, const char *src, void *dst);

        作用:把src所指的地址转换为一个网络地址结构体(network address structure),并把这个结构体拷贝给dst。af参数的内容必须是AF_INET或者AF_INET6。成功的情况返回1;如果src字符串不符合af参数所指定协议族(address family)的要求地址格式,则返回0;如果传递的af参数不是有效地协议族,则返回-1。(支持IPV6地址)

         这里的src参数,如果af是AF_INET的话,必须是dotted-decimal notaion,也就是说它只支持十进制表示的IP地址字符串。

        源自:http://linux.die.net/man/3/inet_pton

        用法:

struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons( (unsigned short)port);
inet_pton(AF_INET, hostIp, (void*)&sin.sin_addr);

        (3) . in_addr_t inet_addr(const char *cp);

        作用:把cp参数指定的且格式为IPV4 numbers-and-dots notation(与inet_aton所要求的地址格式一样)的地址转换为long型整数地址。不支持IPV6。在参数非法的情况下返回-1。而巧合的是255.255.255.255所对应的网络字节序整数地址正好也是-1,所以并不能凭借返回值来判断转换是否成功。所以更推荐使用inet_pton、inet_aton或者getaddrinfo。当然在确保255.255.255.255不会出现的情况下也是可以使用的。
        源自:http://linux.die.net/man/3/inet_addr
        用法:

struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons( (unsigned short)port);
sin.sin_addr.s_addr = inet_addr(hostIp);

        (4) . int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);

        作用:根据给定的node和service信息,getaddrinfo()可以构造一个或多个addrinfo结构体,而其中的每一个addrinfo结构体所包含的互联网地址(internet address)都可用在bind()或者connect()函数调用时。也就是说getaddrinfo()构造了多个符合条件的互联网地址,这些多个地址信息单元组成一个链表,而由res指向这个链表的首元素。遍历每一个地址信息可以使用ai_next。

struct addrinfo {
    int              ai_flags;
    int              ai_family;
    int              ai_socktype;
    int              ai_protocol;
    size_t           ai_addrlen;
    struct sockaddr *ai_addr;
    char            *ai_canonname;
    struct addrinfo *ai_next;
};

        hints虽然也是一个addrinfo结构体,不过它起一个criteria的作用,或者说是过滤器,就是把符合条件的数据留下。hints的ai_flags、ai_family、ai_socktype和ai_protocol可以根据需要指定数值,但是其他的属性就不要去指定了,保证是0或者NULL就可以。如果hints是NULL,那么相当于是ai_socktype=0; ai_protocol=0; ai_family=AF_UNSPEC; ai_flags=(AI_V4MAPPED|AI_ADDRCONFIG)。ai_flags也起着限制的作用,它的值可以是单个值如:AI_ADDRCONFIG,也可以是多取值的,用“|”符号按位将每个flag分隔开,如(AI_V4MAPPED|AI_ADDRCONFIG)。

        node可以是IPV4 numbers-and-dots notation形式的地址,也支持IPV6地址,这些通称numerical network address;域名地址(network hostname)也可以。而如果hints.ai_flags包含AI_NUMBERICHOST标志,那么node必须是numberical network address。因为AI_NUMBERICHOST阻止了任何潜在的对冗长的network host address的查找。

        service指定端口。且node和service最多只能有一个是空的。

        源自:http://linux.die.net/man/3/getaddrinfo

        用法:

    struct addrinfo hints;
    struct addrinfo *result, *rp;
    int sfd, s, j;
    size_t len;
    ssize_t nread;

   /* Obtain address(es) matching host/port */
   memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
    hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
    hints.ai_flags = 0;
    hints.ai_protocol = 0;          /* Any protocol */

   s = getaddrinfo(argv[1], argv[2], &hints, &result);
    if (s != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
        exit(EXIT_FAILURE);
    }

   /* getaddrinfo() returns a list of address structures.
       Try each address until we successfully connect(2).
       If socket(2) (or connect(2)) fails, we (close the socket
       and) try the next address. */

   for (rp = result; rp != NULL; rp = rp->ai_next) {
        sfd = socket(rp->ai_family, rp->ai_socktype,
                     rp->ai_protocol);
        if (sfd == -1)
            continue;

       if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
            break;                  /* Success */

       close(sfd);
    }

        关于网络自己序和主机字节序的转换可参见:http://blog.csdn.net/sunboy_2050/article/details/6100734 和http://blog.csdn.net/Sunboy_2050/article/details/6061528这两篇博客的作者很牛!

    这个可做进一步的学习-网络socket编程指南:http://blog.csdn.net/hello_wyq/article/details/1180747

    如果想做深一步的研究可以使用wireshark做协议抓取分析:

    http://blog.csdn.net/hnney/article/details/5604677

 

相关标签: linux socket