一对简单的IPV6 SOCKET代码

一对简单的IPV6 SOCKET代码,包括服务端ipv6_server.c及客户端ipv6_client.c

服务端ipv6_server.c

#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>

#define MAXLINE 1024

int main(int argc, char **argv)
{
   int listenfd, connfd;
   socklen_t len;
   char buff[MAXLINE];
   struct sockaddr_in6	servaddr, cliaddr;
   //第一个参数指定AF_INET6来创建一个ipv6监听套接字
   listenfd = socket(AF_INET6, SOCK_STREAM, 0);

   bzero(&servaddr, sizeof(servaddr));
   //servaddr的地址族指定AF_INET6
   servaddr.sin6_family = AF_INET6;
   //地址使用通配符
   servaddr.sin6_addr = in6addr_any;
   //端口使用9999
   servaddr.sin6_port = htons(9999);

   bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
   listen(listenfd, 1);

   for ( ; ; ) 
   {
      len = sizeof(cliaddr);
      connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &len);
      sprintf(buff, "hello");
      write(connfd, buff, strlen(buff));
      close(connfd);
	}
}

需要注意的是,在ipv4中,地址通配符可以直接使用0来赋值,即
servaddr.sin_addr.s_addr = 0
而在ipv6的编程中不能用0直接赋值,原因是ipv6的地址是存放在一个长度为16的unit8_t数组中的。

客户端ipv6_client.c

#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <netdb.h>

#define MAXLINE 1024

void mygetaddinfo(struct sockaddr_in6 *servaddr, char *addr)
{
   struct addrinfo *ai, *hints;
   memset(hints, 0, sizeof(struct addrinfo));
   //只要ipv6地址族的结果
   hints->ai_family = AF_INET6;
   if((getaddrinfo(addr, "9999", hints, &ai)) != 0)
   {
      perror("IN GETADDRINFO()");
      exit(1);
   }
   *servaddr = *(struct sockaddr_in6 *)ai->ai_addr;
   //指定使用的接口
   servaddr->sin6_scope_id = 2;
}

int main(int argc, char **argv)
{
   int sockfd, n;
   struct sockaddr_in6 servaddr;
   char recvline[MAXLINE];
   socklen_t len;
   if (argc != 2)
   {
      printf("INPUT ADDRESS!");
      exit(1);
   }

   if ( (sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
   {
      perror("SOCKET");
      exit(1);
   }
   bzero(&servaddr, sizeof(servaddr));
   mygetaddinfo(&servaddr, argv[1]);

   len = sizeof(servaddr);
   if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
   {   
      perror("CONNEXT");
      exit(1);
   }

   n = read(sockfd, recvline, MAXLINE);
   recvline[n] = 0;
   printf("%s\n", recvline);
   exit(0);
}

在客户端的代码中,使用了getaddrinfo(char *, char *, struct addrinfo *, struct addrinfo **)来获取服务端的sockaddr_in6结构体(如果已有地址串及已确定的端口,这调用并没有必要)。值得注意的是,如果使用的链路本地地址(Link-Local Address,以fe80:打头),则必须指定sockaddr_in6中的sin6_scope_id成员,其成员的值可以通过ip link命令获得,为对应接口前的数字:

sunminming@sunminming:~$ ip link   
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00   
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:47:bc:c8 brd ff:ff:ff:ff:ff:ff   

如果使用的ipv6的环回地址::1也可以不用指定sin6_scope_id成员。

posted @ 2020-02-09 21:57  孙敏铭  阅读(3912)  评论(0编辑  收藏  举报