一个简单的IPv6 socket 程序

先回顾一下, IPv4 socket 编程我们用到这两个数据结构:

struct sockaddr {
        u_char          sa_len;         /* total length */
        sa_family_t     sa_family;      /* address family */
        char            sa_data[14];    /* actually longer; address value */
};

struct sockaddr_in
{
        UCHAR   sin_len;
        UCHAR   sin_family;
        VOS_UINT16  sin_port;
        struct  in_addr sin_addr;
        CHAR  sin_zero[8];
};

struct sockaddr 是一个通用的概念,表示任何socket address, connect,bind, recvfrom 等函数用的就是它; struct sockaddr_in 特别表示IPv4 internet address。 我们在做IPv4 编程的时候,其实脑子里已经确定了是在用IPv4的概念,初始化socket 的时候用的是IPv4, 然后把 sockaddr_in 转换为 sockaddr。 这是一个例子:

        int sockfd, n;
        char recvline[MAXLINE + 1];
        struct sockaddr_in servaddr;

        if (argc != 2)
                err_quit("usage: a.out ");

        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
                err_sys("socket error");

        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(12345);  /* port */
        if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
                err_quit("inet_pton error for %s", argv[1]);

        if (connect(sockfd, (struct sockaddr *) & servaddr, sizeof(servaddr)) < 0)
                err_sys("connect error");

我们看到, socket 函数决定了协议类型, 然后初始化 sockaddr_in 结构,接着 inet_pton 把IPv4地址的字符串表示转化为数字表示,这几步都是跟协议相关的。 到了connect 这步把sockaddr_in 转化为sockaddr 就可以了,因为它是跟协议无关的,接受的是sockaddr 参数。

显然,为了用IPv6, 我们需要一个新的数据结构来表示IPv6 地址,初始化这个结构,接下来就跟IPv4的socket编译差不多了:

struct sockaddr_in6 {
   u_int8_t        sin6_len;       /* length of this struct(sa_family_t)*/
   u_int8_t        sin6_family;    /* AF_INET6 (sa_family_t) */
   u_int16_t       sin6_port;      /* Transport layer port # (in_port_t)*/
   u_int32_t       sin6_flowinfo;  /* IP6 flow information */
   struct in6_addr sin6_addr;      /* IP6 address */
   u_int32_t       sin6_scope_id;  /* scope zone index */
};


struct in6_addr {
        union {
                u_int8_t   addr8[16];
                u_int16_t  addr16[8];
                u_int32_t  addr32[4];
        } in6;                  /* 128-bit IP6 address */
};

其中 struct in6_addr 放的是128位IPv6地址。 这是代码片段:

/* generic function to create a socket */
int sockunion_stream_socket(union sockunion *unSu)
{
        int intSock;


        intSock = socket(unSu->su_family, SOCK_STREAM, 0);

        if (intSock < 0)
                {
                        printf("\r\n can't make socket hw_sockunion_stream_socket:%d", intSock);
                }

        return intSock;
}

void create_ipv6_socket(char *ip6str, unsigned short port, int family) 
{
        int             ret;
        union sockunion su;
        int             accept_sock;
        struct in6_addr src_ip;


        if (inet_pton(AF_INET6, ip6str, &src_ip) == 1) 
                {
                        printf("successfully convert ip6 address %s\n", ip6str);
                }
        else
                {
                        printf("invalid ip6 address %s\n", ip6str);
                        return;
                }

        memset(&su, 0, sizeof (union sockunion));
        su.su_family = (unsigned char)family;

        /* Make new socket. */
        accept_sock = sockunion_stream_socket(&su);

用到了一个辅助结构:

typedef union sockunion
{
        struct sockaddr     sa;   
        struct sockaddr_in  sin;  
        struct sockaddr_in6 sin6;  

}st_sockunion;

可以用来表示 sockaddr, sockaddr_in 或sockaddr_in6。

你可能感兴趣的:(网络)